[gupnp/wip/phako/new-api: 6/7] wip: Introduce new gupnp_service_proxy_action_new* functions and port to tem



commit 3b67e71e0511f0130a3f2f0038311fdc250aef3b
Author: Jens Georg <mail jensge org>
Date:   Fri Jan 11 21:23:27 2019 +0100

    wip: Introduce new gupnp_service_proxy_action_new* functions and port to tem

 libgupnp/gupnp-service-proxy-action-private.h |  41 +++++-
 libgupnp/gupnp-service-proxy-action.c         | 133 +++++++++++++++---
 libgupnp/gupnp-service-proxy.c                | 185 +++++++++++++++++---------
 libgupnp/gupnp-service-proxy.h                |   8 ++
 4 files changed, 278 insertions(+), 89 deletions(-)
---
diff --git a/libgupnp/gupnp-service-proxy-action-private.h b/libgupnp/gupnp-service-proxy-action-private.h
index 2eda5a4..53de39f 100644
--- a/libgupnp/gupnp-service-proxy-action-private.h
+++ b/libgupnp/gupnp-service-proxy-action-private.h
@@ -1,12 +1,47 @@
 #ifndef GUPNP_SERVICE_PROXY_ACTION_H
 #define GUPNP_SERVICE_PROXY_ACTION_H
 
+#include <gobject/gvaluecollector.h>
+
 G_BEGIN_DECLS
 
+/* Initializes hash table to hold arg names as keys and GValues of
+ * given type and value.
+ */
+#define VAR_ARGS_TO_IN_LIST(var_args, names, values) \
+        G_STMT_START { \
+                const gchar *arg_name = va_arg (var_args, const gchar *); \
+         \
+                while (arg_name != NULL) { \
+                        GValue *value = g_new0 (GValue, 1); \
+                        gchar *__error = NULL; \
+                        GType type = va_arg (var_args, GType); \
+         \
+                        G_VALUE_COLLECT_INIT (value, \
+                                              type, \
+                                              var_args, \
+                                              G_VALUE_NOCOPY_CONTENTS, \
+                                              &__error); \
+                        if (__error == NULL) { \
+                                names = g_list_prepend (names, g_strdup (arg_name)); \
+                                values = g_list_prepend (values, value); \
+                        } else { \
+                                g_warning ("Failed to collect value of type %s for %s: %s", \
+                                           g_type_name (type), \
+                                           arg_name, \
+                                           __error); \
+                                g_free (__error); \
+                        } \
+                        arg_name = va_arg (var_args, const gchar *); \
+                } \
+                names = g_list_reverse (names); \
+                values = g_list_reverse (values); \
+        } G_STMT_END
+
 struct _GUPnPServiceProxyAction {
-        volatile gint ref_count;
         GUPnPServiceProxy *proxy;
-        char *action_name;
+        char *name;
+        gint header_pos;
 
         SoupMessage *msg;
         GString *msg_str;
@@ -19,7 +54,7 @@ struct _GUPnPServiceProxyAction {
 };
 
 G_GNUC_INTERNAL GUPnPServiceProxyAction *
-gupnp_service_proxy_action_new (const char *action);
+gupnp_service_proxy_action_new_internal (const char *action);
 
 G_GNUC_INTERNAL GUPnPServiceProxyAction *
 gupnp_service_proxy_action_ref (GUPnPServiceProxyAction *action);
diff --git a/libgupnp/gupnp-service-proxy-action.c b/libgupnp/gupnp-service-proxy-action.c
index b932277..1e8ea04 100644
--- a/libgupnp/gupnp-service-proxy-action.c
+++ b/libgupnp/gupnp-service-proxy-action.c
@@ -22,13 +22,17 @@
 #include "gupnp-service-proxy.h"
 #include "gupnp-service-proxy-private.h"
 #include "gupnp-service-proxy-action-private.h"
+#include "gvalue-util.h"
+#include "xml-util.h"
 
 GUPnPServiceProxyAction *
-gupnp_service_proxy_action_new (const char *action) {
+gupnp_service_proxy_action_new_internal (const char *action) {
         GUPnPServiceProxyAction *ret;
 
-        ret = g_slice_new (GUPnPServiceProxyAction);
-        ret->ref_count = 1;
+        g_return_val_if_fail (action != NULL, NULL);
+
+        ret = g_atomic_rc_box_new0 (GUPnPServiceProxyAction);
+        ret->name = g_strdup (action);
 
         return ret;
 }
@@ -37,36 +41,123 @@ GUPnPServiceProxyAction *
 gupnp_service_proxy_action_ref (GUPnPServiceProxyAction *action)
 {
         g_return_val_if_fail (action, NULL);
-        g_return_val_if_fail (action->ref_count > 0, NULL);
 
-        g_atomic_int_inc (&action->ref_count);
+        return g_atomic_rc_box_acquire (action);
+}
 
-        return action;
+static void
+action_dispose (GUPnPServiceProxyAction *action)
+{
+        if (action->proxy != NULL) {
+                g_object_remove_weak_pointer (G_OBJECT (action->proxy),
+                                (gpointer *)&(action->proxy));
+                gupnp_service_proxy_remove_action (action->proxy, action);
+        }
+
+        g_clear_object (&action->msg);
+        g_free (action->name);
 }
 
 void
 gupnp_service_proxy_action_unref (GUPnPServiceProxyAction *action)
 {
-
         g_return_if_fail (action);
-        g_return_if_fail (action->ref_count > 0);
-
-
-        if (g_atomic_int_dec_and_test (&action->ref_count)) {
-                if (action->proxy != NULL) {
-                        g_object_remove_weak_pointer (G_OBJECT (action->proxy),
-                                                      (gpointer *)&(action->proxy));
-                        gupnp_service_proxy_remove_action (action->proxy, action);
-                }
-
-                if (action->msg != NULL)
-                        g_object_unref (action->msg);
 
-                g_slice_free (GUPnPServiceProxyAction, action);
-        }
+        g_atomic_rc_box_release_full (action, (GDestroyNotify) action_dispose);
 }
 
 G_DEFINE_BOXED_TYPE (GUPnPServiceProxyAction,
                      gupnp_service_proxy_action,
                      gupnp_service_proxy_action_ref,
                      gupnp_service_proxy_action_unref)
+
+/* Writes a parameter name and GValue pair to @msg */
+static void
+write_in_parameter (const char *arg_name,
+                    GValue     *value,
+                    GString    *msg_str)
+{
+        /* Write parameter pair */
+        xml_util_start_element (msg_str, arg_name);
+        gvalue_util_value_append_to_xml_string (value, msg_str);
+        xml_util_end_element (msg_str, arg_name);
+}
+
+static void
+write_footer (GUPnPServiceProxyAction *action)
+{
+        /* Finish message */
+        g_string_append (action->msg_str, "</u:");
+        g_string_append (action->msg_str, action->name);
+        g_string_append_c (action->msg_str, '>');
+
+        g_string_append (action->msg_str,
+                         "</s:Body>"
+                         "</s:Envelope>");
+}
+
+GUPnPServiceProxyAction *
+gupnp_service_proxy_action_new (const char *action,
+                                ...)
+{
+        va_list var_args;
+        GList *in_names = NULL;
+        GList *in_values = NULL;
+
+        g_return_val_if_fail (action != NULL, NULL);
+
+        va_start (var_args, action);
+        VAR_ARGS_TO_IN_LIST (var_args, in_names, in_values);
+        va_end (var_args);
+
+        return gupnp_service_proxy_action_new_from_list (action,
+                                                         in_names,
+                                                         in_values);;
+}
+
+
+/**
+ * gupnp_service_proxy_action_new_from_list:
+ * @action: An action
+ * @in_names: (element-type utf8) (transfer none): #GList of 'in' parameter
+ * names (as strings)
+ * @in_values: (element-type GValue) (transfer none): #GList of values (as
+ * #GValue) that line up with @in_names
+ */
+GUPnPServiceProxyAction *
+gupnp_service_proxy_action_new_from_list (const char *action_name,
+                                          GList      *in_names,
+                                          GList      *in_values)
+{
+        GUPnPServiceProxyAction *action;
+        GList *names, *values;
+
+        action = gupnp_service_proxy_action_new_internal (action_name);
+        action->msg_str = xml_util_new_string ();
+
+        g_string_append (action->msg_str,
+                         "<?xml version=\"1.0\"?>"
+                         "<s:Envelope xmlns:s="
+                                "\"http://schemas.xmlsoap.org/soap/envelope/\"; "
+                          "s:encodingStyle="
+                                "\"http://schemas.xmlsoap.org/soap/encoding/\";>"
+                         "<s:Body>");
+        action->header_pos = action->msg_str->len;
+
+        /* Arguments */
+        for (names = in_names, values = in_values;
+             names && values;
+             names=names->next, values = values->next) {
+                GValue* val = values->data;
+
+                write_in_parameter (names->data,
+                                    val,
+                                    action->msg_str);
+        }
+
+        /* Finish and send off */
+        write_footer (action);
+
+        return action;
+}
+
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 987dc0c..9805f98 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -470,39 +470,6 @@ stop_main_loop (G_GNUC_UNUSED GUPnPServiceProxy       *proxy,
                 } \
         } G_STMT_END
 
-/* Initializes hash table to hold arg names as keys and GValues of
- * given type and value.
- */
-#define VAR_ARGS_TO_IN_LIST(var_args, names, values) \
-        G_STMT_START { \
-                const gchar *arg_name = va_arg (var_args, const gchar *); \
-         \
-                while (arg_name != NULL) { \
-                        GValue *value = g_new0 (GValue, 1); \
-                        gchar *__error = NULL; \
-                        GType type = va_arg (var_args, GType); \
-         \
-                        G_VALUE_COLLECT_INIT (value, \
-                                              type, \
-                                              var_args, \
-                                              G_VALUE_NOCOPY_CONTENTS, \
-                                              &__error); \
-                        if (__error == NULL) { \
-                                names = g_list_prepend (names, g_strdup (arg_name)); \
-                                values = g_list_prepend (values, value); \
-                        } else { \
-                                g_warning ("Failed to collect value of type %s for %s: %s", \
-                                           g_type_name (type), \
-                                           arg_name, \
-                                           __error); \
-                                g_free (__error); \
-                        } \
-                        arg_name = va_arg (var_args, const gchar *); \
-                } \
-                names = g_list_reverse (names); \
-                values = g_list_reverse (values); \
-        } G_STMT_END
-
 /* Puts values stored in hash table with GValues into var args.
  */
 #define OUT_HASH_TABLE_TO_VAR_ARGS(hash, var_args) \
@@ -739,6 +706,91 @@ gupnp_service_proxy_begin_action (GUPnPServiceProxy              *proxy,
         return ret;
 }
 
+/* Begins a basic action message */
+static void
+prepare_action_msg (GUPnPServiceProxy              *proxy,
+                    GUPnPServiceProxyAction        *ret,
+                    GUPnPServiceProxyActionCallback callback,
+                    gpointer                        user_data)
+{
+        GUPnPServiceProxyPrivate *priv;
+        char *control_url, *full_action;
+        const char *service_type;
+
+        priv = gupnp_service_proxy_get_instance_private (proxy);
+
+        ret->proxy = proxy;
+        g_object_add_weak_pointer (G_OBJECT (proxy), (gpointer *)&(ret->proxy));
+
+        ret->callback  = callback;
+        ret->user_data = user_data;
+
+        priv->pending_actions = g_list_prepend (priv->pending_actions, ret);
+
+        /* Make sure we have a service type */
+        service_type = gupnp_service_info_get_service_type
+                                        (GUPNP_SERVICE_INFO (proxy));
+        if (service_type == NULL) {
+                ret->error = g_error_new (GUPNP_SERVER_ERROR,
+                                          GUPNP_SERVER_ERROR_OTHER,
+                                          "No service type defined");
+
+                return;
+        }
+
+        /* Create message */
+        control_url = gupnp_service_info_get_control_url
+                                        (GUPNP_SERVICE_INFO (proxy));
+
+        if (control_url != NULL) {
+                GUPnPContext *context = NULL;
+                char *local_control_url = NULL;
+
+                context = gupnp_service_info_get_context
+                                        (GUPNP_SERVICE_INFO (proxy));
+
+                local_control_url = gupnp_context_rewrite_uri (context,
+                                                               control_url);
+                g_free (control_url);
+
+                ret->msg = soup_message_new (SOUP_METHOD_POST, local_control_url);
+                g_free (local_control_url);
+        }
+
+        if (ret->msg == NULL) {
+                ret->error = g_error_new (GUPNP_SERVER_ERROR,
+                                          GUPNP_SERVER_ERROR_INVALID_URL,
+                                          "No valid control URL defined");
+
+                return;
+        }
+
+        /* Specify action */
+        full_action = g_strdup_printf ("\"%s#%s\"", service_type, ret->name);
+        soup_message_headers_append (ret->msg->request_headers,
+                                     "SOAPAction",
+                                     full_action);
+        g_free (full_action);
+
+        /* Specify language */
+        http_request_set_accept_language (ret->msg);
+
+        /* Accept gzip encoding */
+        soup_message_headers_append (ret->msg->request_headers,
+                                     "Accept-Encoding", "gzip");
+
+        g_string_insert (ret->msg_str, ret->header_pos, "<u:");
+        ret->header_pos += strlen("<u:");
+        g_string_insert (ret->msg_str, ret->header_pos, ret->name);
+        ret->header_pos += strlen (ret->name);
+        g_string_insert (ret->msg_str, ret->header_pos, " xmlns:u=\"");
+        ret->header_pos += strlen(" xmlns:u=\"");
+        g_string_insert (ret->msg_str, ret->header_pos, service_type);
+        ret->header_pos += strlen (service_type);
+        g_string_insert (ret->msg_str, ret->header_pos, "\">");
+}
+
+
 /* Begins a basic action message */
 static GUPnPServiceProxyAction *
 begin_action_msg (GUPnPServiceProxy              *proxy,
@@ -754,7 +806,7 @@ begin_action_msg (GUPnPServiceProxy              *proxy,
         priv = gupnp_service_proxy_get_instance_private (proxy);
 
         /* Create action structure */
-        ret = gupnp_service_proxy_action_new (action);
+        ret = gupnp_service_proxy_action_new_internal (action);
 
         ret->proxy = proxy;
         g_object_add_weak_pointer (G_OBJECT (proxy), (gpointer *)&(ret->proxy));
@@ -885,6 +937,35 @@ action_got_response (SoupSession             *session,
         }
 }
 
+static void
+gupnp_service_proxy_action_queue (GUPnPServiceProxyAction *action)
+{
+        GUPnPContext *context;
+        SoupSession *session;
+
+        soup_message_set_request (action->msg,
+                                  "text/xml; charset=\"utf-8\"",
+                                  SOUP_MEMORY_TAKE,
+                                  action->msg_str->str,
+                                  action->msg_str->len);
+
+        g_string_free (action->msg_str, FALSE);
+
+        /* We need to keep our own reference to the message as well,
+         * in order for send_action() to work. */
+        g_object_ref (action->msg);
+
+        /* Send the message */
+        context = gupnp_service_info_get_context
+                                (GUPNP_SERVICE_INFO (action->proxy));
+        session = gupnp_context_get_session (context);
+
+        soup_session_queue_message (session,
+                                    action->msg,
+                                    (SoupSessionCallback) action_got_response,
+                                    action);
+}
+
 /* Finishes an action message and sends it off */
 static void
 finish_action_msg (GUPnPServiceProxyAction *action,
@@ -925,18 +1006,6 @@ finish_action_msg (GUPnPServiceProxyAction *action,
                                     action);
 }
 
-/* Writes a parameter name and GValue pair to @msg */
-static void
-write_in_parameter (const char *arg_name,
-                    GValue     *value,
-                    GString    *msg_str)
-{
-        /* Write parameter pair */
-        xml_util_start_element (msg_str, arg_name);
-        gvalue_util_value_append_to_xml_string (value, msg_str);
-        xml_util_end_element (msg_str, arg_name);
-}
-
 static gboolean
 action_error_idle_cb (gpointer user_data)
 {
@@ -1022,8 +1091,6 @@ gupnp_service_proxy_begin_action_list
                                     gpointer                         user_data)
 {
         GUPnPServiceProxyAction *ret;
-        GList *names;
-        GList *values;
 
         g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), NULL);
         g_return_val_if_fail (action, NULL);
@@ -1032,8 +1099,10 @@ gupnp_service_proxy_begin_action_list
                               g_list_length (in_values),
                               NULL);
 
-        /* Create message */
-        ret = begin_action_msg (proxy, action, callback, user_data);
+        ret = gupnp_service_proxy_action_new_from_list (action,
+                                                        in_names,
+                                                        in_values);
+        prepare_action_msg (proxy, ret, callback, user_data);
 
         if (ret->error) {
                 g_idle_add (action_error_idle_cb, ret);
@@ -1041,21 +1110,7 @@ gupnp_service_proxy_begin_action_list
                 return ret;
         }
 
-        /* Arguments */
-        values = in_values;
-
-        for (names = in_names; names; names=names->next) {
-                GValue* val = values->data;
-
-                write_in_parameter (names->data,
-                                    val,
-                                    ret->msg_str);
-
-                values = values->next;
-        }
-
-        /* Finish and send off */
-        finish_action_msg (ret, action);
+        gupnp_service_proxy_action_queue (ret);
 
         return ret;
 }
diff --git a/libgupnp/gupnp-service-proxy.h b/libgupnp/gupnp-service-proxy.h
index d61ac69..fe9f46b 100644
--- a/libgupnp/gupnp-service-proxy.h
+++ b/libgupnp/gupnp-service-proxy.h
@@ -208,6 +208,14 @@ gupnp_service_proxy_set_subscribed (GUPnPServiceProxy              *proxy,
 gboolean
 gupnp_service_proxy_get_subscribed (GUPnPServiceProxy              *proxy);
 
+GUPnPServiceProxyAction *
+gupnp_service_proxy_action_new (const char *action,
+                                ...);
+
+GUPnPServiceProxyAction *
+gupnp_service_proxy_action_new_from_list (const char *action,
+                                          GList      *in_names,
+                                          GList      *in_values);
 
 G_END_DECLS
 


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