wip: remove threads, make ssb_scuttler_connect an async method

This commit is contained in:
Gergely Polonkai 2019-01-07 15:41:54 +01:00
parent cc4e304418
commit 373d9ace84
3 changed files with 156 additions and 99 deletions

View File

@ -92,9 +92,16 @@ enum {
SIGNAL_LAST SIGNAL_LAST
}; };
static guint ssb_scuttler_signals[SIGNAL_LAST] = {0 enum {
PROP_0,
PROP_INITIALISED,
PROP_CONNECTED,
PROP_COUNT
}; };
static guint ssb_scuttler_signals[SIGNAL_LAST] = {0};
static GParamSpec *ssb_scuttler_properties[PROP_COUNT];
GMainLoop *scuttle_loop = NULL; GMainLoop *scuttle_loop = NULL;
SsbScuttler *singleton = NULL; SsbScuttler *singleton = NULL;
@ -232,7 +239,7 @@ emit_initialised(SsbScuttler *scuttler, gboolean success)
} }
static void static void
initialise(SsbScuttler *scuttler, gchar *ssb_dir) initialise(SsbScuttler *scuttler, const gchar *ssb_dir)
{ {
gchar *config_data = NULL; gchar *config_data = NULL;
GError *err = NULL; GError *err = NULL;
@ -319,13 +326,13 @@ initialise(SsbScuttler *scuttler, gchar *ssb_dir)
} }
/** /**
* ensure_scuttler(): * ssb_scuttler_ensure():
* @ssb_dir: (nullable): the SSB directory * @ssb_dir: (nullable): the SSB directory
* *
* Ensure the scuttler singleton is initialised with @ssb_dir as its base directory. * Ensure the scuttler singleton is initialised with @ssb_dir as its base directory.
*/ */
static inline gboolean gboolean
ensure_scuttler(gchar *ssb_dir) ssb_scuttler_ensure(const gchar *ssb_dir)
{ {
if (singleton != NULL) { if (singleton != NULL) {
if ((ssb_dir != NULL) && g_strcmp0(ssb_dir, singleton->ssb_dir)) { if ((ssb_dir != NULL) && g_strcmp0(ssb_dir, singleton->ssb_dir)) {
@ -344,14 +351,6 @@ ensure_scuttler(gchar *ssb_dir)
return TRUE; return TRUE;
} }
static gboolean
second_hook_cb()
{
g_print("Scuttling…\n");
return TRUE;
}
// was: write_all // was: write_all
static gboolean static gboolean
ssb_scuttler_send_plain(SsbScuttler *scuttler, gpointer data, gsize data_len, GError **error) ssb_scuttler_send_plain(SsbScuttler *scuttler, gpointer data, gsize data_len, GError **error)
@ -597,6 +596,8 @@ ssb_scuttler_shs_connect(SsbScuttler *scuttler, GError **error)
scuttler->noauth = FALSE; scuttler->noauth = FALSE;
scuttler->wrote_goodbye = FALSE; scuttler->wrote_goodbye = FALSE;
g_debug("SHS succeeded");
return TRUE; return TRUE;
} }
@ -606,14 +607,62 @@ emit_connected(SsbScuttler *scuttler, gboolean success)
g_signal_emit(scuttler, ssb_scuttler_signals[SIGNAL_CONNECTED], 0, success); g_signal_emit(scuttler, ssb_scuttler_signals[SIGNAL_CONNECTED], 0, success);
} }
// extracted from main static void
static gboolean connection_finished(GObject *source, GAsyncResult *result, gpointer user_data)
ssb_scuttler_connect(SsbScuttler *scuttler, GError **error)
{ {
GSocketClient *socket_client = G_SOCKET_CLIENT(source);
GTask *task = user_data;
SsbScuttler *scuttler = g_task_get_task_data(task);
GError *err = NULL;
GSocketConnection *connection = g_socket_client_connect_finish(socket_client, result, &err);
if (connection == NULL) {
g_task_return_error(task, err);
g_object_unref(task);
return;
}
g_clear_object(&(scuttler->connection));
scuttler->connection = connection;
// TODO: This is only required if noauth is not set
if (!ssb_scuttler_shs_connect(scuttler, &err)) {
g_task_return_error(task, err);
g_object_unref(task);
return;
}
g_task_return_boolean(task, TRUE);
emit_connected(scuttler, TRUE);
g_object_unref(task);
}
void
ssb_scuttler_connect_async(SsbScuttler *scuttler,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
GInetAddress *address; GInetAddress *address;
GSocketAddress *destination; GSocketAddress *destination;
GError *err = NULL;
g_return_if_fail(SSB_IS_SCUTTLER(scuttler));
g_return_if_fail((cancellable == NULL) || G_IS_CANCELLABLE(cancellable));
task = g_task_new(scuttler, cancellable, callback, user_data);
// TODO: Maybe there should be a better condition here…
if (scuttler->connection) {
g_task_return_boolean(task, TRUE);
g_object_unref(task);
return;
}
g_clear_object(&(scuttler->socket_client));
scuttler->socket_client = g_socket_client_new(); scuttler->socket_client = g_socket_client_new();
// TODO: Implement the UNIX socket version, too! Also, read this stuff from the // TODO: Implement the UNIX socket version, too! Also, read this stuff from the
@ -622,20 +671,19 @@ ssb_scuttler_connect(SsbScuttler *scuttler, GError **error)
destination = g_inet_socket_address_new(address, 8008); destination = g_inet_socket_address_new(address, 8008);
g_object_unref(address); g_object_unref(address);
scuttler->connection = g_socket_client_connect(scuttler->socket_client, g_task_set_task_data(task, g_object_ref(scuttler), (GDestroyNotify)g_object_unref);
G_SOCKET_CONNECTABLE(destination),
NULL, g_socket_client_connect_async(scuttler->socket_client, G_SOCKET_CONNECTABLE(destination), cancellable, connection_finished, task);
&err);
g_object_unref(destination); g_object_unref(destination);
// TODO: This is only required if noauth is not set
if (!ssb_scuttler_shs_connect(scuttler, &err)) {
g_propagate_error(error, err);
return FALSE;
} }
return TRUE; gboolean
ssb_scuttler_connect_finish(SsbScuttler *scuttler, GAsyncResult *result, GError **error)
{
g_return_val_if_fail(SSB_IS_SCUTTLER(scuttler), FALSE);
g_return_val_if_fail(g_task_is_valid(result, scuttler), FALSE);
return g_task_propagate_boolean(G_TASK(result), error);
} }
static void static void
@ -747,7 +795,22 @@ ssb_scuttler_send_packet(SsbScuttler *scuttler,
} }
// was: muxrpc_call // was: muxrpc_call
static void /**
* ssb_scuttler_muxrpc_call:
* @scuttler: an #SsbScuttler instance
* @method: the name of the RPC method to call
* @argument: the argument for the method
* @type: the type of the RPC call
* @typestr: TODO
* @req_id: the request ID to use in the RPC call
* @error: (nullable): placeholder for a #GError, or %NULL
*
* Start an RPC call to SBOT.
*
* This is a low-level call and unless a specific RPC method is not exposed via other #SsbScuttler
* method, it should not be called explicitly.
*/
void
ssb_scuttler_muxrpc_call(SsbScuttler *scuttler, ssb_scuttler_muxrpc_call(SsbScuttler *scuttler,
const gchar *method, const gchar *method,
const gchar *argument, const gchar *argument,
@ -821,6 +884,12 @@ ssb_scuttler_class_init(SsbScuttlerClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS(klass); GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
if (sodium_init() < 0) {
g_critical("Can not initialise sodium");
return;
}
gobject_class->dispose = ssb_scuttler_dispose; gobject_class->dispose = ssb_scuttler_dispose;
gobject_class->finalize = ssb_scuttler_finalize; gobject_class->finalize = ssb_scuttler_finalize;
@ -851,6 +920,23 @@ ssb_scuttler_class_init(SsbScuttlerClass *klass)
0, NULL, NULL, 0, NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1,
G_TYPE_BOOLEAN); G_TYPE_BOOLEAN);
/**
* SsbScuttler:initialised:
*
* If %TRUE, the scuttler is connected
*/
ssb_scuttler_properties[PROP_INITIALISED] = g_param_spec_boolean(
"initialised", "initialised", "initialised",
FALSE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
ssb_scuttler_properties[PROP_CONNECTED] = g_param_spec_boolean(
"connected", "connected", "connected",
FALSE,
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
g_object_class_install_properties(gobject_class, PROP_COUNT, ssb_scuttler_properties);
} }
static void static void
@ -865,68 +951,12 @@ ssb_scuttler_init(SsbScuttler *scuttler)
scuttler->encrypt_key = NULL; scuttler->encrypt_key = NULL;
} }
gpointer SsbScuttler *
scuttle(gchar *ssb_dir) ssb_scuttler_get(void)
{ {
GMainContext *scuttle_context; if (singleton == NULL) {
GSource *second_hook;
GError *err = NULL;
if (sodium_init() < 0) {
g_critical("Can not initialise sodium");
return NULL; return NULL;
} }
// Since scuttler is a singleton global to this file, we dont need the return value of this return g_object_ref(singleton);
// function now.
if (G_UNLIKELY(!ensure_scuttler(ssb_dir))) {
g_critical("Can not reinitialise scuttler with a new SSB directory.");
return NULL;
}
g_object_ref_sink(singleton);
scuttle_context = g_main_context_new();
scuttle_loop = g_main_loop_new(scuttle_context, FALSE);
// TODO: This is for debugging purposes only, lets remove it as soon as the scuttler works
second_hook = g_timeout_source_new_seconds(1);
g_source_set_callback(second_hook,
G_SOURCE_FUNC(second_hook_cb),
g_main_loop_ref(scuttle_loop),
(GDestroyNotify)g_main_loop_unref);
g_source_attach(second_hook, scuttle_context);
// Set scuttle_context as the default context for this thread
g_main_context_push_thread_default(scuttle_context);
if (!ssb_scuttler_connect(singleton, &err))
{
g_critical("Could not connect: %s", err->message);
return NULL;
}
g_debug("Starting scuttle");
g_main_loop_run(scuttle_loop);
g_main_context_pop_thread_default(scuttle_context);
g_main_loop_unref(scuttle_loop);
g_object_unref(singleton);
g_debug("Scuttling stopped");
scuttle_loop = NULL;
return NULL;
}
void
stop_scuttling(void)
{
if (scuttle_loop) {
g_main_loop_quit(scuttle_loop);
}
} }

View File

@ -2,6 +2,7 @@
# define __SBOT_H__ # define __SBOT_H__
# include <glib-object.h> # include <glib-object.h>
# include <gio/gio.h>
# define SSB_TYPE_SCUTTLER ssb_scuttler_get_type() # define SSB_TYPE_SCUTTLER ssb_scuttler_get_type()
G_DECLARE_FINAL_TYPE(SsbScuttler, ssb_scuttler, SSB, SCUTTLER, GInitiallyUnowned) G_DECLARE_FINAL_TYPE(SsbScuttler, ssb_scuttler, SSB, SCUTTLER, GInitiallyUnowned)
@ -22,6 +23,15 @@ void stop_scuttling(void);
# define SSB_SCUTTLER_ERROR (ssb_scuttler_error_quark()) # define SSB_SCUTTLER_ERROR (ssb_scuttler_error_quark())
GQuark ssb_scuttler_error_quark(void); GQuark ssb_scuttler_error_quark(void);
gboolean ssb_scuttler_ensure(const gchar *ssb_dir);
SsbScuttler *ssb_scuttler_get(void);
void ssb_scuttler_connect_async(SsbScuttler *scuttler,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean ssb_scuttler_connect_finish(SsbScuttler *scuttler,
GAsyncResult *result,
GError **error);
G_END_DECLS G_END_DECLS

View File

@ -7,7 +7,7 @@ struct _SsbApp {
gchar *ssb_dir; gchar *ssb_dir;
SsbWindow *window; SsbWindow *window;
GThread *scuttle_thread; SsbScuttler *scuttler;
}; };
G_DEFINE_TYPE(SsbApp, ssb_app, GTK_TYPE_APPLICATION); G_DEFINE_TYPE(SsbApp, ssb_app, GTK_TYPE_APPLICATION);
@ -78,19 +78,42 @@ ssb_app_dispose(GObject *gobject)
SsbApp *app = SSB_APP(gobject); SsbApp *app = SSB_APP(gobject);
g_clear_object(&(app->window)); g_clear_object(&(app->window));
g_clear_object(&(app->scuttler));
G_OBJECT_CLASS(ssb_app_parent_class)->dispose(gobject); G_OBJECT_CLASS(ssb_app_parent_class)->dispose(gobject);
} }
void
connect_finished(GObject *source, GAsyncResult *res, gpointer user_data)
{
SsbScuttler *scuttler = SSB_SCUTTLER(source);
SsbApp *app = user_data;
GError *err = NULL;
gboolean connect_successful = ssb_scuttler_connect_finish(scuttler, res, &err);
}
static void static void
ssb_app_startup(GApplication *gapp) ssb_app_startup(GApplication *gapp)
{ {
SsbApp *app = SSB_APP(gapp); SsbApp *app = SSB_APP(gapp);
SsbScuttler *scuttler = NULL;
G_APPLICATION_CLASS(ssb_app_parent_class)->startup(gapp); G_APPLICATION_CLASS(ssb_app_parent_class)->startup(gapp);
if (app->scuttle_thread == NULL) { if (G_UNLIKELY(!ssb_scuttler_ensure(app->ssb_dir))) {
app->scuttle_thread = g_thread_new("scuttler", (GThreadFunc)scuttle, app->ssb_dir); g_critical("Can not reinitialise scuttler with a new SSB directory.");
return;
} }
// Wait until the scuttler instance comes up
if ((scuttler = ssb_scuttler_get()) == NULL) {
g_critical("Can not get scuttler object");
}
app->scuttler = g_object_ref_sink(ssb_scuttler_get());
ssb_scuttler_connect_async(app->scuttler, NULL, connect_finished, app);
} }
static SsbWindow * static SsbWindow *
@ -113,12 +136,6 @@ ssb_app_activate(GApplication *app)
static void static void
ssb_app_shutdown(GApplication *gapp) ssb_app_shutdown(GApplication *gapp)
{ {
SsbApp *app = SSB_APP(gapp);
stop_scuttling();
(void)g_thread_join(app->scuttle_thread);
G_APPLICATION_CLASS(ssb_app_parent_class)->shutdown(gapp); G_APPLICATION_CLASS(ssb_app_parent_class)->shutdown(gapp);
} }
@ -130,7 +147,7 @@ ssb_app_init(SsbApp *app)
app->ssb_dir = NULL; app->ssb_dir = NULL;
app->window = NULL; app->window = NULL;
app->scuttle_thread = NULL; app->scuttler = NULL;
if (app_dir_path != NULL) { if (app_dir_path != NULL) {
app->ssb_dir = g_strdup(app_dir_path); app->ssb_dir = g_strdup(app_dir_path);