[telepathy-gabble/master] Generate and implement Connection.FUTURE.EnsureSidecar()
Will Thompson
will.thompson at collabora.co.uk
Mon Nov 16 04:47:27 PST 2009
---
extensions/Connection_Future.xml | 110 +++++++++++++
extensions/all.xml | 4 +
src/Makefile.am | 2 +
src/conn-sidecars.c | 316 ++++++++++++++++++++++++++++++++++++++
src/conn-sidecars.h | 35 ++++
src/connection.c | 6 +
src/connection.h | 7 +
7 files changed, 480 insertions(+), 0 deletions(-)
create mode 100644 extensions/Connection_Future.xml
create mode 100644 src/conn-sidecars.c
create mode 100644 src/conn-sidecars.h
diff --git a/extensions/Connection_Future.xml b/extensions/Connection_Future.xml
new file mode 100644
index 0000000..1104798
--- /dev/null
+++ b/extensions/Connection_Future.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" ?>
+<node name="/Connection_FUTURE"
+ xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+ >
+ <tp:copyright>Copyright © 2009 Collabora Limited</tp:copyright>
+ <tp:copyright>Copyright © 2009 Nokia Corporation</tp:copyright>
+ <tp:license xmlns="http://www.w3.org/1999/xhtml">
+<p>This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.</p>
+
+<p>This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.</p>
+
+<p>You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+USA.</p>
+ </tp:license>
+ <interface name="org.freedesktop.Telepathy.Connection.FUTURE"
+ tp:causes-havoc='experimental'>
+ <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
+
+ <method name="EnsureSidecar" tp:name-for-bindings="Ensure_Sidecar">
+ <tp:added version="0.19.UNRELEASED"/>
+
+ <arg direction="in" name="Main_Interface" type="s"
+ tp:type="DBus_Interface">
+ <tp:docstring>
+ The "primary" interface implemented by an object attached
+ to a connection. For example, a Gabble plugin implementing
+ fine-grained control of XEP-0016 privacy lists might expose an object
+ implementing <tt>com.example.PrivacyLists</tt>.
+ </tp:docstring>
+ </arg>
+
+ <arg direction="out" name="Path" type="o">
+ <tp:docstring>The object path of the sidecar, exported by the same bus
+ name as the Connection to which it is attached.</tp:docstring>
+ </arg>
+ <arg direction="out" name="Properties" type="a{sv}"
+ tp:type="Qualified_Property_Value_Map">
+ <tp:docstring>Immutable properties of the sidecar.</tp:docstring>
+ </arg>
+
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>Request an object with a particular interface providing additional
+ connection-specific functionality, together with its immutable
+ properties. These will often be implemented by plug-ins to the
+ connection managers; for example, support for an XMPP XEP for which
+ no generic Telepathy interface exists might be implemented by a
+ Gabble plugin exposing a sidecar with a particular interface.</p>
+
+ <p>This method may be called at any point during the lifetime of a
+ connection, even before its <tp:type>Connection_Status</tp:type>
+ changes to Connected. It MAY take a long time to
+ returnâperhaps it needs to wait for a connection to be established
+ and for all the services supported by the server to be discovered
+ before determining whether necessary server-side support is
+ availableâso callers SHOULD override the default method timeout (25
+ seconds) with a much higher value (perhaps even MAX_INT32, meaning
+ âno timeoutâ in recent versions of libdbus).</p>
+
+ <tp:rationale>
+ <p>There is an implicit assumption that any connection
+ manager plugin will only want to export one âprimaryâ object per
+ feature it implements, since there is a one-to-one mapping between
+ interface and object. This is reasonable since Sidecars are
+ (intended to be) analogous to extra interfaces on the connection,
+ providing once-per-connection shared functionality; it also makes
+ client code straightforward (look up the interface you care about
+ in a dictionary, build a proxy object from the value). More
+ âpluralâ plugins are likely to want to implement new types of
+ <tp:dbus-ref
+ namespace="org.freedesktop.Telepathy">Channel</tp:dbus-ref>
+ instead.</p>
+ </tp:rationale>
+ </tp:docstring>
+
+ <tp:error name="org.freedesktop.Telepathy.Error.NotImplemented">
+ <tp:docstring>
+ The requested sidecar is not implemented by this connection manager,
+ or a necessary server-side component does not exist. (FIXME: split
+ these two errors out? Then again, once we list the guaranteed and
+ possible sidecars on a Protocol object, clients can tell the
+ difference themselves, because they shouldn't be calling this in the
+ first case.)
+ </tp:docstring>
+ </tp:error>
+
+ <tp:error name="org.freedesktop.Telepathy.Error.ServiceBusy">
+ <tp:docstring>
+ A server-side component needed by the requested sidecar reported it
+ is currently too busy, or did not respond for some
+ implementation-defined time. The caller may wish to try again later.
+ </tp:docstring>
+ </tp:error>
+
+ <tp:error name="org.freedesktop.Telepathy.Error.Cancelled">
+ <tp:docstring>
+ The connection was disconnected while the sidecar was being set up.
+ </tp:docstring>
+ </tp:error>
+ </method>
+
+ </interface>
+</node>
diff --git a/extensions/all.xml b/extensions/all.xml
index a2055df..9f6c76b 100644
--- a/extensions/all.xml
+++ b/extensions/all.xml
@@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
<xi:include href="Channel_Type_Contact_Search.xml"/>
<xi:include href="Connection_Interface_Contact_Info.xml"/>
+<xi:include href="Connection_Future.xml"/>
<tp:generic-types>
<tp:external-type name="Contact_Handle" type="u"
@@ -94,6 +95,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA</p>
<tp:external-type name="Requestable_Channel_Class" type="(a{sv}as)"
from="Telepathy specification"/>
+ <tp:external-type name="Connection_Status" type="u"
+ from="Telepathy specification"/>
+
</tp:generic-types>
</tp:spec>
diff --git a/src/Makefile.am b/src/Makefile.am
index 4178c72..9034676 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -41,6 +41,8 @@ libgabble_convenience_la_SOURCES = \
conn-olpc.c \
conn-presence.h \
conn-presence.c \
+ conn-sidecars.h \
+ conn-sidecars.c \
connection.h \
connection.c \
connection-manager.h \
diff --git a/src/conn-sidecars.c b/src/conn-sidecars.c
new file mode 100644
index 0000000..e21766e
--- /dev/null
+++ b/src/conn-sidecars.c
@@ -0,0 +1,316 @@
+/*
+ * conn-sidecars.h - Gabble connection implementation of sidecars
+ * Copyright © 2009 Collabora Ltd.
+ * Copyright © 2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "conn-sidecars.h"
+
+#include <telepathy-glib/dbus.h>
+
+#include "extensions/extensions.h"
+
+#define DEBUG_FLAG GABBLE_DEBUG_CONNECTION
+#include "debug.h"
+#include "plugin-loader.h"
+#include "sidecar.h"
+
+static void
+sidecars_conn_status_changed_cb (
+ GabbleConnection *conn,
+ guint status,
+ guint reason,
+ gpointer unused);
+
+void
+conn_sidecars_init (GabbleConnection *conn)
+{
+ conn->sidecars = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+ conn->pending_sidecars = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_list_free);
+
+ g_signal_connect (conn, "status-changed",
+ (GCallback) sidecars_conn_status_changed_cb, NULL);
+}
+
+void
+conn_sidecars_dispose (GabbleConnection *conn)
+{
+ g_warn_if_fail (g_hash_table_size (conn->sidecars) == 0);
+ g_hash_table_unref (conn->sidecars);
+ conn->sidecars = NULL;
+
+ g_warn_if_fail (g_hash_table_size (conn->pending_sidecars) == 0);
+ g_hash_table_unref (conn->pending_sidecars);
+ conn->pending_sidecars = NULL;
+}
+
+static gchar *
+make_sidecar_path (
+ GabbleConnection *conn,
+ const gchar *sidecar_iface)
+{
+ TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn);
+
+ return g_strdelimit (
+ g_strdup_printf ("%s/Sidecar/%s", base_conn->object_path, sidecar_iface),
+ ".", '/');
+}
+
+/**
+ * connection_install_sidecar:
+ *
+ * Registers @sidecar on the bus, and returns its object path.
+ */
+static gchar *
+connection_install_sidecar (
+ GabbleConnection *conn,
+ GabbleSidecar *sidecar,
+ const gchar *sidecar_iface)
+{
+ gchar *path = make_sidecar_path (conn, sidecar_iface);
+
+ dbus_g_connection_register_g_object (tp_get_bus (), path, G_OBJECT (sidecar));
+ g_hash_table_insert (conn->sidecars, g_strdup (sidecar_iface),
+ g_object_ref (sidecar));
+
+ return path;
+}
+
+typedef struct {
+ GabbleConnection *conn;
+ gchar *sidecar_iface;
+} Grr;
+
+static Grr *
+grr_new (
+ GabbleConnection *conn,
+ const gchar *sidecar_iface)
+{
+ Grr *grr = g_slice_new (Grr);
+
+ grr->conn = g_object_ref (conn);
+ grr->sidecar_iface = g_strdup (sidecar_iface);
+
+ return grr;
+}
+
+static void
+grr_free (Grr *grr)
+{
+ g_object_unref (grr->conn);
+ g_free (grr->sidecar_iface);
+
+ g_slice_free (Grr, grr);
+}
+
+static void
+create_sidecar_cb (
+ GObject *loader_obj,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GabblePluginLoader *loader = GABBLE_PLUGIN_LOADER (loader_obj);
+ Grr *ctx = user_data;
+ GabbleConnection *conn = ctx->conn;
+ const gchar *sidecar_iface = ctx->sidecar_iface;
+ GabbleSidecar *sidecar;
+ GList *contexts;
+ GError *error = NULL;
+
+ sidecar = gabble_plugin_loader_create_sidecar_finish (loader, result, &error);
+ contexts = g_hash_table_lookup (conn->pending_sidecars, sidecar_iface);
+
+ if (contexts == NULL)
+ {
+ /* We never use the empty list as a value in pending_sidecars, so this
+ * must mean we've disconnected and already returned. Jettison the
+ * sidecar!
+ */
+ DEBUG ("creating sidecar %s %s after connection closed; jettisoning!",
+ sidecar_iface, (sidecar != NULL ? "succeeded" : "failed"));
+ goto out;
+ }
+
+ if (sidecar != NULL)
+ {
+ const gchar *actual_iface = gabble_sidecar_get_interface (sidecar);
+
+ if (tp_strdiff (ctx->sidecar_iface, actual_iface))
+ {
+ /* TODO: maybe this lives in the loader? It knows what the plugin is
+ * called. */
+ g_set_error (&error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+ "A buggy plugin created a %s sidecar when asked to create %s",
+ actual_iface, ctx->sidecar_iface);
+ }
+ }
+
+ if (error == NULL)
+ {
+ gchar *path = connection_install_sidecar (ctx->conn, sidecar,
+ ctx->sidecar_iface);
+ GHashTable *props = gabble_sidecar_get_immutable_properties (sidecar);
+ GList *l;
+
+ for (l = contexts; l != NULL; l = l->next)
+ gabble_svc_connection_future_return_from_ensure_sidecar (l->data,
+ path, props);
+
+ g_hash_table_unref (props);
+ }
+ else
+ {
+ g_list_foreach (contexts, (GFunc) dbus_g_method_return_error, error);
+ }
+
+ g_hash_table_remove (ctx->conn->pending_sidecars, ctx->sidecar_iface);
+
+out:
+ if (sidecar != NULL)
+ g_object_unref (sidecar);
+
+ g_clear_error (&error);
+ grr_free (ctx);
+}
+
+static void
+gabble_connection_ensure_sidecar (
+ GabbleSvcConnectionFUTURE *iface,
+ const gchar *sidecar_iface,
+ DBusGMethodInvocation *context)
+{
+ GabbleConnection *conn = GABBLE_CONNECTION (iface);
+ TpBaseConnection *base_conn = TP_BASE_CONNECTION (conn);
+ GabbleSidecar *sidecar;
+ gpointer key, value;
+ GabblePluginLoader *loader;
+ GError *error = NULL;
+
+ if (base_conn->status == TP_CONNECTION_STATUS_DISCONNECTED)
+ {
+ GError e = { TP_ERRORS, TP_ERROR_DISCONNECTED,
+ "This connection has already disconnected" };
+
+ DEBUG ("already disconnected, declining request for %s", sidecar_iface);
+ dbus_g_method_return_error (context, &e);
+ return;
+ }
+
+ if (!tp_dbus_check_valid_interface_name (sidecar_iface, &error))
+ {
+ error->domain = TP_ERRORS;
+ error->code = TP_ERROR_INVALID_ARGUMENT;
+ DEBUG ("%s is malformed: %s", sidecar_iface, error->message);
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
+ return;
+ }
+
+ sidecar = g_hash_table_lookup (conn->sidecars, sidecar_iface);
+
+ if (sidecar != NULL)
+ {
+ gchar *path = make_sidecar_path (conn, sidecar_iface);
+ GHashTable *props = gabble_sidecar_get_immutable_properties (sidecar);
+
+ DEBUG ("sidecar %s already exists at %s", sidecar_iface, path);
+ gabble_svc_connection_future_return_from_ensure_sidecar (context, path,
+ props);
+
+ g_free (path);
+ g_hash_table_unref (props);
+ return;
+ }
+
+ if (g_hash_table_lookup_extended (conn->pending_sidecars, sidecar_iface,
+ &key, &value))
+ {
+ GList *contexts = value;
+
+ DEBUG ("already awaiting %s, joining a queue of %u", sidecar_iface,
+ g_list_length (contexts));
+
+ contexts = g_list_prepend (contexts, context);
+ g_hash_table_steal (conn->pending_sidecars, key);
+ g_hash_table_insert (conn->pending_sidecars, key, contexts);
+ return;
+ }
+
+ DEBUG ("requesting %s from the plugin loader", sidecar_iface);
+ loader = gabble_plugin_loader_dup ();
+ g_hash_table_insert (conn->pending_sidecars, g_strdup (sidecar_iface),
+ g_list_prepend (NULL, context));
+ gabble_plugin_loader_create_sidecar (loader, sidecar_iface,
+ create_sidecar_cb, grr_new (conn, sidecar_iface));
+ g_object_unref (loader);
+}
+
+static void
+sidecars_conn_status_changed_cb (
+ GabbleConnection *conn,
+ guint status,
+ guint reason,
+ gpointer unused)
+{
+ DBusGConnection *bus = tp_get_bus ();
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (status != TP_CONNECTION_STATUS_DISCONNECTED)
+ return;
+
+ g_hash_table_iter_init (&iter, conn->sidecars);
+
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ DEBUG ("removing %s from the bus", gabble_sidecar_get_interface (value));
+ dbus_g_connection_unregister_g_object (bus, G_OBJECT (value));
+ }
+
+ g_hash_table_iter_init (&iter, conn->pending_sidecars);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ const gchar *sidecar_iface = key;
+ GList *contexts = value;
+
+ GError *error = g_error_new (TP_ERRORS, TP_ERROR_CANCELLED,
+ "Disconnected before %s could be created", sidecar_iface);
+
+ g_list_foreach (contexts, (GFunc) dbus_g_method_return_error, error);
+ g_error_free (error);
+ }
+
+ g_hash_table_remove_all (conn->sidecars);
+ g_hash_table_remove_all (conn->pending_sidecars);
+}
+
+void
+conn_future_iface_init (
+ gpointer g_iface,
+ gpointer iface_data)
+{
+ GabbleSvcConnectionFUTUREClass *klass = g_iface;
+
+#define IMPLEMENT(x) \
+ gabble_svc_connection_future_implement_##x (\
+ klass, gabble_connection_##x)
+ IMPLEMENT (ensure_sidecar);
+#undef IMPLEMENT
+}
diff --git a/src/conn-sidecars.h b/src/conn-sidecars.h
new file mode 100644
index 0000000..46e076c
--- /dev/null
+++ b/src/conn-sidecars.h
@@ -0,0 +1,35 @@
+/*
+ * conn-sidecars.h - Header for Gabble connection implementation of sidecars
+ * Copyright © 2009 Collabora Ltd.
+ * Copyright © 2009 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __CONN_SIDECARS_H__
+#define __CONN_SIDECARS_H__
+
+#include "connection.h"
+
+G_BEGIN_DECLS
+
+void conn_sidecars_init (GabbleConnection *conn);
+void conn_sidecars_dispose (GabbleConnection *conn);
+void conn_future_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_END_DECLS
+
+#endif /* __CONN_SIDECARS_H__ */
+
diff --git a/src/connection.c b/src/connection.c
index 9dba372..d301d3d 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -55,6 +55,7 @@
#include "conn-avatars.h"
#include "conn-location.h"
#include "conn-presence.h"
+#include "conn-sidecars.h"
#include "conn-olpc.h"
#include "debug.h"
#include "disco.h"
@@ -118,6 +119,8 @@ G_DEFINE_TYPE_WITH_CODE(GabbleConnection,
gabble_conn_contact_caps_iface_init);
G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_OLPC_GADGET,
olpc_gadget_iface_init);
+ G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_CONNECTION_FUTURE,
+ conn_future_iface_init);
)
/* properties */
@@ -329,6 +332,7 @@ gabble_connection_constructor (GType type,
conn_presence_init (self);
conn_olpc_activity_properties_init (self);
conn_location_init (self);
+ conn_sidecars_init (self);
tp_contacts_mixin_add_contact_attributes_iface (G_OBJECT (self),
TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES,
@@ -1043,6 +1047,8 @@ gabble_connection_dispose (GObject *object)
self->pep_olpc_act_props = NULL;
}
+ conn_sidecars_dispose (self);
+
if (G_OBJECT_CLASS (gabble_connection_parent_class)->dispose)
G_OBJECT_CLASS (gabble_connection_parent_class)->dispose (object);
}
diff --git a/src/connection.h b/src/connection.h
index 73006d4..e15c25d 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -200,6 +200,13 @@ struct _GabbleConnection {
WockyPepService *pep_olpc_current_act;
WockyPepService *pep_olpc_act_props;
+ /* Sidecars */
+ /* gchar *interface â GabbleSidecar */
+ GHashTable *sidecars;
+
+ /* gchar *interface â GList<DBusGMethodInvocation> */
+ GHashTable *pending_sidecars;
+
GabbleConnectionPrivate *priv;
};
--
1.5.6.5
More information about the telepathy-commits
mailing list