[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