[gnome-online-accounts] provider: make goa_provider_get_all() async
- From: Marco Barisione <mbari src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-online-accounts] provider: make goa_provider_get_all() async
- Date: Thu, 22 Aug 2013 14:18:04 +0000 (UTC)
commit 1a8bfdf90fd24e9bbaeeae15ff9f16e847a6b48e
Author: Marco Barisione <marco barisione collabora co uk>
Date: Wed Jul 24 16:32:55 2013 +0100
provider: make goa_provider_get_all() async
https://bugzilla.gnome.org/show_bug.cgi?id=696267
src/daemon/goadaemon.c | 121 +++++++++++++++++++---------
src/examples/list-providers.c | 41 +++++++++-
src/goabackend/goaprovider.c | 176 ++++++++++++++++++++++++++++++++++++++---
src/goabackend/goaprovider.h | 6 +-
4 files changed, 292 insertions(+), 52 deletions(-)
---
diff --git a/src/daemon/goadaemon.c b/src/daemon/goadaemon.c
index aead6b1..5da951d 100644
--- a/src/daemon/goadaemon.c
+++ b/src/daemon/goadaemon.c
@@ -717,17 +717,24 @@ generate_new_id (GoaDaemon *daemon)
return ret;
}
-static gboolean
-on_manager_handle_add_account (GoaManager *manager,
- GDBusMethodInvocation *invocation,
- const gchar *provider_type,
- const gchar *identity,
- const gchar *presentation_identity,
- GVariant *credentials,
- GVariant *details,
- gpointer user_data)
+typedef struct
{
- GoaDaemon *daemon = GOA_DAEMON (user_data);
+ GoaDaemon *daemon;
+ GoaManager *manager;
+ GDBusMethodInvocation *invocation;
+ gchar *provider_type;
+ gchar *identity;
+ gchar *presentation_identity;
+ GVariant *credentials;
+ GVariant *details;
+} AddAccountData;
+
+static void
+get_all_providers_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ AddAccountData *data = user_data;
GoaProvider *provider;
GKeyFile *key_file;
GError *error;
@@ -736,7 +743,7 @@ on_manager_handle_add_account (GoaManager *manager,
gchar *path;
gchar *id;
gchar *group;
- gchar *data;
+ gchar *key_file_data;
gsize length;
gchar *object_path;
GVariantIter iter;
@@ -751,10 +758,12 @@ on_manager_handle_add_account (GoaManager *manager,
path = NULL;
id = NULL;
group = NULL;
- data = NULL;
+ key_file_data = NULL;
object_path = NULL;
- providers = goa_provider_get_all ();
+ if (!goa_provider_get_all_finish (&providers, res, NULL))
+ goto out;
+
for (l = providers; l != NULL; l = l->next)
{
GoaProvider *p;
@@ -762,7 +771,7 @@ on_manager_handle_add_account (GoaManager *manager,
p = GOA_PROVIDER (l->data);
type = goa_provider_get_provider_type (p);
- if (g_strcmp0 (type, provider_type) == 0)
+ if (g_strcmp0 (type, data->provider_type) == 0)
{
provider = p;
break;
@@ -776,8 +785,8 @@ on_manager_handle_add_account (GoaManager *manager,
GOA_ERROR,
GOA_ERROR_FAILED, /* TODO: more specific */
_("Failed to find a provider for: %s"),
- provider_type);
- g_dbus_method_invocation_return_gerror (invocation, error);
+ data->provider_type);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
goto out;
}
@@ -785,7 +794,7 @@ on_manager_handle_add_account (GoaManager *manager,
path = g_strdup_printf ("%s/goa-1.0/accounts.conf", g_get_user_config_dir ());
error = NULL;
if (!g_file_get_contents (path,
- &data,
+ &key_file_data,
&length,
&error))
{
@@ -796,7 +805,7 @@ on_manager_handle_add_account (GoaManager *manager,
else
{
g_prefix_error (&error, "Error loading file %s: ", path);
- g_dbus_method_invocation_return_gerror (invocation, error);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
goto out;
}
}
@@ -805,22 +814,22 @@ on_manager_handle_add_account (GoaManager *manager,
if (length > 0)
{
error = NULL;
- if (!g_key_file_load_from_data (key_file, data, length, G_KEY_FILE_KEEP_COMMENTS, &error))
+ if (!g_key_file_load_from_data (key_file, key_file_data, length, G_KEY_FILE_KEEP_COMMENTS, &error))
{
g_prefix_error (&error, "Error parsing key-value-file %s: ", path);
- g_dbus_method_invocation_return_gerror (invocation, error);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
goto out;
}
}
}
- id = generate_new_id (daemon);
+ id = generate_new_id (data->daemon);
group = g_strdup_printf ("Account %s", id);
- g_key_file_set_string (key_file, group, "Provider", provider_type);
- g_key_file_set_string (key_file, group, "Identity", identity);
- g_key_file_set_string (key_file, group, "PresentationIdentity", presentation_identity);
+ g_key_file_set_string (key_file, group, "Provider", data->provider_type);
+ g_key_file_set_string (key_file, group, "Identity", data->identity);
+ g_key_file_set_string (key_file, group, "PresentationIdentity", data->presentation_identity);
- g_variant_iter_init (&iter, details);
+ g_variant_iter_init (&iter, data->details);
while (g_variant_iter_next (&iter, "{&s&s}", &key, &value))
{
/* We treat IsTemporary special. If it's true we add in
@@ -833,7 +842,7 @@ on_manager_handle_add_account (GoaManager *manager,
{
const char *guid;
- guid = g_dbus_connection_get_guid (daemon->connection);
+ guid = g_dbus_connection_get_guid (data->daemon->connection);
g_key_file_set_string (key_file, group, "SessionId", guid);
}
}
@@ -841,26 +850,26 @@ on_manager_handle_add_account (GoaManager *manager,
g_key_file_set_string (key_file, group, key, value);
}
- g_free (data);
+ g_free (key_file_data);
error = NULL;
- data = g_key_file_to_data (key_file,
- &length,
- &error);
- if (data == NULL)
+ key_file_data = g_key_file_to_data (key_file,
+ &length,
+ &error);
+ if (key_file_data == NULL)
{
g_prefix_error (&error, "Error generating key-value-file: ");
- g_dbus_method_invocation_return_gerror (invocation, error);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
goto out;
}
error = NULL;
if (!g_file_set_contents (path,
- data,
+ key_file_data,
length,
&error))
{
g_prefix_error (&error, "Error writing key-value-file %s: ", path);
- g_dbus_method_invocation_return_gerror (invocation, error);
+ g_dbus_method_invocation_return_gerror (data->invocation, error);
goto out;
}
@@ -869,26 +878,62 @@ on_manager_handle_add_account (GoaManager *manager,
*/
goa_utils_store_credentials_for_id_sync (provider,
id,
- credentials,
+ data->credentials,
NULL, /* GCancellable */
NULL);
- goa_daemon_reload_configuration (daemon);
+ goa_daemon_reload_configuration (data->daemon);
object_path = g_strdup_printf ("/org/gnome/OnlineAccounts/Accounts/%s", id);
- goa_manager_complete_add_account (manager, invocation, object_path);
+ goa_manager_complete_add_account (data->manager, data->invocation, object_path);
out:
g_free (object_path);
if (providers != NULL)
g_list_free_full (providers, g_object_unref);
- g_free (data);
+ g_free (key_file_data);
g_free (group);
g_free (id);
g_free (path);
if (key_file != NULL)
g_key_file_free (key_file);
+ g_object_unref (data->daemon);
+ g_object_unref (data->manager);
+ g_object_unref (data->invocation);
+ g_free (data->provider_type);
+ g_free (data->identity);
+ g_free (data->presentation_identity);
+ g_variant_unref (data->credentials);
+ g_variant_unref (data->details);
+ g_slice_free (AddAccountData, data);
+}
+
+static gboolean
+on_manager_handle_add_account (GoaManager *manager,
+ GDBusMethodInvocation *invocation,
+ const gchar *provider_type,
+ const gchar *identity,
+ const gchar *presentation_identity,
+ GVariant *credentials,
+ GVariant *details,
+ gpointer user_data)
+{
+ GoaDaemon *daemon = GOA_DAEMON (user_data);
+ AddAccountData *data;
+
+ data = g_slice_new0 (AddAccountData);
+ data->daemon = g_object_ref (daemon);
+ data->manager = g_object_ref (manager);
+ data->invocation = g_object_ref (invocation);
+ data->provider_type = g_strdup (provider_type);
+ data->identity = g_strdup (identity);
+ data->presentation_identity = g_strdup (presentation_identity);
+ data->credentials = g_variant_ref (credentials);
+ data->details = g_variant_ref (details);
+
+ goa_provider_get_all (get_all_providers_cb, data);
+
return TRUE; /* invocation was handled */
}
diff --git a/src/examples/list-providers.c b/src/examples/list-providers.c
index 3aa93ad..3079f1f 100644
--- a/src/examples/list-providers.c
+++ b/src/examples/list-providers.c
@@ -25,14 +25,45 @@
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
+typedef struct
+{
+ GMainLoop *loop;
+ GList *providers;
+ GError *error;
+} GetAllData;
+
+static void
+get_all_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GetAllData *data = user_data;
+
+ goa_provider_get_all_finish (&data->providers, res, &data->error);
+ g_main_loop_quit (data->loop);
+}
+
int
main (int argc, char **argv)
{
+ GetAllData data = {0,};
GoaProvider *provider;
- GList *providers, *l;
+ GList *l;
+
+ data.loop = g_main_loop_new (NULL, FALSE);
+ goa_provider_get_all (get_all_cb, &data);
+ g_main_loop_run (data.loop);
- providers = goa_provider_get_all ();
- for (l = providers; l != NULL; l = l->next) {
+ if (data.error != NULL) {
+ g_printerr ("Failed to list providers: %s (%s, %d)\n",
+ data.error->message,
+ g_quark_to_string (data.error->domain),
+ data.error->code);
+ g_error_free (data.error);
+ goto out;
+ }
+
+ for (l = data.providers; l != NULL; l = l->next) {
char *provider_name;
provider = GOA_PROVIDER (l->data);
@@ -42,5 +73,9 @@ main (int argc, char **argv)
provider = NULL;
}
+out:
+ g_main_loop_unref (data.loop);
+ g_list_free_full (data.providers, g_object_unref);
+
return 0;
}
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index 9880c2c..7d7170c 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -899,37 +899,193 @@ goa_provider_get_for_provider_type (const gchar *provider_type)
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct
+{
+ GQueue ret;
+ gint pending_calls;
+ GSimpleAsyncResult *result;
+} GetAllData;
+
+static void
+free_list_and_unref (gpointer data)
+{
+ g_list_free_full (data, g_object_unref);
+}
+
+static gint
+compare_providers (GoaProvider *a,
+ GoaProvider *b)
+{
+ gboolean a_branded;
+ gboolean b_branded;
+
+ if (goa_provider_get_provider_features (a) & GOA_PROVIDER_FEATURE_BRANDED)
+ a_branded = TRUE;
+ else
+ a_branded = FALSE;
+
+ if (goa_provider_get_provider_features (b) & GOA_PROVIDER_FEATURE_BRANDED)
+ b_branded = TRUE;
+ else
+ b_branded = FALSE;
+
+ /* g_queue_sort() uses a stable sort, so, if we return 0, the order
+ * is not changed. */
+ if (a_branded == b_branded)
+ return 0;
+ else if (a_branded)
+ return -1;
+ else
+ return 1;
+}
+
+static void
+get_all_check_done (GetAllData *data)
+{
+ if (data->pending_calls > 0)
+ return;
+
+ /* Make sure that branded providers come first, but don't change the
+ * order otherwise. */
+ g_queue_sort (&data->ret, (GCompareDataFunc) compare_providers, NULL);
+
+ /* Steal the list out of the GQueue. */
+ g_simple_async_result_set_op_res_gpointer (data->result, data->ret.head,
+ free_list_and_unref);
+ g_simple_async_result_complete_in_idle (data->result);
+
+ g_object_unref (data->result);
+ g_slice_free (GetAllData, data);
+}
+
+static void
+get_providers_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GoaProviderFactory *factory = GOA_PROVIDER_FACTORY (source);
+ GetAllData *data = user_data;
+ GList *providers = NULL;
+ GList *l;
+ GError *error = NULL;
+
+ if (!goa_provider_factory_get_providers_finish (factory, &providers, res, &error))
+ {
+ goa_error ("Error getting providers from a factory: %s (%s, %d)",
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_clear_error (&error);
+ goto out;
+ }
+
+ for (l = providers; l != NULL; l = l->next)
+ {
+ /* Steal the value */
+ g_queue_push_tail (&data->ret, l->data);
+ }
+
+ g_list_free (providers);
+
+out:
+ data->pending_calls--;
+ get_all_check_done (data);
+}
+
/**
* goa_provider_get_all:
+ * @callback: The function to call when the request is satisfied.
+ * @user_data: Pointer to pass to @callback.
*
- * Looks up the %GOA_PROVIDER_EXTENSION_POINT_NAME extension
- * point and returns a newly created #GoaProvider for each
- * provider type encountered.
+ * Creates a list of all the available #GoaProvider instances.
+ *
+ * When the result is ready, @callback will be called in the the <link
+ * linkend="g-main-context-push-thread-default">thread-default main
+ * loop</link> this function was called from. You can then call
+ * goa_provider_get_all_finish() to get the result of the operation.
+ *
+ * See goa_provider_get_for_provider_type() for details on how the providers
+ * are found.
*
* Returns: (transfer full) (element-type GoaProvider): A list
* of element providers that should be freed with g_list_free()
* after each element has been freed with g_object_unref().
*/
-GList *
-goa_provider_get_all (void)
+void
+goa_provider_get_all (GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GList *ret;
GList *extensions;
GList *l;
GIOExtensionPoint *extension_point;
+ GetAllData *data;
+ gint i;
ensure_builtins_loaded ();
- ret = NULL;
+ data = g_slice_new0 (GetAllData);
+ data->result = g_simple_async_result_new (NULL, callback, user_data,
+ goa_provider_get_all);
+ g_queue_init (&data->ret);
+
+ /* Load the normal providers. */
extension_point = g_io_extension_point_lookup (GOA_PROVIDER_EXTENSION_POINT_NAME);
extensions = g_io_extension_point_get_extensions (extension_point);
/* TODO: what if there are two extensions with the same name? */
- for (l = extensions; l != NULL; l = l->next)
+ for (l = extensions, i = 0; l != NULL; l = l->next, i++)
{
GIOExtension *extension = l->data;
- ret = g_list_prepend (ret, g_object_new (g_io_extension_get_type (extension), NULL));
+ /* The extensions are loaded in the reverse order we used in
+ * ensure_builtins_loaded, so we need to push extension if front of
+ * the already loaded ones. */
+ g_queue_push_head (&data->ret, g_object_new (g_io_extension_get_type (extension), NULL));
}
- return ret;
+
+ /* Load the provider factories and get the dynamic providers out of them. */
+ extension_point = g_io_extension_point_lookup (GOA_PROVIDER_FACTORY_EXTENSION_POINT_NAME);
+ extensions = g_io_extension_point_get_extensions (extension_point);
+ for (l = extensions, i = 0; l != NULL; l = l->next, i++)
+ {
+ GIOExtension *extension = l->data;
+ goa_provider_factory_get_providers (g_object_new (g_io_extension_get_type (extension), NULL),
+ get_providers_cb, data);
+ data->pending_calls++;
+ }
+
+ get_all_check_done (data);
+}
+
+/**
+ * goa_provider_get_all_finish:
+ * @out_providers: (out): Return location for a list of #GoaProvider instances.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to goa_provider_get_all().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with goa_provider_get_all().
+ *
+ * Returns: %TRUE if the list was successfully retrieved, %FALSE if @error is set.
+ */
+gboolean
+goa_provider_get_all_finish (GList **out_providers,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = (GSimpleAsyncResult *) result;
+ GList *providers;
+
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+ goa_provider_get_all), FALSE);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ if (out_providers != NULL)
+ {
+ providers = g_simple_async_result_get_op_res_gpointer (simple);
+ *out_providers = g_list_copy_deep (providers, (GCopyFunc) g_object_ref, NULL);
+ }
+
+ return TRUE;
}
/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/goabackend/goaprovider.h b/src/goabackend/goaprovider.h
index 89fb826..67aa5fd 100644
--- a/src/goabackend/goaprovider.h
+++ b/src/goabackend/goaprovider.h
@@ -174,7 +174,11 @@ gboolean goa_provider_ensure_credentials_sync (GoaProvider *provid
GError **error);
guint goa_provider_get_credentials_generation (GoaProvider *provider);
-GList *goa_provider_get_all (void);
+void goa_provider_get_all (GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean goa_provider_get_all_finish (GList **out_providers,
+ GAsyncResult *result,
+ GError **error);
GoaProvider *goa_provider_get_for_provider_type (const gchar *provider_type);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]