diff --git a/libdc/include/dc/session.h b/libdc/include/dc/session.h index 54b7464..6702d4a 100644 --- a/libdc/include/dc/session.h +++ b/libdc/include/dc/session.h @@ -83,6 +83,23 @@ dc_account_t dc_session_me(dc_session_t s); */ dc_api_t dc_session_api(dc_session_t s); +/** + * Queue API. If you enable queuing the session will keep the events from the + * web socket around for you to handle. Please note that all internal states + * will already have been upgraded, and changed once you pull these events + * from the queue. Also note that if you enable queuing but never pull these + * events from the queue they will pile up, and use a lot of memory. + * + * If you disable queuing then the queue is deleted, and no more events are + * placed into the queue. + * + * dc_session_pop_event() will remove an event from the queue for you to handle. + * You will have to call dc_unref() on it yourself to cleanup any internal data + * of the event. It will return NULL if no event is in the queue. + */ +void dc_session_enable_queue(dc_session_t s, bool enable); +dc_event_t dc_session_pop_event(dc_session_t s); + /** * access to the internal account cache */ diff --git a/libdc/src/session.c b/libdc/src/session.c index aee8b8c..71aa63d 100644 --- a/libdc/src/session.c +++ b/libdc/src/session.c @@ -32,6 +32,9 @@ struct dc_session_ GHashTable *accounts; GHashTable *channels; GHashTable *guilds; + + GQueue *queue; + pthread_mutex_t *mutex; }; /* event handlers @@ -50,6 +53,16 @@ static void dc_session_free(dc_session_t s) { return_if_true(s == NULL,); + if (s->mutex != NULL) { + pthread_mutex_lock(s->mutex); + if (s->queue != NULL) { + g_queue_free_full(s->queue, (GDestroyNotify)dc_unref); + s->queue = NULL; + } + pthread_mutex_destroy(s->mutex); + s->mutex = NULL; + } + if (s->accounts != NULL) { g_hash_table_unref(s->accounts); s->accounts = NULL; @@ -189,6 +202,14 @@ static void dc_session_handler(dc_gateway_t gw, dc_event_t e, void *p) h(s, e); } + /* add to queue, if the queue is enabled + */ + pthread_mutex_lock(s->mutex); + if (s->queue != NULL) { + g_queue_push_tail(s->queue, dc_ref(e)); + } + pthread_mutex_unlock(s->mutex); + #ifdef DEBUG char *str = NULL; str = json_dumps(dc_event_payload(e), 0); @@ -223,6 +244,9 @@ dc_session_t dc_session_new(dc_loop_t loop) ); goto_if_true(s->channels == NULL, error); + s->mutex = calloc(1, sizeof(pthread_mutex_t)); + goto_if_true(s->mutex == NULL, error); + s->loop = dc_ref(loop); s->api = dc_api_new(); @@ -337,6 +361,38 @@ bool dc_session_equal_me(dc_session_t s, dc_account_t a) ); } +void dc_session_enable_queue(dc_session_t s, bool enable) +{ + return_if_true(s == NULL,); + + return_if_true(enable == true && s->queue != NULL,); + return_if_true(enable == false && s->queue == NULL,); + + if (enable) { + pthread_mutex_lock(s->mutex); + s->queue = g_queue_new(); + pthread_mutex_unlock(s->mutex); + } else { + pthread_mutex_lock(s->mutex); + g_queue_free_full(s->queue, (GDestroyNotify)dc_unref); + s->queue = NULL; + pthread_mutex_unlock(s->mutex); + } +} + +dc_event_t dc_session_pop_event(dc_session_t s) +{ + return_if_true(s == NULL || s->queue == NULL, NULL); + + dc_event_t e = NULL; + + pthread_mutex_lock(s->mutex); + e = g_queue_pop_head(s->queue); + pthread_mutex_unlock(s->mutex); + + return e; +} + bool dc_session_equal_me_fullname(dc_session_t s, char const *a) { return_if_true(s == NULL || s->login == NULL || a == NULL, false); diff --git a/ncdc/src/login.c b/ncdc/src/login.c index 4c105e3..5b6e4c3 100644 --- a/ncdc/src/login.c +++ b/ncdc/src/login.c @@ -51,6 +51,10 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, goto cleanup; } + /* enable queueing + */ + dc_session_enable_queue(s, true); + g_ptr_array_add(sessions, s); } else { s = g_ptr_array_index(sessions, idx); @@ -68,14 +72,7 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, dc_unref(current_session); current_session = dc_ref(s); - LOG(n, L"login: %ls: authentication successful, waiting for ready " - L"from websocket...", av[1]); - - while (!dc_session_is_ready(current_session)) - ; - - LOG(n, L"login: %ls: ready", av[1]); - ncdc_mainwindow_update_guilds(n); + LOG(n, L"login: %ls: authentication successful", av[1]); ret = true; diff --git a/ncdc/src/mainwindow.c b/ncdc/src/mainwindow.c index 7588ea7..0393b8e 100644 --- a/ncdc/src/mainwindow.c +++ b/ncdc/src/mainwindow.c @@ -477,10 +477,38 @@ void ncdc_mainwindow_switch_view(ncdc_mainwindow_t n, ncdc_textview_t v) } } +static void ncdc_mainwindow_handle_events(ncdc_mainwindow_t n) +{ + if (!is_logged_in()) { + return; + } + + dc_event_t e = NULL; + + e = dc_session_pop_event(current_session); + if (e == NULL) { + return; + } + + switch (dc_event_type_code(e)) { + case DC_EVENT_TYPE_READY: + { + LOG(n, L"connection to discord is ready"); + ncdc_mainwindow_update_guilds(n); + } break; + + default: break; + } + + dc_unref(e); +} + void ncdc_mainwindow_refresh(ncdc_mainwindow_t n) { ncdc_textview_t v = 0; + ncdc_mainwindow_handle_events(n); + ncdc_treeview_render(n->guildview, n->guilds, n->guilds_h, n->guilds_w); wnoutrefresh(n->guilds);