void sess_connect() { assert(g_session.username && g_session.password); sess_disconnect(); if (!(g_session.dsfy = despotify_init_client(sess_callback, NULL, true, true))) panic("despotify_init_client(...) failed"); play_state = PAUSE; pthread_create(&thread, NULL, &thread_loop, g_session.dsfy); // Login with credentials set by sess_username/sess_password. if (!despotify_authenticate(g_session.dsfy, g_session.username, g_session.password)) { g_session.state = SESS_ERROR; log_append(despotify_get_error(g_session.dsfy)); despotify_exit(g_session.dsfy); // Switch to log view. ui_show(UI_SET_LOG); } else { g_session.state = SESS_ONLINE; log_append("Logged in as %s@%s:%d (%s)", g_session.dsfy->user_info->username, g_session.dsfy->user_info->server_host, g_session.dsfy->user_info->server_port, g_session.dsfy->user_info->country); // Switch to browser view. ui_show(UI_SET_BROWSER); } // Redraw status info. ui_dirty(UI_FOOTER); }
void sess_cleanup() { sess_disconnect(); audio_exit(audio_device); log_append("Destroyed audio output"); // Free search results. for (sess_search_t *s = g_session.search; s;) { despotify_free_search(s->res); sess_search_t *p = s; s = s->next; free(p); } if (!despotify_cleanup()) panic("despotify_cleanup() failed"); free(g_session.username); g_session.username = 0; free(g_session.password); g_session.password = 0; }
/* * Main loop */ int sess_main(struct irc_session *sess) { /* Jump into mainloop */ while (!sess->kill) { time_t lastidle = time(NULL); time_t last_sign_of_life = time(NULL); if (sess_connect(sess) < 0) break; sess->session_start = time(NULL); sess_login(sess); /* Inner loop, receive and handle data */ while (!sess->kill) { /* * Since both idle and flood protection are based on second * precision, this is an optimal timeout */ struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 }; int res = sess_handle_data(sess, &timeout); if (res < 0) { break; } else if (res > 0) { last_sign_of_life = time(NULL); } else { if ((time(NULL) - last_sign_of_life) >= TIMEOUT) { struct tm *tm = TIME_GETTIME(&last_sign_of_life); char buffer[TIMEBUF_MAX] = {0}; strftime(buffer, sizeof(buffer), STRFTIME_FORMAT, tm); log_info("Last sign of life was %d seconds " "ago (%s). Pinging server...", time(NULL) - last_sign_of_life, buffer); struct irc_message ping; irc_mkmessage(&ping, CMD_PING, NULL, 0, "%s", sess->hostname); if (sess_sendmsg_real(sess, &ping) <= 0) break; } } /* Try to send messages in outbuffer */ while (sess->buffer_out_start != sess->buffer_out_end) { struct irc_message *next = &(sess->buffer_out[sess->buffer_out_start]); unsigned len = irc_message_size(next); len = MAX(len, FLOODPROT_MIN); if (tokenbucket_consume(&sess->quota, len)) { sess_sendmsg_real(sess, next); sess->buffer_out_start = (sess->buffer_out_start + 1) % FLOODPROT_BUFFER; } else { break; } } /* Check if we have to emit an idle event */ if ((time(NULL) - lastidle) >= IDLE_INTERVAL) { if (sess->cb.on_idle) sess->cb.on_idle(sess->cb.arg, lastidle); lastidle = time(NULL); } /* And regenerate some tokens */ tokenbucket_generate(&sess->quota); } if (sess->cb.on_disconnect) sess->cb.on_disconnect(sess->cb.arg); /* Session is finished, free resources and start again unless killed */ hashtable_clear(sess->channels); hashtable_clear(sess->capabilities); sess_disconnect(sess); } return 0; } int sess_login(struct irc_session *sess) { struct irc_message nick; struct irc_message user; irc_mkmessage(&nick, CMD_NICK, (const char *[]){ sess->nick }, 1, NULL); irc_mkmessage(&user, CMD_USER, (const char *[]){ sess->user, "*", "*" }, 3, "%s", sess->real);
void cmd_cb_disconnect() { sess_disconnect(); }
void sess_init(struct event_base *evbase) { g_session.evbase = evbase; g_session.spot_ev = evtimer_new(evbase, sess_event_cb, &g_session); g_session.stop_ev = evtimer_new(evbase, sess_stop_cb, &g_session); g_session.exiting = false; g_session.current_track = NULL; sp_session_config config = { .api_version = SPOTIFY_API_VERSION, .cache_location = "tmp", .settings_location = "tmp", .application_key = g_appkey, .application_key_size = g_appkey_size, .user_agent = POLSPOT_USER_AGENT, .callbacks = &g_callbacks, .userdata = &g_session }; sp_error err = sp_session_init(&config, &g_session.spotify); if (err != SP_ERROR_OK) panic("sp_session_init() failed: %s", sp_error_message(err)); } void sess_cleanup() { // If user is logged in then initiate logout. This will change the session // state to SESS_DISCONNECTING. Another call to this function will thus exit // the main loop without waiting for the logout process to finish, allowing // users to avoid waiting for timeouts by issuing the quit commant twice. if (g_session.state == SESS_ONLINE) { sess_disconnect(); g_session.exiting = true; } else { free(g_session.username); g_session.username = 0; free(g_session.password); g_session.password = 0; // Free search results. for (sess_search_t *s = g_session.search; s;) { sp_search_release(s->res); sess_search_t *p = s; s = s->next; free(p); } g_session.current_track = NULL; event_free(g_session.spot_ev); // Exit main event loop. event_base_loopbreak(g_session.evbase); } } void sess_connect() { assert(g_session.username && g_session.password); sess_disconnect(); // Login with credentials set by sess_username/sess_password. sp_error err = sp_session_login(g_session.spotify, g_session.username, g_session.password); if (err != SP_ERROR_OK) panic("sp_session_login() failed: %s", sp_error_message(err)); log_append("Connecting..."); // Redraw status info. g_session.state = SESS_CONNECTING; ui_dirty(UI_FOOTER); ui_update_post(0); }