[Telepathy-commits] [telepathy-mission-control/master] Asynchronous loading of accounts

Alberto Mardegan alberto.mardegan at nokia.com
Tue Feb 3 06:34:56 PST 2009


Allow for accounts to be loaded and created asynchronously.
Also, don't request the service name to DBus before having loaded all the
accounts.
---
 src/mcd-account-manager.c |  178 ++++++++++++++++++++++++++++++++++----------
 src/mcd-account-manager.h |   21 +++--
 src/mcd-account.c         |   76 ++++++++++++++++---
 src/mcd-account.h         |   11 +++-
 4 files changed, 223 insertions(+), 63 deletions(-)

diff --git a/src/mcd-account-manager.c b/src/mcd-account-manager.c
index d232318..8d988dd 100644
--- a/src/mcd-account-manager.c
+++ b/src/mcd-account-manager.c
@@ -83,6 +83,21 @@ struct _McdAccountManagerPrivate
     GHashTable *invalid_accounts;
 };
 
+typedef struct
+{
+    McdAccountManager *account_manager;
+    gint account_lock;
+} McdLoadAccountsData;
+
+typedef struct
+{
+    McdAccountManager *account_manager;
+    GHashTable *parameters;
+    McdGetAccountCb callback;
+    gpointer user_data;
+    GDestroyNotify destroy;
+} McdCreateAccountData;
+
 enum
 {
     PROP_0,
@@ -91,6 +106,8 @@ enum
 
 static guint write_conf_id = 0;
 
+static void register_dbus_service (McdAccountManager *account_manager);
+
 static McdAccount *
 account_new (McdAccountManager *account_manager, const gchar *name)
 {
@@ -174,23 +191,34 @@ add_account (McdAccountManager *account_manager, McdAccount *account)
     return valid;
 }
 
-static McdAccount *
-complete_account_creation (McdAccountManager *account_manager,
-			   const gchar *unique_name,
-			   GHashTable *params,
-			   const gchar **object_path,
-			   GError **error)
+static void
+mcd_create_account_data_free (McdCreateAccountData *cad)
 {
-    McdAccount *account;
+    g_hash_table_unref (cad->parameters);
+    g_slice_free (McdCreateAccountData, cad);
+}
+
+static void
+complete_account_creation (McdAccount *account,
+                           const GError *cb_error,
+                           gpointer user_data)
+{
+    McdCreateAccountData *cad = user_data;
+    McdAccountManager *account_manager;
+    GError *error = NULL;
     gboolean ok;
 
-    account = MCD_ACCOUNT_MANAGER_GET_CLASS (account_manager)->account_new
-        (account_manager, unique_name);
+    account_manager = cad->account_manager;
+    if (G_UNLIKELY (cb_error))
+    {
+        cad->callback (account_manager, account, cb_error, cad->user_data);
+        mcd_create_account_data_free (cad);
+        return;
+    }
 
-    ok = mcd_account_set_parameters (account, params, error);
+    ok = mcd_account_set_parameters (account, cad->parameters, &error);
     if (ok)
     {
-	*object_path = mcd_account_get_object_path (account);
 	add_account (account_manager, account);
 	mcd_account_check_validity (account);
     }
@@ -201,7 +229,11 @@ complete_account_creation (McdAccountManager *account_manager,
 	account = NULL;
     }
     mcd_account_manager_write_conf (account_manager);
-    return account;
+
+    cad->callback (account_manager, account, error, cad->user_data);
+    if (G_UNLIKELY (error))
+        g_error_free (error);
+    mcd_create_account_data_free (cad);
 }
 
 static gchar *
@@ -244,26 +276,30 @@ create_unique_name (McdAccountManagerPrivate *priv, const gchar *manager,
     return unique_name;
 }
 
-McdAccount *
+void
 mcd_account_manager_create_account (McdAccountManager *account_manager,
 				    const gchar *manager,
 				    const gchar *protocol,
 				    const gchar *display_name,
 				    GHashTable *params,
-				    const gchar **account_obj,
-				    GError **error)
+                                    McdGetAccountCb callback,
+                                    gpointer user_data, GDestroyNotify destroy)
 {
     McdAccountManagerPrivate *priv = account_manager->priv;
-    gchar *unique_name;
+    McdCreateAccountData *cad;
     McdAccount *account;
+    gchar *unique_name;
 
     g_debug ("%s called", G_STRFUNC);
     if (G_UNLIKELY (manager == NULL || manager[0] == 0 ||
 		    protocol == NULL || protocol[0] == 0))
     {
-	g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-		     "Invalid parameters");
-	return NULL;
+        GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+            "Invalid parameters"};
+        callback (account_manager, NULL, &error, user_data);
+        if (destroy)
+            destroy (user_data);
+        return;
     }
 
     unique_name = create_unique_name (priv, manager, protocol, params);
@@ -278,38 +314,61 @@ mcd_account_manager_create_account (McdAccountManager *account_manager,
 	g_key_file_set_string (priv->keyfile, unique_name,
 			       MC_ACCOUNTS_KEY_DISPLAY_NAME, display_name);
 
-    account = complete_account_creation (account_manager, unique_name,
-					 params, account_obj, error);
+    account = MCD_ACCOUNT_MANAGER_GET_CLASS (account_manager)->account_new
+        (account_manager, unique_name);
     g_free (unique_name);
-    return account;
+
+    if (G_LIKELY (account))
+    {
+        cad = g_slice_new (McdCreateAccountData);
+        cad->account_manager = account_manager;
+        cad->parameters = g_hash_table_ref (params);
+        cad->callback = callback;
+        cad->user_data = user_data;
+        cad->destroy = destroy;
+        _mcd_account_load (account, complete_account_creation, cad);
+    }
+    else
+    {
+        GError error = { TP_ERRORS, TP_ERROR_NOT_AVAILABLE, "" };
+        callback (account_manager, NULL, &error, user_data);
+        if (destroy)
+            destroy (user_data);
+    }
 }
 
 static void
-account_manager_create_account (McSvcAccountManager *self,
-			       	const gchar *manager, const gchar *protocol,
-				const gchar *display_name,
-				GHashTable *parameters,
-				DBusGMethodInvocation *context)
+create_account_cb (McdAccountManager *account_manager, McdAccount *account,
+                   const GError *error, gpointer user_data)
 {
-    GError *error = NULL;
+    DBusGMethodInvocation *context = user_data;
     const gchar *object_path;
 
-    if (!mcd_account_manager_create_account (MCD_ACCOUNT_MANAGER (self),
-					     manager, protocol, display_name,
-					     parameters, &object_path, &error))
+    if (G_UNLIKELY (error))
     {
-	if (!error)
-	    g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
-			 "Internal error");
-	dbus_g_method_return_error (context, error);
-	g_error_free (error);
+        dbus_g_method_return_error (context, (GError *)error);
 	return;
     }
 
+    g_return_if_fail (MCD_IS_ACCOUNT (account));
+    object_path = mcd_account_get_object_path (account);
     mc_svc_account_manager_return_from_create_account (context, object_path);
 }
 
 static void
+account_manager_create_account (McSvcAccountManager *self,
+			       	const gchar *manager, const gchar *protocol,
+				const gchar *display_name,
+				GHashTable *parameters,
+				DBusGMethodInvocation *context)
+{
+    mcd_account_manager_create_account (MCD_ACCOUNT_MANAGER (self),
+                                        manager, protocol, display_name,
+                                        parameters,
+                                        create_account_cb, context, NULL);
+}
+
+static void
 account_manager_iface_init (McSvcAccountManagerClass *iface,
 			    gpointer iface_data)
 {
@@ -435,6 +494,32 @@ write_conf (gpointer userdata)
     return FALSE;
 }
 
+static void
+release_load_accounts_lock (McdLoadAccountsData *lad)
+{
+    g_return_if_fail (lad->account_lock > 0);
+    lad->account_lock--;
+    g_debug ("%s called, count is now %d", G_STRFUNC, lad->account_lock);
+    if (lad->account_lock == 0)
+    {
+        register_dbus_service (lad->account_manager);
+        g_slice_free (McdLoadAccountsData, lad);
+    }
+}
+
+static void
+account_loaded (McdAccount *account, const GError *error, gpointer user_data)
+{
+    McdLoadAccountsData *lad = user_data;
+
+    if (error)
+        g_warning ("%s: got error: %s", G_STRFUNC, error->message);
+    else
+        add_account (lad->account_manager, account);
+
+    release_load_accounts_lock (lad);
+}
+
 /**
  * _mcd_account_manager_setup:
  * @account_manager: the #McdAccountManager.
@@ -446,19 +531,32 @@ void
 _mcd_account_manager_setup (McdAccountManager *account_manager)
 {
     McdAccountManagerPrivate *priv = account_manager->priv;
+    McdLoadAccountsData *lad;
     gchar **accounts, **name;
 
+    lad = g_slice_new (McdLoadAccountsData);
+    lad->account_manager = account_manager;
+    lad->account_lock = 1; /* will be released at the end of this function */
+
     accounts = g_key_file_get_groups (priv->keyfile, NULL);
     for (name = accounts; *name != NULL; name++)
     {
-	McdAccount *account;
+        McdAccount *account;
 
         account = MCD_ACCOUNT_MANAGER_GET_CLASS (account_manager)->account_new
             (account_manager, *name);
-	if (account)
-	    add_account (account_manager, account);
+        if (G_UNLIKELY (!account))
+        {
+            g_warning ("%s: account %s failed to instantiate", G_STRFUNC,
+                       *name);
+            continue;
+        }
+        lad->account_lock++;
+        _mcd_account_load (account, account_loaded, lad);
     }
     g_strfreev (accounts);
+
+    release_load_accounts_lock (lad);
 }
 
 static void
@@ -500,8 +598,6 @@ set_property (GObject *obj, guint prop_id,
 	if (priv->dbus_daemon)
 	    g_object_unref (priv->dbus_daemon);
 	priv->dbus_daemon = TP_DBUS_DAEMON (g_value_dup_object (val));
-	if (priv->dbus_daemon)
-	    register_dbus_service (account_manager);
 	break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
diff --git a/src/mcd-account-manager.h b/src/mcd-account-manager.h
index 10af94a..b78fbc3 100644
--- a/src/mcd-account-manager.h
+++ b/src/mcd-account-manager.h
@@ -89,14 +89,19 @@ McdAccount *mcd_account_manager_lookup_account_by_path (McdAccountManager *accou
 /* for interfaces only */
 G_GNUC_INTERNAL
 GHashTable *mcd_account_manager_get_valid_accounts (McdAccountManager *account_manager);
+
+typedef void (*McdGetAccountCb) (McdAccountManager *account_manager,
+                                 McdAccount *account,
+                                 const GError *error,
+                                 gpointer user_data);
 G_GNUC_INTERNAL
-McdAccount *mcd_account_manager_create_account (McdAccountManager *
-						account_manager,
-						const gchar *manager,
-						const gchar *protocol,
-						const gchar *display_name,
-						GHashTable *params,
-						const gchar **account_obj,
-						GError **error);
+void mcd_account_manager_create_account (McdAccountManager *account_manager,
+                                         const gchar *manager,
+                                         const gchar *protocol,
+                                         const gchar *display_name,
+                                         GHashTable *params,
+                                         McdGetAccountCb callback,
+                                         gpointer user_data,
+                                         GDestroyNotify destroy);
 
 #endif
diff --git a/src/mcd-account.c b/src/mcd-account.c
index 678f742..30388a0 100644
--- a/src/mcd-account.c
+++ b/src/mcd-account.c
@@ -133,6 +133,7 @@ struct _McdAccountPrivate
     guint connect_automatically : 1;
     guint enabled : 1;
     guint valid : 1;
+    guint loaded : 1;
 
     /* These fields are used to cache the changed properties */
     GHashTable *changed_properties;
@@ -149,6 +150,17 @@ enum
 };
 
 guint _mcd_account_signals[LAST_SIGNAL] = { 0 };
+static GQuark account_ready_quark = 0;
+
+static void
+mcd_account_loaded (McdAccount *account)
+{
+    g_return_if_fail (!account->priv->loaded);
+    account->priv->loaded = TRUE;
+
+    /* invoke all the callbacks */
+    mcd_object_ready (account, account_ready_quark, NULL);
+}
 
 static void
 set_parameter (McdAccount *account, const gchar *name, const GValue *value)
@@ -251,6 +263,23 @@ get_parameter (McdAccount *account, const gchar *name, GValue *value)
     return TRUE;
 }
 
+static void on_manager_ready (McdManager *manager, const GError *error,
+                              gpointer user_data)
+{
+    McdAccount *account = MCD_ACCOUNT (user_data);
+    McdAccountPrivate *priv = account->priv;
+
+    if (error)
+    {
+        g_debug ("%s: got error: %s", G_STRFUNC, error->message);
+    }
+    else
+    {
+        priv->valid = mcd_account_check_parameters (account);
+    }
+    mcd_account_loaded (account);
+}
+
 static gboolean
 load_manager (McdAccount *account)
 {
@@ -263,6 +292,7 @@ load_manager (McdAccount *account)
     if (priv->manager)
     {
 	g_object_ref (priv->manager);
+        mcd_manager_call_when_ready (priv->manager, on_manager_ready, account);
 	return TRUE;
     }
     else
@@ -325,6 +355,17 @@ _mcd_account_delete (McdAccount *account, GError **error)
 }
 
 static void
+_mcd_account_load_real (McdAccount *account, McdAccountLoadCb callback,
+                        gpointer user_data)
+{
+    if (account->priv->loaded)
+        callback (account, NULL, user_data);
+    else
+        mcd_object_call_when_ready (account, account_ready_quark,
+                                    (McdReadyCb)callback, user_data);
+}
+
+static void
 on_connection_abort (McdConnection *connection, McdAccount *account)
 {
     McdAccountPrivate *priv = MCD_ACCOUNT_PRIV (account);
@@ -1224,7 +1265,6 @@ static gboolean
 mcd_account_setup (McdAccount *account)
 {
     McdAccountPrivate *priv = account->priv;
-    gboolean valid;
 
     priv->keyfile = mcd_account_manager_get_config (priv->account_manager);
     if (!priv->keyfile) return FALSE;
@@ -1250,16 +1290,6 @@ mcd_account_setup (McdAccount *account)
 	g_key_file_get_boolean (priv->keyfile, priv->unique_name,
 				MC_ACCOUNTS_KEY_CONNECT_AUTOMATICALLY, NULL);
 
-    /* check the manager */
-    if (!priv->manager && !load_manager (account))
-    {
-	g_warning ("Could not find manager `%s'", priv->manager_name);
-	valid = FALSE;
-    }
-    else
-	valid = mcd_account_check_parameters (account);
-    priv->valid = valid;
-
     /* load the automatic presence */
     priv->auto_presence_type =
 	g_key_file_get_integer (priv->keyfile, priv->unique_name,
@@ -1273,6 +1303,14 @@ mcd_account_setup (McdAccount *account)
 			       MC_ACCOUNTS_KEY_AUTO_PRESENCE_MESSAGE,
 			       NULL);
 
+    /* check the manager */
+    if (!priv->manager && !load_manager (account))
+    {
+	g_warning ("Could not find manager `%s'", priv->manager_name);
+        mcd_account_loaded (account);
+    }
+
+    _mcd_account_load (account, (McdAccountLoadCb)register_dbus_service, NULL);
     return TRUE;
 }
 
@@ -1420,8 +1458,7 @@ _mcd_account_constructed (GObject *object)
     GObjectClass *object_class = (GObjectClass *)mcd_account_parent_class;
     McdAccount *account = MCD_ACCOUNT (object);
 
-    if (mcd_account_setup (account))
-        register_dbus_service (account);
+    mcd_account_setup (account);
 
     if (object_class->constructed)
         object_class->constructed (object);
@@ -1443,6 +1480,7 @@ mcd_account_class_init (McdAccountClass * klass)
     klass->get_parameter = get_parameter;
     klass->set_parameter = set_parameter;
     klass->delete = _mcd_account_delete;
+    klass->load = _mcd_account_load_real;
 
     g_object_class_install_property
         (object_class, PROP_DBUS_DAEMON,
@@ -1511,6 +1549,8 @@ mcd_account_class_init (McdAccountClass * klass)
 		      NULL, NULL, g_cclosure_marshal_VOID__STRING,
 		      G_TYPE_NONE, 1, G_TYPE_STRING);
     _mcd_account_connection_class_init (klass);
+
+    account_ready_quark = g_quark_from_static_string ("mcd_account_load");
 }
 
 static void
@@ -2247,3 +2287,13 @@ mcd_account_get_avatar_filename (McdAccount *account)
     return filename;
 }
 
+void
+_mcd_account_load (McdAccount *account, McdAccountLoadCb callback,
+                   gpointer user_data)
+{
+    g_return_if_fail (MCD_IS_ACCOUNT (account));
+    g_return_if_fail (callback != NULL);
+
+    MCD_ACCOUNT_GET_CLASS (account)->load (account, callback, user_data);
+}
+
diff --git a/src/mcd-account.h b/src/mcd-account.h
index c84f75f..e703327 100644
--- a/src/mcd-account.h
+++ b/src/mcd-account.h
@@ -51,6 +51,10 @@ struct _McdAccount
     McdAccountPrivate *priv;
 };
 
+typedef void (*McdAccountLoadCb) (McdAccount *account,
+                                  const GError *error,
+                                  gpointer user_data);
+
 struct _McdAccountClass
 {
     GObjectClass parent_class;
@@ -59,7 +63,8 @@ struct _McdAccountClass
     void (*set_parameter) (McdAccount *account, const gchar *name,
                            const GValue *value);
     gboolean (*delete) (McdAccount *account, GError **error);
-    void (*_mc_reserved4) (void);
+    void (*load) (McdAccount *account, McdAccountLoadCb callback,
+                  gpointer user_data);
     void (*_mc_reserved5) (void);
     void (*_mc_reserved6) (void);
     void (*_mc_reserved7) (void);
@@ -153,4 +158,8 @@ gchar *mcd_account_get_avatar_filename (McdAccount *account);
 /* non-exported methods */
 void _mcd_account_tp_connection_changed (McdAccount *account);
 
+G_GNUC_INTERNAL
+void _mcd_account_load (McdAccount *account, McdAccountLoadCb callback,
+                        gpointer user_data);
+
 #endif
-- 
1.5.6.5




More information about the telepathy-commits mailing list