soc.2010.detachablepurple: 5cc9c52f: Added a system to generically handle req...
gillux at soc.pidgin.im
gillux at soc.pidgin.im
Sat Jul 31 01:35:54 EDT 2010
----------------------------------------------------------------------
Revision: 5cc9c52f256394c46b4439a1b2dae352ed8f98f2
Parent: 3a83836c05404a948c6ffa363b239fefd84f7fe6
Author: gillux at soc.pidgin.im
Date: 07/29/10 23:53:33
Branch: im.pidgin.soc.2010.detachablepurple
URL: http://d.pidgin.im/viewmtn/revision/info/5cc9c52f256394c46b4439a1b2dae352ed8f98f2
Changelog:
Added a system to generically handle requests the user have to answer. This
include registering a request from and in the daemon, and allowing any client
to answer it using the new RunRequest method. See the comments for more details.
Changes against parent 3a83836c05404a948c6ffa363b239fefd84f7fe6
patched libpurple/dbus-callback.c
patched libpurple/dbus-callback.h
patched libpurple/dbus-prototypes/callback.xml
-------------- next part --------------
============================================================
--- libpurple/dbus-callback.c fbcb214c638e3d5226ab87d72ef0d3aa944a39e4
+++ libpurple/dbus-callback.c 18e8fc3fbcc40556715e4b7ce9061fe5bd71629c
@@ -25,6 +25,8 @@
#include "core.h"
#include "dbus-callback.h"
#include "dbus-callback-server.h"
+#include "dbus-callback-client.h"
+#include "dbus-maybe.h"
#include "dbus-purple.h"
#include "dbus-server.h"
#include "debug.h"
@@ -32,9 +34,11 @@
/**
* PurpleDBusCallback, a singleteon class that aims to run handle application
- * provided callbacks, in detachable sessions context. On the client side,
- * when we want to remotely run a method that takes a callback as parameter,
- * the following happens:
+ * provided callbacks and requests the user have to answer, in detachable
+ * sessions context.
+ *
+ * On the client side, when we want to remotely run a method that takes a
+ * callback as parameter, the following happens:
* 1. Client side: the method is remotely called.
* 2. Daemon side: the method wrapper gets called, we generate a unique id for
* the callback. We locally run the wrapped method, giving a fake callback,
@@ -48,6 +52,12 @@
* 5. Client side: We receive the RunCallback signal, which invokes the
* run_callback_cb() sighandler. It gets the stored callback with the
* provided id, and run it with its parameters.
+ *
+ * This class can also handle requests the user have to answer. One can run
+ * the purple_callback_register_req() to register a request on the daemon,
+ * and a client can later answer this request using the RunRequest dbus
+ * method.
+ *
*/
G_DEFINE_TYPE(PurpleDBusCallback, purple_dbus_callback, PURPLE_TYPE_OBJECT)
@@ -108,6 +118,7 @@ purple_dbus_callback_finalize(GObject *s
klass = g_type_class_peek(PURPLE_TYPE_DBUS_CALLBACK);
klass->instance = NULL;
g_hash_table_destroy(PURPLE_DBUS_CALLBACK(self)->callbacks);
+ g_hash_table_destroy(PURPLE_DBUS_CALLBACK(self)->requests);
G_OBJECT_CLASS(purple_dbus_callback_parent_class)->finalize(self);
}
@@ -139,16 +150,19 @@ purple_dbus_callback_init(PurpleDBusCall
static void
purple_dbus_callback_init(PurpleDBusCallback *self)
{
- self->last_id = 0;
+ self->last_callback_id = 0;
self->callbacks = g_hash_table_new_full(g_int64_hash, g_int64_equal,
g_free, (GDestroyNotify)g_closure_unref);
+ self->last_request_id = 0;
+ self->requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify)g_ptr_array_unref);
}
guint64
purple_dbus_callback_new_id(void)
{
PurpleDBusCallback* handler = g_object_new(PURPLE_TYPE_DBUS_CALLBACK, NULL);
- return ++handler->last_id;
+ return ++handler->last_callback_id;
}
/**
@@ -252,3 +266,68 @@ purple_dbus_callback_register(guint64 id
purple_debug_info("dbus", "Registering pending callback %llu!\n", *new_id);
g_hash_table_insert(handler->callbacks, new_id, closure);
}
+
+guint
+purple_callback_register_req(guint n_closures, ...)
+{
+ PurpleDBusCallback* handler = g_object_new(PURPLE_TYPE_DBUS_CALLBACK, NULL);
+ va_list ap;
+ GPtrArray *closures;
+ int i;
+ void *key;
+
+ g_return_val_if_fail(handler != NULL, 0);
+ g_return_val_if_fail(handler->requests != NULL, 0);
+
+ /* Put the provided closures in a GPtrArray */
+ closures = g_ptr_array_sized_new(n_closures);
+ g_ptr_array_set_free_func(closures, (GDestroyNotify)g_closure_unref);
+ va_start(ap, n_closures);
+ for (i = 0; i < n_closures; i++)
+ g_ptr_array_add(closures, va_arg(ap, GClosure *));
+ va_end(ap);
+
+ /* Put the array in our hash table */
+ key = GINT_TO_POINTER(++handler->last_request_id);
+ g_hash_table_insert(handler->requests, key, closures);
+
+ return handler->last_request_id;
+}
+
+void
+purple_callback_run_request_RPC(guint request_id, guint choice)
+{
+ PurpleDBusCallback* handler = g_object_new(PURPLE_TYPE_DBUS_CALLBACK, NULL);
+ DBusGProxy* proxy;
+ GError *error = NULL;
+
+ proxy = purple_object_get_dbus_obj_proxy(PURPLE_OBJECT(handler));
+ if (!im_pidgin_purple_callback_run_request(proxy, request_id, choice,
+ &error))
+ PURPLE_RPC_FAILED(purple_account_run_request, error);
+}
+
+gboolean
+DBUS_purple_callback_run_request(PurpleDBusCallback *handler, guint request_id, guint choice, GError** error)
+{
+ GPtrArray *closures;
+ GClosure *closure;
+ void *key = GINT_TO_POINTER(request_id);
+
+ /* Get the pending request back */
+ closures = g_hash_table_lookup(handler->requests, key);
+ /* Not getting the request back is normal, it usually means another
+ * client already ran a RunRequest faster than the one who presently
+ * sent us this RunRequest. */
+ if (!closures)
+ return TRUE;
+ g_return_val_if_fail(choice < closures->len, FALSE);
+ closure = closures->pdata[choice];
+
+ /* Run it! */
+ g_closure_invoke(closure, NULL, 0, NULL, NULL);
+
+ /* Forget about this pending request, it has been handled */
+ g_hash_table_remove(handler->requests, key);
+ return TRUE;
+}
============================================================
--- libpurple/dbus-callback.h d3f3d8113fe3adc485c821ffc3aa3b9b9e9c138c
+++ libpurple/dbus-callback.h b592df26ea5e69c379a11ff63c34db0767b28363
@@ -38,7 +38,9 @@ typedef struct {
typedef struct {
PurpleObject parent;
GHashTable *callbacks; /* id -> GClosure map */
- guint64 last_id;
+ guint64 last_callback_id;
+ GHashTable *requests; /* id -> GPtrArray-of-GClosure map */
+ guint last_request_id;
} PurpleDBusCallback;
/* DBus transfered data formats */
@@ -66,4 +68,28 @@ void purple_dbus_callback__b(void *obj,
*/
void purple_dbus_callback__b(void *obj, gboolean arg1, guint64 *id);
+/**
+ * Register a pending request, with n_closures available choices.
+ * The request can be later answered by one of the choices available choices,
+ * using the dbus RunRequest method with the returned request id.
+ *
+ * @param n_closures The number of closures passed after this parameter
+ * @param ... n_closures GClosures, each representing a choice that can answer
+ * the request.
+ * @return A request id that identifies the created pending request. This id
+ * can be passed to the dbus RunRequest method, which can be called
+ * on the client side with purple_dbus_callback_run_request_RPC().
+ */
+guint purple_callback_register_req(guint n_closures, ...);
+
+/**
+ * Client side function that run the RunRequest dbus method on the daemon.
+ */
+void purple_callback_run_request_RPC(guint request_id, guint choice);
+
+/**
+ * Daemon side RunRequest dbus method implementation.
+ */
+gboolean DBUS_purple_callback_run_request(PurpleDBusCallback *handler, guint request_id, guint choice, GError** error);
+
#endif /* _DBUS_CALLBACK_H_ */
============================================================
--- libpurple/dbus-prototypes/callback.xml 862322ae1693f45a8f2d60423fbcb6a8bf6b302e
+++ libpurple/dbus-prototypes/callback.xml 9bce208dc8e2f6000c8ac291d34c32ea71eae2b6
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<node name="/im/pidgin/purple/callback">
<interface name="im.pidgin.purple.callback">
+ <method name="RunRequest">
+ <arg type="u" name="request_id" direction="in" />
+ <arg type="u" name="choice" direction="in" />
+ </method>
+
<signal name="RunCallback">
<arg type="t" name="callback_id" />
<arg type="av" name="args" />
More information about the Commits
mailing list