From f7d02c8d7729819cf2e66a6b1ec7a06ddb9acb9c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 20 Jul 2016 17:55:02 +0200 Subject: [PATCH] client: add client object instrospection --- pinos/client/context.c | 9 +++ pinos/client/introspect.c | 108 ++++++++++++++++++++++++++++++++++++ pinos/client/introspect.h | 56 +++++++++++++++++++ pinos/client/private.h | 1 + pinos/client/subscribe.c | 3 + pinos/client/subscribe.h | 9 +-- pinos/tools/pinos-monitor.c | 50 +++++++++++++++++ 7 files changed, 232 insertions(+), 4 deletions(-) diff --git a/pinos/client/context.c b/pinos/client/context.c index b33f6e46f..b3dd73058 100644 --- a/pinos/client/context.c +++ b/pinos/client/context.c @@ -149,6 +149,8 @@ pinos_context_finalize (GObject * object) g_list_free (priv->nodes); g_list_free (priv->ports); + g_list_free (priv->clients); + g_list_free (priv->channels); g_clear_object (&priv->subscribe); g_clear_error (&priv->error); @@ -401,6 +403,13 @@ subscription_cb (PinosSubscribe *subscribe, priv->daemon = g_object_ref (object); break; + case PINOS_SUBSCRIPTION_FLAG_CLIENT: + if (event == PINOS_SUBSCRIPTION_EVENT_NEW) + priv->clients = g_list_prepend (priv->clients, object); + else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) + priv->clients = g_list_remove (priv->clients, object); + break; + case PINOS_SUBSCRIPTION_FLAG_NODE: if (event == PINOS_SUBSCRIPTION_EVENT_NEW) priv->nodes = g_list_prepend (priv->nodes, object); diff --git a/pinos/client/introspect.c b/pinos/client/introspect.c index e6ca096cb..dbf2b952e 100644 --- a/pinos/client/introspect.c +++ b/pinos/client/introspect.c @@ -178,6 +178,114 @@ pinos_context_get_daemon_info (PinosContext *context, g_object_unref (task); } +static void +client_fill_info (PinosClientInfo *info, GDBusProxy *proxy) +{ + GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); + + info->id = proxy; + info->client_path = g_dbus_proxy_get_object_path (proxy); + SET_STRING ("Sender", sender, 0); + + info->change_mask = 0; + SET_PROPERTIES ("Properties", properties, 0); + + if (changed) + g_hash_table_remove_all (changed); +} + +static void +client_clear_info (PinosClientInfo *info) +{ + if (info->properties) + pinos_properties_free (info->properties); +} + + +/** + * pinos_context_list_client_info: + * @context: a connected #PinosContext + * @flags: extra #PinosClientInfoFlags + * @cb: a #PinosClientInfoCallback + * @cancelable: a #GCancellable + * @callback: a #GAsyncReadyCallback to call when the operation is finished + * @user_data: user data passed to @cb + * + * Call @cb for each client. + */ +void +pinos_context_list_client_info (PinosContext *context, + PinosClientInfoFlags flags, + PinosClientInfoCallback cb, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PinosContextPrivate *priv; + GList *walk; + GTask *task; + + g_return_if_fail (PINOS_IS_CONTEXT (context)); + g_return_if_fail (cb != NULL); + + task = g_task_new (context, cancellable, callback, user_data); + + priv = context->priv; + + for (walk = priv->clients; walk; walk = g_list_next (walk)) { + GDBusProxy *proxy = walk->data; + PinosClientInfo info; + + client_fill_info (&info, proxy); + cb (context, &info, user_data); + client_clear_info (&info); + } + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +/** + * pinos_context_get_client_info_by_id: + * @context: a connected #PinosContext + * @id: a client id + * @flags: extra #PinosClientInfoFlags + * @cb: a #PinosClientInfoCallback + * @cancelable: a #GCancellable + * @callback: a #GAsyncReadyCallback to call when the operation is finished + * @user_data: user data passed to @cb + * + * Call @cb for the client with @id. + */ +void +pinos_context_get_client_info_by_id (PinosContext *context, + gpointer id, + PinosClientInfoFlags flags, + PinosClientInfoCallback cb, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + PinosClientInfo info; + GDBusProxy *proxy; + GTask *task; + + g_return_if_fail (PINOS_IS_CONTEXT (context)); + g_return_if_fail (id != NULL); + g_return_if_fail (cb != NULL); + + task = g_task_new (context, cancellable, callback, user_data); + + proxy = G_DBUS_PROXY (id); + + client_fill_info (&info, proxy); + cb (context, &info, user_data); + client_clear_info (&info); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + /** * pinos_node_state_as_string: * @state: a #PinosNodeeState diff --git a/pinos/client/introspect.h b/pinos/client/introspect.h index c2aea5742..42fad9863 100644 --- a/pinos/client/introspect.h +++ b/pinos/client/introspect.h @@ -144,6 +144,62 @@ void pinos_context_get_daemon_info (PinosContext *context, GAsyncReadyCallback callback, gpointer user_data); +/** + * PinosClientInfo: + * @id: generic id of the client + * @client_path: unique path of the client + * @sender: sender of client + * @change_mask: bitfield of changed fields since last call + * @properties: extra properties + * + * The client information. Extra information can be added in later + * versions. + */ +typedef struct { + gpointer id; + const char *client_path; + const char *sender; + guint64 change_mask; + PinosProperties *properties; +} PinosClientInfo; + +/** + * PinosClientInfoFlags: + * @PINOS_CLIENT_INFO_FLAGS_NONE: no flags + * + * Extra flags for pinos_context_list_client_info() and + * pinos_context_get_client_info_by_id(). + */ +typedef enum { + PINOS_CLIENT_INFO_FLAGS_NONE = 0, +} PinosClientInfoFlags; + +/** + * PinosClientInfoCallback: + * @c: a #PinosContext + * @info: a #PinosClientInfo + * @user_data: user data + * + * Callback with information about the Pinos client in @info. + */ +typedef void (*PinosClientInfoCallback) (PinosContext *c, + const PinosClientInfo *info, + gpointer user_data); + +void pinos_context_list_client_info (PinosContext *context, + PinosClientInfoFlags flags, + PinosClientInfoCallback cb, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +void pinos_context_get_client_info_by_id (PinosContext *context, + gpointer id, + PinosClientInfoFlags flags, + PinosClientInfoCallback cb, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + /** * PinosNodeInfo: * @id: generic id of the node diff --git a/pinos/client/private.h b/pinos/client/private.h index 7332b37dd..08f4085de 100644 --- a/pinos/client/private.h +++ b/pinos/client/private.h @@ -38,6 +38,7 @@ struct _PinosContextPrivate PinosSubscriptionFlags subscription_mask; PinosSubscribe *subscribe; + GList *clients; GList *nodes; GList *ports; GList *connections; diff --git a/pinos/client/subscribe.c b/pinos/client/subscribe.c index 2f7237f45..87dd69e96 100644 --- a/pinos/client/subscribe.c +++ b/pinos/client/subscribe.c @@ -102,6 +102,9 @@ notify_event (PinosSubscribe *subscribe, if (g_strcmp0 (interface_name, "org.pinos.Daemon1") == 0) { flags = PINOS_SUBSCRIPTION_FLAG_DAEMON; } + if (g_strcmp0 (interface_name, "org.pinos.Client1") == 0) { + flags = PINOS_SUBSCRIPTION_FLAG_CLIENT; + } else if (g_strcmp0 (interface_name, "org.pinos.Node1") == 0) { flags = PINOS_SUBSCRIPTION_FLAG_NODE; } diff --git a/pinos/client/subscribe.h b/pinos/client/subscribe.h index 820385969..74c8ffbef 100644 --- a/pinos/client/subscribe.h +++ b/pinos/client/subscribe.h @@ -46,12 +46,13 @@ typedef enum { typedef enum { PINOS_SUBSCRIPTION_FLAG_DAEMON = (1 << 0), - PINOS_SUBSCRIPTION_FLAG_NODE = (1 << 1), - PINOS_SUBSCRIPTION_FLAG_PORT = (1 << 2), - PINOS_SUBSCRIPTION_FLAG_CHANNEL = (1 << 3) + PINOS_SUBSCRIPTION_FLAG_CLIENT = (1 << 1), + PINOS_SUBSCRIPTION_FLAG_NODE = (1 << 2), + PINOS_SUBSCRIPTION_FLAG_PORT = (1 << 3), + PINOS_SUBSCRIPTION_FLAG_CHANNEL = (1 << 4) } PinosSubscriptionFlags; -#define PINOS_SUBSCRIPTION_FLAGS_ALL 0x0f +#define PINOS_SUBSCRIPTION_FLAGS_ALL 0x1f typedef enum { PINOS_SUBSCRIPTION_EVENT_NEW = 0, diff --git a/pinos/tools/pinos-monitor.c b/pinos/tools/pinos-monitor.c index 404bb6991..4fabbebe0 100644 --- a/pinos/tools/pinos-monitor.c +++ b/pinos/tools/pinos-monitor.c @@ -153,6 +153,19 @@ dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, gpointer user_da } } +static void +dump_client_info (PinosContext *c, const PinosClientInfo *info, gpointer user_data) +{ + DumpData *data = user_data; + + g_print ("\tid: %p\n", info->id); + g_print ("\tclient-path: \"%s\"\n", info->client_path); + if (data->print_all) { + g_print ("\tsender: \"%s\"\n", info->sender); + print_properties (info->properties, MARK_CHANGE (0)); + } +} + static void dump_node_info (PinosContext *c, const PinosNodeInfo *info, gpointer user_data) { @@ -186,6 +199,25 @@ dump_port_info (PinosContext *c, const PinosPortInfo *info, gpointer user_data) } } +static void +dump_channel_info (PinosContext *c, const PinosChannelInfo *info, gpointer user_data) +{ + DumpData *data = user_data; + + g_print ("\tid: %p\n", info->id); + g_print ("\tchannel-path: \"%s\"\n", info->channel_path); + if (data->print_all) { + g_print ("\tdirection: \"%s\"\n", pinos_direction_as_string (info->direction)); + g_print ("\tclient-path: \"%s\"\n", info->client_path); + + g_print ("%c\tnode-path: \"%s\"\n", MARK_CHANGE (0), info->port_path); + print_properties (info->properties, MARK_CHANGE (1)); + g_print ("%c\tstate: \"%s\"\n", MARK_CHANGE (2), pinos_channel_state_as_string (info->state)); + print_formats ("possible formats", info->possible_formats, MARK_CHANGE (3)); + print_formats ("format", info->format, MARK_CHANGE (4)); + } +} + #if 0 static void dump_connection_info (PinosContext *c, const PinosConnectionInfo *info, gpointer user_data) @@ -213,6 +245,15 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags, info_ready, data); } + else if (flags & PINOS_SUBSCRIPTION_FLAG_CLIENT) { + pinos_context_get_client_info_by_id (context, + id, + PINOS_CLIENT_INFO_FLAGS_NONE, + dump_client_info, + NULL, + info_ready, + data); + } else if (flags & PINOS_SUBSCRIPTION_FLAG_NODE) { pinos_context_get_node_info_by_id (context, id, @@ -231,6 +272,15 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags, info_ready, data); } + else if (flags & PINOS_SUBSCRIPTION_FLAG_CHANNEL) { + pinos_context_get_channel_info_by_id (context, + id, + PINOS_CHANNEL_INFO_FLAGS_NONE, + dump_channel_info, + NULL, + info_ready, + data); + } } static void