[rygel-grilo] Add asynchonous function to get properties



commit 57ef843b78fadb464526d439b198f8c1d176402e
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date:   Thu May 20 12:27:49 2010 +0200

    Add asynchonous function to get properties

 lib/media-server1-client.c |  194 ++++++++++++++++++++++++++++++++++++++++++++
 lib/media-server1-client.h |   10 +++
 src/test-client.c          |   80 +++++++++++++++++--
 3 files changed, 277 insertions(+), 7 deletions(-)
---
diff --git a/lib/media-server1-client.c b/lib/media-server1-client.c
index 1288229..2a3a955 100644
--- a/lib/media-server1-client.c
+++ b/lib/media-server1-client.c
@@ -36,17 +36,30 @@
 /*
  * Structure to store data for asynchronous operations
  *   gproxy: dbus proxy to invoke methods
+ *   expected_replies: how many replies are still pending before notifying user
+ *                     (used only with get_properties_async())
  *   error: operation error
  *   properties: result of invoking get_properties
  *   children: result of invoking list_children
  */
 typedef struct {
   DBusGProxy *gproxy;
+  gint expected_replies;
   GError *error;
   GHashTable *properties;
   GList *children;
 } AsyncData;
 
+/*
+ * Structure to store data for asynchronous Get operation
+ *   key: key which value is reported
+ *   result: common data used in the asynchronous operation
+ */
+typedef struct {
+  gchar *key;
+  GSimpleAsyncResult *result;
+} GetData;
+
 enum {
   UPDATED,
   DESTROY,
@@ -93,6 +106,14 @@ free_async_data (AsyncData *adata)
   g_slice_free (AsyncData, adata);
 }
 
+/* Free GetData */
+static void
+free_get_data (GetData *gdata)
+{
+  g_free (gdata->key);
+  g_slice_free (GetData, gdata);
+}
+
 /* Insert <key, value> in hashtable */
 static gboolean
 collect_value (gpointer key,
@@ -224,6 +245,62 @@ search_objects_reply (DBusGProxy *proxy,
   g_simple_async_result_complete (res);
 }
 
+/* Callback invoked when Get reply is received */
+static void
+get_reply (DBusGProxy *proxy,
+           DBusGProxyCall *call,
+           void *user_data)
+{
+  AsyncData *adata;
+  GValue *v = NULL;
+  GetData *gdata = (GetData *) user_data;
+
+  adata = g_simple_async_result_get_op_res_gpointer (gdata->result);
+
+  if (dbus_g_proxy_end_call (proxy, call, &(adata->error),
+                             G_TYPE_VALUE, v,
+                             G_TYPE_INVALID)) {
+    g_hash_table_insert (adata->properties,
+                         g_strdup (gdata->key),
+                         v);
+  }
+  adata->expected_replies--;
+  if (adata->expected_replies == 0) {
+    g_simple_async_result_complete (gdata->result);
+    g_object_unref (gdata->result);
+  }
+}
+
+/* Callback invoked when GetAll reply is received */
+static void
+get_all_reply (DBusGProxy *proxy,
+               DBusGProxyCall *call,
+               void *user_data)
+{
+  AsyncData *adata;
+  GHashTable *prop_result;
+  GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+
+  adata = g_simple_async_result_get_op_res_gpointer (res);
+
+  if (dbus_g_proxy_end_call (proxy, call, &(adata->error),
+                             dbus_g_type_get_map ("GHashTable",
+                                                  G_TYPE_STRING,
+                                                  G_TYPE_VALUE), &prop_result,
+                             G_TYPE_INVALID)) {
+    g_hash_table_foreach_steal (prop_result,
+                                (GHRFunc) collect_value,
+                                adata->properties);
+    g_hash_table_unref (prop_result);
+  }
+
+  adata->expected_replies--;
+  if (adata->expected_replies == 0) {
+    g_simple_async_result_complete (res);
+    g_object_unref (res);
+  }
+}
+
 /* Dispose function */
 static void
 ms1_client_dispose (GObject *object)
@@ -448,6 +525,123 @@ ms1_client_get_provider_name (MS1Client *client)
 }
 
 /**
+ * ms1_client_get_properties_async:
+ * @client: a #MS1Client
+ * @object_path: media identifier to obtain properties from
+ * @callback: a #GAsyncReadyCallback to call when request is satisfied
+ * @user_data: the data to pass to callback function
+ *
+ * Starts an asynchronous request of properties.
+ *
+ * For more details, see ms1_client_get_properties(), which is the synchronous
+ * version of this call.
+ *
+ * When the result has been obtained, @callback will be called with
+ * @user_data. To finish the operation, call ms1_client_get_properties_finish()
+ * with the #GAsyncResult returned by the @callback.
+ **/
+void
+ms1_client_get_properties_async (MS1Client *client,
+                                 const gchar *object_path,
+                                 gchar **properties,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+  AsyncData *adata;
+  GetData *gdata;
+  GSimpleAsyncResult *res;
+  gchar ***prop_by_iface;
+  gint i;
+  gint num_props;
+
+  g_return_if_fail (MS1_IS_CLIENT (client));
+
+  res = g_simple_async_result_new (G_OBJECT (client),
+                                   callback,
+                                   user_data,
+                                   ms1_client_get_properties_async);
+  adata = g_slice_new0 (AsyncData);
+  g_simple_async_result_set_op_res_gpointer (res,
+                                             adata,
+                                             (GDestroyNotify) free_async_data);
+  adata->gproxy = dbus_g_proxy_new_for_name (client->priv->bus,
+                                             client->priv->fullname,
+                                             object_path,
+                                             "org.freedesktop.DBus.Properties");
+
+  adata->properties = g_hash_table_new_full (g_str_hash,
+                                             g_str_equal,
+                                             (GDestroyNotify) g_free,
+                                             (GDestroyNotify) free_gvalue);
+
+  prop_by_iface = split_properties_by_interface (properties);
+  for (i = 0; i < 3; i++) {
+    num_props = g_strv_length (prop_by_iface[i]);
+    /* If only one property is required, then invoke "Get" method */
+    if (num_props == 1) {
+      adata->expected_replies++;
+      gdata = g_slice_new (GetData);
+      gdata->key = g_strdup (prop_by_iface[i][0]);
+      gdata->result = res;
+      dbus_g_proxy_begin_call (adata->gproxy,
+                               "Get", get_reply,
+                               gdata, (GDestroyNotify) free_get_data,
+                               G_TYPE_STRING, IFACES[i],
+                               G_TYPE_STRING, prop_by_iface[i][0],
+                               G_TYPE_INVALID);
+    } else if (num_props > 1) {
+      /* If several properties are required, use "GetAll" method */
+      adata->expected_replies++;
+      dbus_g_proxy_begin_call (adata->gproxy,
+                               "GetAll", get_all_reply,
+                               res, NULL,
+                               G_TYPE_STRING, IFACES[i],
+                               G_TYPE_INVALID);
+    }
+  }
+
+  g_free (prop_by_iface[0]);
+  g_free (prop_by_iface[1]);
+  g_free (prop_by_iface[2]);
+  g_free (prop_by_iface);
+}
+
+/**
+ * ms1_client_get_properties_finish:
+ * @client: a #MS1Client
+ * @res: a #GAsyncResult
+ * @error: a #GError location to store the error ocurring, or @NULL to ignore
+ *
+ * Finishes an asynchronous request of properties operation.
+ *
+ * Returns: a new #GHashTable
+ **/
+GHashTable *
+ms1_client_get_properties_finish (MS1Client *client,
+                                  GAsyncResult *res,
+                                  GError **error)
+{
+  AsyncData *adata;
+
+  g_return_val_if_fail (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (res)) ==
+                        ms1_client_get_properties_async, NULL);
+
+  adata = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+
+  /* If there was an error, just return NULL to avoid partially-filled table */
+  if (adata->error) {
+    g_hash_table_unref (adata->properties);
+    adata->children = NULL;
+  }
+
+  if (error) {
+    *error = adata->error;
+  }
+
+  return adata->properties;
+}
+
+/**
  * ms1_client_get_properties:
  * @client: a #MS1Client
  * @object_path: media identifier to obtain properties from
diff --git a/lib/media-server1-client.h b/lib/media-server1-client.h
index a9f3886..02cb16b 100644
--- a/lib/media-server1-client.h
+++ b/lib/media-server1-client.h
@@ -86,6 +86,16 @@ MS1Client *ms1_client_new (const gchar *provider);
 
 const gchar *ms1_client_get_provider_name (MS1Client *client);
 
+void ms1_client_get_properties_async (MS1Client *client,
+                                      const gchar *object_path,
+                                      gchar **properties,
+                                      GAsyncReadyCallback callback,
+                                      gpointer user_data);
+
+GHashTable *ms1_client_get_properties_finish (MS1Client *client,
+                                              GAsyncResult *res,
+                                              GError **error);
+
 GHashTable *ms1_client_get_properties (MS1Client *client,
                                        const gchar *object_path,
                                        gchar **properties,
diff --git a/src/test-client.c b/src/test-client.c
index a8ee223..ad4c87e 100644
--- a/src/test-client.c
+++ b/src/test-client.c
@@ -4,13 +4,13 @@
 #include <string.h>
 
 static gchar *properties[] = { MS1_PROP_PATH,
-                               /* MS1_PROP_DISPLAY_NAME, */
-                               /* MS1_PROP_PARENT, */
-                               /* MS1_PROP_CHILD_COUNT, */
+                               MS1_PROP_DISPLAY_NAME,
+                               MS1_PROP_PARENT,
+                               MS1_PROP_CHILD_COUNT,
                                MS1_PROP_CONTAINERS,
-                               /* MS1_PROP_ITEMS, */
-                               /* MS1_PROP_URLS, */
-                               /* MS1_PROP_ARTIST, */
+                               MS1_PROP_ITEMS,
+                               MS1_PROP_URLS,
+                               MS1_PROP_ARTIST,
                                NULL };
 
 static void
@@ -77,6 +77,71 @@ test_properties ()
 }
 
 static void
+properties_reply (GObject *source,
+                  GAsyncResult *res,
+                  gpointer user_data)
+{
+  GError *error = NULL;
+  GHashTable *result;
+  GValue *v;
+  gchar **p;
+
+  result =
+    ms1_client_get_properties_finish (MS1_CLIENT (source), res, &error);
+
+  if (!result) {
+    g_print ("\tDid not get any property, %s\n",
+             error? error->message: "no error");
+    return;
+  }
+
+  for (p = properties; *p; p++) {
+    v = g_hash_table_lookup (result, *p);
+    if (v && G_VALUE_HOLDS_INT (v)) {
+      g_print ("\t* '%s' value: '%d'\n", *p, g_value_get_int (v));
+    } else if (v && G_VALUE_HOLDS_STRING (v)) {
+      g_print ("\t* '%s' value: '%s'\n", *p, g_value_get_string (v));
+    } else {
+      g_print ("\t* '%s' value: ---\n", *p);
+    }
+  }
+  g_hash_table_unref (result);
+  g_object_unref (source);
+}
+
+static void
+test_properties_async ()
+{
+  MS1Client *client;
+  gchar **provider;
+  gchar **providers;
+
+  providers = ms1_client_get_providers ();
+
+  if (!providers) {
+    g_print ("There is no MediaServer1 provider\n");
+    return;
+  }
+
+  for (provider = providers; *provider; provider ++) {
+    client = ms1_client_new (*provider);
+
+    if (!client) {
+      g_printerr ("Unable to create a client\n");
+      return;
+    }
+
+    ms1_client_get_properties_async (client,
+                                     ms1_client_get_root_path (client),
+                                     (gchar **) properties,
+                                     properties_reply,
+                                     NULL);
+  }
+
+  g_strfreev (providers);
+}
+
+static void
 test_children ()
 {
   GError *error = NULL;
@@ -370,8 +435,9 @@ int main (int argc, char **argv)
   g_type_init ();
 
   if (0) test_properties ();
+  if (1) test_properties_async ();
   if (0) test_children ();
-  if (1) test_children_async ();
+  if (0) test_children_async ();
   if (0) test_search ();
   if (0) test_provider_free ();
   if (0) test_updated ();



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