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