[Telepathy-commits] [telepathy-mission-control/master] Implement channel requests in a better way
Alberto Mardegan
alberto.mardegan at nokia.com
Thu Jan 29 03:17:41 PST 2009
Don't use the pointer to the request structure as a unique id; instead, keep
the mapping in a hash table.
Introduce mc_channelrequest_get_path() and mc_channelrequest_get_from_path(),
which don't require an account.
---
libmcclient/mc-account-priv.h | 4 -
libmcclient/mc-account-request.c | 188 ++++++++++++++++++++------------------
libmcclient/mc-account.c | 3 -
libmcclient/mc-account.h | 2 +
4 files changed, 102 insertions(+), 95 deletions(-)
diff --git a/libmcclient/mc-account-priv.h b/libmcclient/mc-account-priv.h
index 2437b91..e37d5ff 100644
--- a/libmcclient/mc-account-priv.h
+++ b/libmcclient/mc-account-priv.h
@@ -45,7 +45,6 @@ extern guint _mc_account_signals[LAST_SIGNAL];
typedef struct _McAccountProps McAccountProps;
typedef struct _McAccountAvatarProps McAccountAvatarProps;
-typedef struct _McAccountChannelrequestsProps McAccountChannelrequestsProps;
typedef struct _McAccountCompatProps McAccountCompatProps;
typedef struct _McAccountConditionsProps McAccountConditionsProps;
typedef struct _McAccountStatsProps McAccountStatsProps;
@@ -53,7 +52,6 @@ typedef struct _McAccountStatsProps McAccountStatsProps;
struct _McAccountPrivate {
McAccountProps *props;
McAccountAvatarProps *avatar_props;
- McAccountChannelrequestsProps *request_props;
McAccountCompatProps *compat_props;
McAccountConditionsProps *conditions_props;
McAccountStatsProps *stats_props;
@@ -75,8 +73,6 @@ struct _McAccountClass {
void _mc_account_avatar_props_free (McAccountAvatarProps *props);
void _mc_account_avatar_class_init (McAccountClass *klass);
-void _mc_account_channelrequests_props_free
- (McAccountChannelrequestsProps *props);
void _mc_account_channelrequests_class_init (McAccountClass *klass);
void _mc_account_compat_props_free (McAccountCompatProps *props);
diff --git a/libmcclient/mc-account-request.c b/libmcclient/mc-account-request.c
index 432cf2b..9d39cd4 100644
--- a/libmcclient/mc-account-request.c
+++ b/libmcclient/mc-account-request.c
@@ -31,12 +31,9 @@
#include <telepathy-glib/interfaces.h>
-struct _McAccountChannelrequestsProps {
- GList *requests;
-};
-
typedef struct
{
+ guint id;
McAccount *account;
gchar *request_path;
GError *error;
@@ -49,33 +46,31 @@ typedef struct
GObject *weak_object;
} McChannelRequest;
+static GHashTable *requests = NULL;
+static guint last_request_id = 0;
-static void mc_request_free (McChannelRequest *req);
+#define REQUEST_FROM_ID(id) request_from_id(id)
+#define REQUEST_ID(req) (req->id)
-static void
-on_weak_object_destroy (McAccount *account, GObject *weak_object)
+static inline McChannelRequest *
+request_from_id (guint id)
{
- McAccountChannelrequestsProps *props;
- GList *list;
+ if (G_UNLIKELY (!requests)) return NULL;
- g_return_if_fail (MC_IS_ACCOUNT (account));
+ return g_hash_table_lookup (requests, GUINT_TO_POINTER (id));
+}
- props = account->priv->request_props;
- g_return_if_fail (props != NULL);
+static void
+on_weak_object_destroy (guint id, GObject *weak_object)
+{
+ McChannelRequest *req;
- /* look for this request */
- for (list = props->requests; list != NULL; list = list->next)
- {
- McChannelRequest *req = list->data;
+ req = REQUEST_FROM_ID (id);
+ if (G_UNLIKELY (!req)) return;
- if (req->weak_object == weak_object)
- {
- props->requests = g_list_delete_link (props->requests, list);
- req->weak_object = NULL;
- mc_request_free (req);
- break;
- }
- }
+ g_return_if_fail (req->weak_object != weak_object);
+ req->weak_object = NULL;
+ g_hash_table_remove (requests, GUINT_TO_POINTER (id));
}
static void
@@ -84,7 +79,7 @@ mc_request_free (McChannelRequest *req)
if (req->weak_object)
g_object_weak_unref (req->weak_object,
(GWeakNotify)on_weak_object_destroy,
- req->account);
+ GUINT_TO_POINTER (req->id));
if (req->destroy)
req->destroy (req->user_data);
g_free (req->request_path);
@@ -96,31 +91,15 @@ mc_request_free (McChannelRequest *req)
static void
emit_request_event (McChannelRequest *req, McAccountChannelrequestEvent event)
{
- McAccountChannelrequestsProps *props;
-
- props = req->account->priv->request_props;
-
if (req->callback)
- req->callback (req->account, GPOINTER_TO_UINT (req), event,
+ req->callback (req->account, REQUEST_ID (req), event,
req->user_data, req->weak_object);
if (event == MC_ACCOUNT_CR_SUCCEEDED ||
event == MC_ACCOUNT_CR_FAILED ||
event == MC_ACCOUNT_CR_CANCELLED)
{
- GList *list;
-
- /* we must delete the request, but being careful that this might have
- * been already done by the client, by destroying the weak_object */
- for (list = props->requests; list != NULL; list = list->next)
- {
- if (req == list->data)
- {
- props->requests = g_list_delete_link (props->requests, list);
- mc_request_free (req);
- break;
- }
- }
+ g_hash_table_remove (requests, GUINT_TO_POINTER (REQUEST_ID (req)));
}
}
@@ -158,13 +137,16 @@ on_request_failed (TpProxy *proxy, const gchar *request_path,
gpointer user_data, GObject *weak_object)
{
McChannelRequest *req;
+ guint id;
g_debug ("%s called for %s", G_STRFUNC, request_path);
- req = GUINT_TO_POINTER (mc_account_channelrequest_get_from_path
- (MC_ACCOUNT (proxy), request_path));
- if (!req) /* not our request, ignore it */
+ id = mc_channelrequest_get_from_path (request_path);
+ if (id == 0) /* not our request, ignore it */
return;
+ req = REQUEST_FROM_ID (id);
+ if (G_UNLIKELY (!req)) return;
+
/* FIXME: map the error properly */
req->error = g_error_new (MC_ERROR, MC_CHANNEL_REQUEST_GENERIC_ERROR,
error_message);
@@ -176,26 +158,17 @@ on_request_succeeded (TpProxy *proxy, const gchar *request_path,
gpointer user_data, GObject *weak_object)
{
McChannelRequest *req;
+ guint id;
g_debug ("%s called for %s", G_STRFUNC, request_path);
- req = GUINT_TO_POINTER (mc_account_channelrequest_get_from_path
- (MC_ACCOUNT (proxy), request_path));
- if (!req) /* not our request, ignore it */
+ id = mc_channelrequest_get_from_path (request_path);
+ if (id == 0) /* not our request, ignore it */
return;
- emit_request_event (req, MC_ACCOUNT_CR_SUCCEEDED);
-}
+ req = REQUEST_FROM_ID (id);
+ if (G_UNLIKELY (!req)) return;
-void
-_mc_account_channelrequests_props_free (McAccountChannelrequestsProps *props)
-{
- GList *list;
-
- for (list = props->requests; list != NULL; list = list->next)
- mc_request_free (list->data);
-
- g_list_free (props->requests);
- g_slice_free (McAccountChannelrequestsProps, props);
+ emit_request_event (req, MC_ACCOUNT_CR_SUCCEEDED);
}
static McChannelRequest *
@@ -204,14 +177,12 @@ create_request_struct (McAccount *account,
gpointer user_data, GDestroyNotify destroy,
GObject *weak_object)
{
- McAccountChannelrequestsProps *props;
McChannelRequest *req;
- props = account->priv->request_props;
- if (props == NULL)
+ if (!requests)
{
- account->priv->request_props = props =
- g_slice_new0 (McAccountChannelrequestsProps);
+ requests = g_hash_table_new_full (NULL, NULL, NULL,
+ (GDestroyNotify)mc_request_free);
mc_cli_account_interface_channelrequests_connect_to_failed (account,
on_request_failed, NULL, NULL, NULL, NULL);
@@ -220,6 +191,7 @@ create_request_struct (McAccount *account,
}
req = g_slice_new0 (McChannelRequest);
+ req->id = ++last_request_id;
req->account = account;
req->callback = callback;
req->user_data = user_data;
@@ -228,10 +200,12 @@ create_request_struct (McAccount *account,
{
req->weak_object = weak_object;
g_object_weak_ref (weak_object,
- (GWeakNotify)on_weak_object_destroy, account);
+ (GWeakNotify)on_weak_object_destroy,
+ GUINT_TO_POINTER (req->id));
}
- props->requests = g_list_prepend (props->requests, req);
+ g_hash_table_insert (requests, GUINT_TO_POINTER (req->id), req);
+
return req;
}
@@ -417,7 +391,7 @@ mc_account_channelrequest_ht (McAccount *account,
(account, -1, properties, user_action_time, handler,
request_create_cb, req, NULL, NULL);
- return GPOINTER_TO_UINT (req);
+ return REQUEST_ID (req);
}
/**
@@ -454,7 +428,7 @@ mc_account_channelrequest_add (McAccount *account, const gchar *object_path,
id = mc_account_channelrequest_get_from_path (account, object_path);
if (id != 0)
{
- req = GUINT_TO_POINTER (id);
+ req = REQUEST_FROM_ID (id);
/* either we properly invoke this callback too, or we must return an
* error to inform that it will not be called */
if (callback != NULL &&
@@ -473,7 +447,7 @@ mc_account_channelrequest_add (McAccount *account, const gchar *object_path,
req->request_path = g_strdup (object_path);
/* at the moment there isn't even a method for retrieving the properties,
* so let's ignore them */
- return GPOINTER_TO_UINT (req);
+ return REQUEST_ID (req);
}
/**
@@ -490,7 +464,12 @@ mc_account_channelrequest_cancel (McAccount *account, guint request_id)
g_return_if_fail (MC_IS_ACCOUNT (account));
g_return_if_fail (request_id != 0);
- req = GUINT_TO_POINTER (request_id);
+ req = REQUEST_FROM_ID (request_id);
+ if (G_UNLIKELY (!req))
+ {
+ g_warning ("%s: invalid request ID: %u", G_STRFUNC, request_id);
+ return;
+ }
if (req->request_path)
{
@@ -522,7 +501,12 @@ mc_account_channelrequest_get_error (McAccount *account, guint request_id)
g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
g_return_val_if_fail (request_id != 0, NULL);
- req = GUINT_TO_POINTER (request_id);
+ req = REQUEST_FROM_ID (request_id);
+ if (G_UNLIKELY (!req))
+ {
+ g_warning ("%s: invalid request ID: %u", G_STRFUNC, request_id);
+ return NULL;
+ }
return req->error;
}
@@ -541,12 +525,7 @@ mc_account_channelrequest_get_error (McAccount *account, guint request_id)
const gchar *
mc_account_channelrequest_get_path (McAccount *account, guint request_id)
{
- McChannelRequest *req;
-
- g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
- g_return_val_if_fail (request_id != 0, NULL);
- req = GUINT_TO_POINTER (request_id);
- return req->request_path;
+ return mc_channelrequest_get_path (request_id);
}
/**
@@ -563,20 +542,53 @@ guint
mc_account_channelrequest_get_from_path (McAccount *account,
const gchar *object_path)
{
- McAccountChannelrequestsProps *props;
- GList *list;
+ return mc_channelrequest_get_from_path (object_path);
+}
+
+/**
+ * mc_channelrequest_get_path:
+ * @request_id: the ID of the channel request.
+ *
+ * Get the object path of the channel request identified by @request_id.
+ * The channel request D-Bus object is currently not implemented, but this
+ * object path can be used consistently with the
+ * org.freedesktop.Telepathy.Client.Handler interface.
+ *
+ * Returns: the object path of the channel request.
+ */
+const gchar *
+mc_channelrequest_get_path (guint request_id)
+{
+ McChannelRequest *req;
+
+ g_return_val_if_fail (request_id != 0, NULL);
+ req = REQUEST_FROM_ID (request_id);
+ return req ? req->request_path : NULL;
+}
+
+/**
+ * mc_channelrequest_get_from_path:
+ * @object_path: the D-Bus object path of a channel request.
+ *
+ * Finds the request ID whose D-Bus object path matches @object_path.
+ * This only works if the request was created by this process.
+ *
+ * Returns: the unique ID of the channel request, or %0.
+ */
+guint
+mc_channelrequest_get_from_path (const gchar *object_path)
+{
+ McChannelRequest *req;
+ GHashTableIter iter;
- g_return_val_if_fail (MC_IS_ACCOUNT (account), 0);
g_return_val_if_fail (object_path != NULL, 0);
- props = account->priv->request_props;
- if (!props) return 0;
+ if (G_UNLIKELY (!requests)) return 0;
- for (list = props->requests; list != NULL; list = list->next)
+ g_hash_table_iter_init (&iter, requests);
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer)&req))
{
- McChannelRequest *req = list->data;
-
if (req->request_path && strcmp (req->request_path, object_path) == 0)
- return GPOINTER_TO_UINT (req);
+ return REQUEST_ID (req);
}
return 0;
}
diff --git a/libmcclient/mc-account.c b/libmcclient/mc-account.c
index 4f911ca..80c2222 100644
--- a/libmcclient/mc-account.c
+++ b/libmcclient/mc-account.c
@@ -208,9 +208,6 @@ finalize (GObject *object)
if (account->priv->avatar_props)
_mc_account_avatar_props_free (account->priv->avatar_props);
- if (account->priv->request_props)
- _mc_account_channelrequests_props_free (account->priv->request_props);
-
if (account->priv->compat_props)
_mc_account_compat_props_free (account->priv->compat_props);
diff --git a/libmcclient/mc-account.h b/libmcclient/mc-account.h
index 713b5be..f82989c 100644
--- a/libmcclient/mc-account.h
+++ b/libmcclient/mc-account.h
@@ -294,6 +294,8 @@ const gchar *mc_account_channelrequest_get_path (McAccount *account,
guint request_id);
guint mc_account_channelrequest_get_from_path (McAccount *account,
const gchar *object_path);
+const gchar *mc_channelrequest_get_path (guint request_id);
+guint mc_channelrequest_get_from_path (const gchar *object_path);
/* Account statistics */
--
1.5.6.5
More information about the telepathy-commits
mailing list