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
};
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;
SsbScuttler *singleton = NULL;
@ -232,7 +239,7 @@ emit_initialised(SsbScuttler *scuttler, gboolean success)
}
static void
initialise(SsbScuttler *scuttler, gchar *ssb_dir)
initialise(SsbScuttler *scuttler, const gchar *ssb_dir)
{
gchar *config_data = 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
*
* Ensure the scuttler singleton is initialised with @ssb_dir as its base directory.
*/
static inline gboolean
ensure_scuttler(gchar *ssb_dir)
gboolean
ssb_scuttler_ensure(const gchar *ssb_dir)
{
if (singleton != NULL) {
if ((ssb_dir != NULL) && g_strcmp0(ssb_dir, singleton->ssb_dir)) {
@ -344,14 +351,6 @@ ensure_scuttler(gchar *ssb_dir)
return TRUE;
}
static gboolean
second_hook_cb()
{
g_print("Scuttling…\n");
return TRUE;
}
// was: write_all
static gboolean
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->wrote_goodbye = FALSE;
g_debug("SHS succeeded");
return TRUE;
}
@ -606,14 +607,62 @@ emit_connected(SsbScuttler *scuttler, gboolean success)
g_signal_emit(scuttler, ssb_scuttler_signals[SIGNAL_CONNECTED], 0, success);
}
// extracted from main
static gboolean
ssb_scuttler_connect(SsbScuttler *scuttler, GError **error)
static void
connection_finished(GObject *source, GAsyncResult *result, gpointer user_data)
{
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;
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();
// 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);
g_object_unref(address);
scuttler->connection = g_socket_client_connect(scuttler->socket_client,
G_SOCKET_CONNECTABLE(destination),
NULL,
&err);
g_task_set_task_data(task, g_object_ref(scuttler), (GDestroyNotify)g_object_unref);
g_socket_client_connect_async(scuttler->socket_client, G_SOCKET_CONNECTABLE(destination), cancellable, connection_finished, task);
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);
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 FALSE;
}
return TRUE;
return g_task_propagate_boolean(G_TASK(result), error);
}
static void
@ -747,7 +795,22 @@ ssb_scuttler_send_packet(SsbScuttler *scuttler,
}
// 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,
const gchar *method,
const gchar *argument,
@ -821,6 +884,12 @@ ssb_scuttler_class_init(SsbScuttlerClass *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->finalize = ssb_scuttler_finalize;
@ -851,6 +920,23 @@ ssb_scuttler_class_init(SsbScuttlerClass *klass)
0, NULL, NULL,
g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1,
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
@ -865,68 +951,12 @@ ssb_scuttler_init(SsbScuttler *scuttler)
scuttler->encrypt_key = NULL;
}
gpointer
scuttle(gchar *ssb_dir)
SsbScuttler *
ssb_scuttler_get(void)
{
GMainContext *scuttle_context;
GSource *second_hook;
GError *err = NULL;
if (sodium_init() < 0) {
g_critical("Can not initialise sodium");
if (singleton == NULL) {
return NULL;
}
// Since scuttler is a singleton global to this file, we dont need the return value of this
// 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);
}
return g_object_ref(singleton);
}

View File

@ -2,6 +2,7 @@
# define __SBOT_H__
# include <glib-object.h>
# include <gio/gio.h>
# define SSB_TYPE_SCUTTLER ssb_scuttler_get_type()
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())
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

View File

@ -7,7 +7,7 @@ struct _SsbApp {
gchar *ssb_dir;
SsbWindow *window;
GThread *scuttle_thread;
SsbScuttler *scuttler;
};
G_DEFINE_TYPE(SsbApp, ssb_app, GTK_TYPE_APPLICATION);
@ -78,19 +78,42 @@ ssb_app_dispose(GObject *gobject)
SsbApp *app = SSB_APP(gobject);
g_clear_object(&(app->window));
g_clear_object(&(app->scuttler));
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
ssb_app_startup(GApplication *gapp)
{
SsbApp *app = SSB_APP(gapp);
SsbScuttler *scuttler = NULL;
G_APPLICATION_CLASS(ssb_app_parent_class)->startup(gapp);
if (app->scuttle_thread == NULL) {
app->scuttle_thread = g_thread_new("scuttler", (GThreadFunc)scuttle, app->ssb_dir);
if (G_UNLIKELY(!ssb_scuttler_ensure(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 *
@ -113,12 +136,6 @@ ssb_app_activate(GApplication *app)
static void
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);
}
@ -130,7 +147,7 @@ ssb_app_init(SsbApp *app)
app->ssb_dir = NULL;
app->window = NULL;
app->scuttle_thread = NULL;
app->scuttler = NULL;
if (app_dir_path != NULL) {
app->ssb_dir = g_strdup(app_dir_path);