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
|
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 don’t 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, 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user