[gupnp/wip/phako/initable: 3/4] ServiceIntrospection: Implement GInitable




commit 544d8d1a0be65f748daff380bebc3bf6ad586b56
Author: Jens Georg <mail jensge org>
Date:   Sun Oct 24 22:29:20 2021 +0200

    ServiceIntrospection: Implement GInitable
    
    Fixes #53

 libgupnp/gupnp-error.c                         |  19 +++++
 libgupnp/gupnp-error.h                         |  14 ++++
 libgupnp/gupnp-service-info.c                  |   2 +-
 libgupnp/gupnp-service-introspection-private.h |   2 +-
 libgupnp/gupnp-service-introspection.c         | 110 ++++++++++++++++++-------
 5 files changed, 113 insertions(+), 34 deletions(-)
---
diff --git a/libgupnp/gupnp-error.c b/libgupnp/gupnp-error.c
index 7dcf5db..d93dfe0 100644
--- a/libgupnp/gupnp-error.c
+++ b/libgupnp/gupnp-error.c
@@ -107,6 +107,25 @@ gupnp_rootdevice_error_quark (void)
         return quark;
 }
 
+/**
+ * GUPNP_SERVICE_INTROSPECTION_ERROR:
+ *
+ * The #GQuark uniquely used by GUPnP ServiceIntrospection errors.
+ *
+ * Returns: a #GQuark uniquely used by GUPnP ServiceIntrospection creation errors.
+ */
+GQuark
+gupnp_service_introspection_error_quark (void)
+{
+        static GQuark quark = 0;
+
+        if (!quark)
+                quark = g_quark_from_static_string ("gupnp-root-device-error");
+
+        return quark;
+}
+
+
 /* Soup status code => GUPnPServerError */
 static int
 code_from_status_code (int status_code)
diff --git a/libgupnp/gupnp-error.h b/libgupnp/gupnp-error.h
index cd26e04..d3a7a43 100644
--- a/libgupnp/gupnp-error.h
+++ b/libgupnp/gupnp-error.h
@@ -127,6 +127,20 @@ typedef enum {
         GUPNP_ROOT_DEVICE_ERROR_FAIL
 } GUPnPRootdeviceError;
 
+GQuark
+gupnp_service_introspection_error_quark (void) G_GNUC_CONST;
+
+#define GUPNP_SERVICE_INTROSPECTION_ERROR                                      \
+        (gupnp_service_introspection_error_quark ())
+
+/**
+ * GUPnPServiceIntrospectionError:
+ * @GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER@: Unknown error
+ */
+typedef enum
+{
+        GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER,
+} GUPnPServiceIntrospectionError;
 G_END_DECLS
 
 #endif /* GUPNP_ERROR_H */
diff --git a/libgupnp/gupnp-service-info.c b/libgupnp/gupnp-service-info.c
index 9a9f4de..1194268 100644
--- a/libgupnp/gupnp-service-info.c
+++ b/libgupnp/gupnp-service-info.c
@@ -595,7 +595,7 @@ got_scpd_url (G_GNUC_UNUSED SoupSession *session,
                 scpd = xmlRecoverMemory (msg->response_body->data,
                                          msg->response_body->length);
                 if (scpd) {
-                        introspection = gupnp_service_introspection_new (scpd);
+                        introspection = gupnp_service_introspection_new (scpd, NULL);
 
                         xmlFreeDoc (scpd);
                 }
diff --git a/libgupnp/gupnp-service-introspection-private.h b/libgupnp/gupnp-service-introspection-private.h
index 63741ca..0e73a98 100644
--- a/libgupnp/gupnp-service-introspection-private.h
+++ b/libgupnp/gupnp-service-introspection-private.h
@@ -14,6 +14,6 @@
 #include "gupnp-service-introspection.h"
 
 G_GNUC_INTERNAL GUPnPServiceIntrospection *
-gupnp_service_introspection_new (xmlDoc *scpd);
+gupnp_service_introspection_new (xmlDoc *scpd, GError **error);
 
 #endif /* GUPNP_SERVICE_INTROSPECTION_PRIVATE_H */
diff --git a/libgupnp/gupnp-service-introspection.c b/libgupnp/gupnp-service-introspection.c
index a614b7f..68f09d7 100644
--- a/libgupnp/gupnp-service-introspection.c
+++ b/libgupnp/gupnp-service-introspection.c
@@ -37,6 +37,7 @@
 
 #include "gupnp-service-introspection.h"
 #include "gupnp-service-introspection-private.h"
+#include "gupnp-error.h"
 #include "xml-util.h"
 #include "gvalue-util.h"
 #include "gupnp-types.h"
@@ -49,6 +50,7 @@ struct _GUPnPServiceIntrospection {
 };
 
 struct _GUPnPServiceIntrospectionPrivate {
+        xmlDoc *scpd;
         GList *variables;
         GList *actions;
 
@@ -60,17 +62,27 @@ struct _GUPnPServiceIntrospectionPrivate {
 typedef struct _GUPnPServiceIntrospectionPrivate
                 GUPnPServiceIntrospectionPrivate;
 
-G_DEFINE_TYPE_WITH_PRIVATE (GUPnPServiceIntrospection,
-                            gupnp_service_introspection,
-                            G_TYPE_OBJECT)
+
+static GInitableIface *initable_parent_iface = NULL;
+static void
+gupnp_service_introspection_initable_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_EXTENDED (
+        GUPnPServiceIntrospection,
+        gupnp_service_introspection,
+        G_TYPE_OBJECT,
+        0,
+        G_ADD_PRIVATE (GUPnPServiceIntrospection) G_IMPLEMENT_INTERFACE (
+                G_TYPE_INITABLE,
+                gupnp_service_introspection_initable_iface_init))
 enum {
         PROP_0,
         PROP_SCPD
 };
 
-static void
+static gboolean
 construct_introspection_info (GUPnPServiceIntrospection *introspection,
-                              xmlDoc                    *scpd);
+                              GError                    **error);
 
 /**
  * gupnp_service_state_variable_info_free:
@@ -123,12 +135,12 @@ gupnp_service_introspection_set_property (GObject      *object,
         GUPnPServiceIntrospection *introspection;
 
         introspection = GUPNP_SERVICE_INTROSPECTION (object);
+        GUPnPServiceIntrospectionPrivate *priv =
+                gupnp_service_introspection_get_instance_private (introspection);
 
         switch (property_id) {
         case PROP_SCPD:
-                /* Construct introspection data */
-                construct_introspection_info (introspection,
-                                              g_value_get_pointer (value));
+                priv->scpd = g_value_get_pointer (value);
                 break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -220,6 +232,42 @@ gupnp_service_introspection_finalize (GObject *object)
                 g_list_free (priv->action_names);
 }
 
+static gboolean
+gupnp_service_introspection_initable_init (GInitable *initable,
+                                           GCancellable *cancellable,
+                                           GError **error)
+{
+        GUPnPServiceIntrospection *self =
+                GUPNP_SERVICE_INTROSPECTION (initable);
+        GUPnPServiceIntrospectionPrivate *priv =
+                gupnp_service_introspection_get_instance_private (self);
+
+        if (priv->scpd == NULL) {
+                g_set_error_literal (
+                        error,
+                        GUPNP_SERVICE_INTROSPECTION_ERROR,
+                        GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER,
+                        "SCDP is required for creating a ServiceIntrospection");
+
+                return FALSE;
+        }
+
+        if (priv->actions != NULL || priv->variables != NULL)
+                return TRUE;
+
+        return construct_introspection_info (self, error);
+}
+
+static void
+gupnp_service_introspection_initable_iface_init (gpointer g_iface,
+                                                 gpointer iface_data)
+{
+        GInitableIface *iface = (GInitableIface *) g_iface;
+        initable_parent_iface = g_type_interface_peek_parent (iface);
+        iface->init = gupnp_service_introspection_initable_init;
+}
+
+
 static void
 gupnp_service_introspection_class_init (GUPnPServiceIntrospectionClass *klass)
 {
@@ -687,19 +735,16 @@ get_state_variables (xmlNode *list_element)
  * Creates the #GHashTable's of action and state variable information
  *
  * */
-static void
+static gboolean
 construct_introspection_info (GUPnPServiceIntrospection *introspection,
-                              xmlDoc                    *scpd)
+                              GError **error)
 {
         xmlNode *element;
         GUPnPServiceIntrospectionPrivate *priv;
 
-        g_return_if_fail (scpd != NULL);
-
         priv = gupnp_service_introspection_get_instance_private (introspection);
-
         /* Get actionList element */
-        element = xml_util_get_element ((xmlNode *) scpd,
+        element = xml_util_get_element ((xmlNode *) priv->scpd,
                                         "scpd",
                                         "actionList",
                                         NULL);
@@ -707,12 +752,23 @@ construct_introspection_info (GUPnPServiceIntrospection *introspection,
                 priv->actions = get_actions (element);
 
         /* Get serviceStateTable element */
-        element = xml_util_get_element ((xmlNode *) scpd,
+        element = xml_util_get_element ((xmlNode *) priv->scpd,
                                         "scpd",
                                         "serviceStateTable",
                                         NULL);
         if (element)
                 priv->variables = get_state_variables (element);
+
+        if (priv->actions == NULL && priv->variables == NULL) {
+                g_set_error_literal (error,
+                                     GUPNP_SERVICE_INTROSPECTION_ERROR,
+                                     GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER,
+                                     "Service description has neither actions "
+                                     "nor variables");
+                return FALSE;
+        }
+
+        return TRUE;
 }
 
 static void
@@ -746,26 +802,16 @@ collect_variable_names (gpointer data,
  * Return value: A new #GUPnPServiceIntrospection.
  **/
 GUPnPServiceIntrospection *
-gupnp_service_introspection_new (xmlDoc *scpd)
+gupnp_service_introspection_new (xmlDoc *scpd, GError **error)
 {
-        GUPnPServiceIntrospection *introspection;
-        GUPnPServiceIntrospectionPrivate *priv;
-
         g_return_val_if_fail (scpd != NULL, NULL);
 
-        introspection = g_object_new (GUPNP_TYPE_SERVICE_INTROSPECTION,
-                                      "scpd", scpd,
-                                      NULL);
-
-        priv = gupnp_service_introspection_get_instance_private (introspection);
-
-        if (priv->actions == NULL &&
-            priv->variables == NULL) {
-                g_object_unref (introspection);
-                introspection = NULL;
-        }
-
-        return introspection;
+        return g_initable_new (GUPNP_TYPE_SERVICE_INTROSPECTION,
+                                        NULL,
+                                        error,
+                                        "scpd",
+                                        scpd,
+                                        NULL);
 }
 
 /**


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