[gupnp/wip/phako/reusable-service-action: 1/7] ServiceProxyAction: Change serialization




commit c615161b80eee31f8ebf039601a602047caffc1c
Author: Jens Georg <mail jensge org>
Date:   Sat May 29 00:55:49 2021 +0200

    ServiceProxyAction: Change serialization
    
     - Arguemnts are stored in the ServiceProxyAction
     - Serialization is done before creating the message

 libgupnp/gupnp-service-proxy-action-private.h | 12 +++-
 libgupnp/gupnp-service-proxy-action.c         | 85 ++++++++++++++++++++-------
 libgupnp/gupnp-service-proxy.c                | 60 ++++++++-----------
 3 files changed, 100 insertions(+), 57 deletions(-)
---
diff --git a/libgupnp/gupnp-service-proxy-action-private.h b/libgupnp/gupnp-service-proxy-action-private.h
index 31927a4..d5068e6 100644
--- a/libgupnp/gupnp-service-proxy-action-private.h
+++ b/libgupnp/gupnp-service-proxy-action-private.h
@@ -144,7 +144,6 @@ G_BEGIN_DECLS
                 } \
         } G_STMT_END
 
-
 struct _GUPnPServiceProxyAction {
         GUPnPServiceProxy *proxy;
         char *name;
@@ -159,8 +158,12 @@ struct _GUPnPServiceProxyAction {
         GUPnPServiceProxyActionCallback callback;
         gpointer user_data;
 
-        GError *error;    /* If non-NULL, description of error that
-                             occurred when preparing message */
+        GError *error; /* If non-NULL, description of error that
+                          occurred when preparing message */
+
+        GPtrArray *args;
+        GHashTable *arg_map;
+        gboolean pending;
 };
 
 G_GNUC_INTERNAL GUPnPServiceProxyAction *
@@ -171,6 +174,9 @@ gupnp_service_proxy_action_get_result_valist (GUPnPServiceProxyAction *action,
                                               GError                 **error,
                                               va_list                  var_args);
 
+G_GNUC_INTERNAL void
+gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action,
+                                      const char *service_type);
 G_END_DECLS
 
 #endif /* GUPNP_SERVICE_PROXY_ACTION_H */
diff --git a/libgupnp/gupnp-service-proxy-action.c b/libgupnp/gupnp-service-proxy-action.c
index da41d91..d2af09b 100644
--- a/libgupnp/gupnp-service-proxy-action.c
+++ b/libgupnp/gupnp-service-proxy-action.c
@@ -26,6 +26,20 @@
 #include "gvalue-util.h"
 #include "xml-util.h"
 
+struct _ActionArgument {
+        char *name;
+        GValue value;
+};
+typedef struct _ActionArgument ActionArgument;
+
+void
+action_argument_free (ActionArgument* arg)
+{
+        g_free (arg->name);
+        g_value_unset (&arg->value);
+        g_free (arg);
+}
+
 /* Reads a value into the parameter name and initialised GValue pair
  * from @response */
 static void
@@ -202,6 +216,8 @@ gupnp_service_proxy_action_new_internal (const char *action) {
 
         ret = g_atomic_rc_box_new0 (GUPnPServiceProxyAction);
         ret->name = g_strdup (action);
+        ret->args = g_ptr_array_new_with_free_func((GDestroyNotify)action_argument_free);
+        ret->arg_map = g_hash_table_new (g_str_hash, g_str_equal);
 
         return ret;
 }
@@ -234,6 +250,8 @@ action_dispose (GUPnPServiceProxyAction *action)
                 g_string_free (action->msg_str, TRUE);
                 action->msg_str = NULL;
         }
+        g_hash_table_destroy (action->arg_map);
+        g_ptr_array_unref (action->args);
         g_free (action->name);
 }
 
@@ -252,14 +270,13 @@ G_DEFINE_BOXED_TYPE (GUPnPServiceProxyAction,
 
 /* Writes a parameter name and GValue pair to @msg */
 static void
-write_in_parameter (const char *arg_name,
-                    GValue     *value,
+write_in_parameter (ActionArgument *arg,
                     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);
+        xml_util_start_element (msg_str, arg->name);
+        gvalue_util_value_append_to_xml_string (&arg->value, msg_str);
+        xml_util_end_element (msg_str, arg->name);
 }
 
 static void
@@ -314,34 +331,62 @@ gupnp_service_proxy_action_new_from_list (const char *action_name,
 {
         GUPnPServiceProxyAction *action;
         GList *names, *values;
+        guint position;
 
         action = gupnp_service_proxy_action_new_internal (action_name);
+
+        /* Arguments */
+        for (names = in_names, values = in_values, position = 0;
+             names && values;
+             names = names->next, values = values->next, position++) {
+                GValue *val = values->data;
+
+                ActionArgument *arg = g_new0 (ActionArgument, 1);
+                arg->name = g_strdup (names->data);
+                g_value_init (&arg->value, G_VALUE_TYPE (val));
+                g_value_copy (val, &arg->value);
+                g_hash_table_insert (action->arg_map,
+                                     arg->name,
+                                     GUINT_TO_POINTER (position));
+                g_ptr_array_add (action->args, arg);
+        }
+
+        return action;
+}
+
+void
+gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action,
+                                      const char *service_type)
+{
+        if (action->msg_str != NULL) {
+                g_string_free (action->msg_str, TRUE);
+        }
         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/\";>"
+                         "\"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);
-        }
+        g_ptr_array_foreach (action->args,
+                             (GFunc) write_in_parameter,
+                             action->msg_str);
 
-        /* Finish and send off */
         write_footer (action);
 
-        return action;
+        g_string_insert (action->msg_str, action->header_pos, "<u:");
+        action->header_pos += strlen ("<u:");
+        g_string_insert (action->msg_str, action->header_pos, action->name);
+        action->header_pos += strlen (action->name);
+        g_string_insert (action->msg_str, action->header_pos, " xmlns:u=\"");
+        action->header_pos += strlen (" xmlns:u=\"");
+        g_string_insert (action->msg_str, action->header_pos, service_type);
+        action->header_pos += strlen (service_type);
+        g_string_insert (action->msg_str, action->header_pos, "\">");
 }
 
 /**
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 6e09456..e630747 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -628,10 +628,12 @@ on_action_cancelled (GCancellable *cancellable, gpointer user_data)
         }
 }
 
+
+
 /* Begins a basic action message */
 static void
 prepare_action_msg (GUPnPServiceProxy              *proxy,
-                    GUPnPServiceProxyAction        *ret,
+                    GUPnPServiceProxyAction        *action,
                     GCancellable                   *cancellable)
 {
         GUPnPServiceProxyPrivate *priv;
@@ -639,27 +641,26 @@ prepare_action_msg (GUPnPServiceProxy              *proxy,
         const char *service_type;
 
         priv = gupnp_service_proxy_get_instance_private (proxy);
+        action->proxy = proxy;
+        g_object_add_weak_pointer (G_OBJECT (proxy), (gpointer *)&(action->proxy));
 
-        ret->proxy = proxy;
-        g_object_add_weak_pointer (G_OBJECT (proxy), (gpointer *)&(ret->proxy));
-
-        priv->pending_actions = g_list_prepend (priv->pending_actions, ret);
+        priv->pending_actions = g_list_prepend (priv->pending_actions, action);
 
         if (cancellable != NULL) {
-                ret->cancellable = g_object_ref (cancellable);
+                action->cancellable = g_object_ref (cancellable);
         } else {
-                ret->cancellable = g_cancellable_new ();
+                action->cancellable = g_cancellable_new ();
         }
-        ret->cancellable_connection_id = g_cancellable_connect (ret->cancellable,
+        action->cancellable_connection_id = g_cancellable_connect (action->cancellable,
                                                                 G_CALLBACK (on_action_cancelled),
-                                                                ret,
+                                                                action,
                                                                 NULL);
 
         /* 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,
+                action->error = g_error_new (GUPNP_SERVER_ERROR,
                                           GUPNP_SERVER_ERROR_OTHER,
                                           "No service type defined");
 
@@ -681,12 +682,10 @@ prepare_action_msg (GUPnPServiceProxy              *proxy,
                                                                control_url);
                 g_free (control_url);
 
-                ret->msg = soup_message_new (SOUP_METHOD_POST, local_control_url);
+                action->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,
+        } else {
+                action->error = g_error_new (GUPNP_SERVER_ERROR,
                                           GUPNP_SERVER_ERROR_INVALID_URL,
                                           "No valid control URL defined");
 
@@ -694,37 +693,29 @@ prepare_action_msg (GUPnPServiceProxy              *proxy,
         }
 
         /* Specify action */
-        full_action = g_strdup_printf ("\"%s#%s\"", service_type, ret->name);
-        soup_message_headers_append (ret->msg->request_headers,
+        full_action = g_strdup_printf ("\"%s#%s\"", service_type, action->name);
+        soup_message_headers_append (action->msg->request_headers,
                                      "SOAPAction",
                                      full_action);
         g_free (full_action);
 
         /* Specify language */
-        http_request_set_accept_language (ret->msg);
+        http_request_set_accept_language (action->msg);
 
         /* Accept gzip encoding */
-        soup_message_headers_append (ret->msg->request_headers,
+        soup_message_headers_append (action->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, "\">");
-
-        soup_message_set_request (ret->msg,
+        gupnp_service_proxy_action_serialize (action, service_type);
+
+        soup_message_set_request (action->msg,
                                   "text/xml; charset=\"utf-8\"",
                                   SOUP_MEMORY_TAKE,
-                                  ret->msg_str->str,
-                                  ret->msg_str->len);
+                                  action->msg_str->str,
+                                  action->msg_str->len);
 
-        g_string_free (ret->msg_str, FALSE);
-        ret->msg_str = NULL;
+        g_string_free (action->msg_str, FALSE);
+        action->msg_str = NULL;
 }
 
 static void
@@ -818,6 +809,7 @@ gupnp_service_proxy_action_queue_task (GTask *task)
                                     action->msg,
                                     (SoupSessionCallback) action_task_got_response,
                                     task);
+        action->pending = TRUE;
 }
 
 /**


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