2009/10/25 Mikkel Kamstrup Erlandsen <mikkel.kamst...@gmail.com>: > 2009/10/15 David Zeuthen <da...@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);
_______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org http://mail.gnome.org/mailman/listinfo/gtk-devel-list