Re: GDBus API Questions; was: GDBus/GVariant plans for next GLib release



2009/10/25 Mikkel Kamstrup Erlandsen <mikkel kamstrup gmail com>:
> 2009/10/15 David Zeuthen <david fubar dk>:
>> Hey Mikkel,
>>
>> On Thu, 2009-10-15 at 08:24 +0200, Mikkel Kamstrup Erlandsen wrote:
>>>  * Can I register a GDBusInterfaceVTable without registering an
>>> object? The use case I have in mind is something akin to dynamically
>>> spawning objects on the server side when messages are send to objects
>>> under a given path[1]. Fx. when messages are send to
>>> /org/example/item/* I create the item matching * dynamically. Ideally
>>> one would register the vtable for objects matching a regexp. This
>>> would facilitate RESTful message passing on the bus.
>>
>> Yeah, there's a TODO in gdbusconnection.h to say we need something like
>> that - it would be similar dbus_connection_register_fallback() [1]. We
>> probably want a separate GDBusHierarchyVTable with functions to a) list
>> objects in the "directory"; and b) get introspection data for objects in
>> the "directory".
>
> I just looked over the newly introduced
> g_dbus_connection_register_subtree() and related data structures, and
> I think it will fit very nicely with what I am going to need. All in
> all it looks really sweet, good work.
>
> One thing though is that as I read it objects in a subtree must be
> known before method calls are accepted to them? For my use case in
> Zeitgeist I was hoping that I could completely get rid of a "Manager"
> type of interface, and just implicitly create objects in the tree
> whenever calls where made to them. This does not look possible as it
> stands?
>
> Maybe allowing '*' as a wildcard node name in the subtree enumeration function?

I had a stab at this myself. The wildcard idea seemed like a bad one,
so I instead added another gboolean param to
g_dbus_connection_register_subtree(), @is_dynamic.

If is_dynamic is TRUE then objects need not be in the enumerated list
of objects in order to be introspected and dispatched. Pretty simple.

No matter the simplicity I still managed to screw up one of the unit
tests. I will fix it and add some specific tests for the dynamic case
if you give the "go" for this David.

-- 
Cheers,
Mikkel

PS: And thanks for nice readable and commented code David!
diff --git a/gdbus/example-subtree.c b/gdbus/example-subtree.c
index 041a8f4..f870589 100644
--- a/gdbus/example-subtree.c
+++ b/gdbus/example-subtree.c
@@ -332,6 +332,7 @@ on_name_acquired (GDBusConnection *connection,
   registration_id = g_dbus_connection_register_subtree (connection,
                                                        "/org/gtk/GDBus/TestSubtree/Devices",
                                                         &subtree_vtable,
+                                                        FALSE, /* is_dynamic */
                                                         NULL,  /* user_data */
                                                         NULL,  /* user_data_free_func */
                                                         NULL); /* GError** */
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
index aa21213..d9099c0 100644
--- a/gdbus/gdbusconnection.c
+++ b/gdbus/gdbusconnection.c
@@ -3620,6 +3620,7 @@ struct ExportedSubtree
   gchar                    *object_path;
   GDBusConnection          *connection;
   const GDBusSubtreeVTable *vtable;
+  gboolean                  is_dynamic;
 
   GMainContext             *context;
   gpointer                  user_data;
@@ -3685,6 +3686,8 @@ handle_subtree_introspect (DBusConnection  *connection,
 
   //g_debug ("in handle_subtree_introspect for %s", requested_object_path);
 
+  /* Strictly we don't need the children in dynamic mode, but we avoid the
+   * conditionals to preserve code clarity */
   children = es->vtable->enumerate (es->connection,
                                     es->user_data,
                                     sender,
@@ -3693,8 +3696,9 @@ handle_subtree_introspect (DBusConnection  *connection,
   if (!is_root)
     {
       requested_node = strrchr (requested_object_path, '/') + 1;
-      /* skip if requested node is not part of children */
-      if (!_g_strv_has_string ((const gchar * const *) children, requested_node))
+
+      /* Assert existence of object if we are not dynamic */
+      if (!es->is_dynamic && !_g_strv_has_string ((const gchar * const *) children, requested_node))
         goto out;
     }
   else
@@ -3825,8 +3829,9 @@ handle_subtree_method_invocation (DBusConnection *connection,
   if (!is_root)
     {
       requested_node = strrchr (requested_object_path, '/') + 1;
-      /* skip if requested node is not part of children */
-      if (!_g_strv_has_string ((const gchar * const *) children, requested_node))
+
+      /* If not dynamic, skip if requested node is not part of children */
+      if (!es->is_dynamic && !_g_strv_has_string ((const gchar * const *) children, requested_node))
         goto out;
     }
   else
@@ -4048,6 +4053,9 @@ static const DBusObjectPathVTable dbus_1_subtree_vtable =
  * @connection: A #GDBusConnection.
  * @object_path: The object path to register the subtree at.
  * @vtable: A #GDBusSubtreeVTable to enumerate, introspect and dispatch nodes in the subtree.
+ * @is_dynamic: If %TRUE method calls to objects not in the enumerated range
+ *              will still be dispatched. This is useful if you want to
+ *              dynamically spawn objects in the subtree.
  * @user_data: Data to pass to functions in @vtable.
  * @user_data_free_func: Function to call when the subtree is unregistered.
  * @error: Return location for error or %NULL.
@@ -4059,8 +4067,9 @@ static const DBusObjectPathVTable dbus_1_subtree_vtable =
  * by @object_path.
  *
  * When handling remote calls into any node in the subtree, first the
- * @enumerate and @introspection function is used to check if the node
- * exists and whether it supports the requested method. If so, the
+ * @enumerate function is used to check if the node exists. If the node exists
+ * or @is_dynamic is set to %TRUE the @introspection function is used to
+ * check if the node supports the requested method. If so, the
  * @dispatch function is used to determine where to dispatch the
  * call. The collected #GDBusInterfaceVTable and #gpointer will be
  * used to call into the interface vtable for processing the request.
@@ -4087,6 +4096,7 @@ guint
 g_dbus_connection_register_subtree (GDBusConnection            *connection,
                                     const gchar                *object_path,
                                     const GDBusSubtreeVTable   *vtable,
+                                    gboolean                    is_dynamic,
                                     gpointer                    user_data,
                                     GDestroyNotify              user_data_free_func,
                                     GError                    **error)
@@ -4099,6 +4109,7 @@ g_dbus_connection_register_subtree (GDBusConnection            *connection,
   g_return_val_if_fail (!g_dbus_connection_get_is_disconnected (connection), 0);
   g_return_val_if_fail (object_path != NULL, 0);
   g_return_val_if_fail (vtable != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
   ret = 0;
 
@@ -4146,6 +4157,7 @@ g_dbus_connection_register_subtree (GDBusConnection            *connection,
     }
 
   es->vtable = vtable;
+  es->is_dynamic = is_dynamic;
   es->id = _global_subtree_registration_id++; /* TODO: overflow etc. */
   es->user_data = user_data;
   es->user_data_free_func = user_data_free_func;
diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h
index da07e14..cd49a07 100644
--- a/gdbus/gdbusconnection.h
+++ b/gdbus/gdbusconnection.h
@@ -318,6 +318,7 @@ struct _GDBusSubtreeVTable
 guint            g_dbus_connection_register_subtree           (GDBusConnection            *connection,
                                                                const gchar                *object_path,
                                                                const GDBusSubtreeVTable   *vtable,
+                                                               gboolean                    is_dynamic,
                                                                gpointer                    user_data,
                                                                GDestroyNotify              user_data_free_func,
                                                                GError                    **error);
diff --git a/gdbus/tests/export.c b/gdbus/tests/export.c
index 5a678e1..f868d54 100644
--- a/gdbus/tests/export.c
+++ b/gdbus/tests/export.c
@@ -649,6 +649,7 @@ test_object_registration (void)
   subtree_registration_id = g_dbus_connection_register_subtree (c,
                                                                 "/foo/boss/executives",
                                                                 &subtree_vtable,
+                                                                FALSE,
                                                                 &data,
                                                                 on_subtree_unregistered,
                                                                 &error);
@@ -658,6 +659,7 @@ test_object_registration (void)
   registration_id = g_dbus_connection_register_subtree (c,
                                                         "/foo/boss/executives",
                                                         &subtree_vtable,
+                                                        FALSE,
                                                         &data,
                                                         on_subtree_unregistered,
                                                         &error);
@@ -674,6 +676,7 @@ test_object_registration (void)
   subtree_registration_id = g_dbus_connection_register_subtree (c,
                                                                 "/foo/boss/executives",
                                                                 &subtree_vtable,
+                                                                FALSE,
                                                                 &data,
                                                                 on_subtree_unregistered,
                                                                 &error);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]