try out a queue API to notify "listeners" of the session

I was always unsure on what to do: a callback or a simple queue for
dc_event_t. But since we already have dc_event_t (and ref counting)
this seemed like the best solution.
This commit is contained in:
Florian Stinglmayr 2019-07-23 20:01:12 +02:00
parent 551e67c823
commit bd88d735eb
4 changed files with 106 additions and 8 deletions

View File

@ -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
*/

View File

@ -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);

View File

@ -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;

View File

@ -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);