wip: remove threads, make ssb_scuttler_connect an async method
This commit is contained in:
parent
cc4e304418
commit
373d9ace84
208
ssb-gtk/sbot.c
208
ssb-gtk/sbot.c
@ -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 don’t 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, let’s 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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user