summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2013-04-05 11:08:36 -0700
committerDavid Schleef <ds@schleef.org>2013-04-05 11:08:36 -0700
commitb1c18eaba06171ad38d9489be55243a2eec6ea2d (patch)
tree7d4e7e855bdfc3fe946bbf6844750fc2ae6b3915
parentb4a3617d764c57ee94596177916ced251909a43d (diff)
transaction: add json serialization
-rw-r--r--gst-streaming-server/gss-transaction.c245
-rw-r--r--gst-streaming-server/gss-transaction.h2
2 files changed, 247 insertions, 0 deletions
diff --git a/gst-streaming-server/gss-transaction.c b/gst-streaming-server/gss-transaction.c
index a942dd7..f0f7744 100644
--- a/gst-streaming-server/gss-transaction.c
+++ b/gst-streaming-server/gss-transaction.c
@@ -24,6 +24,8 @@
#include "gss-transaction.h"
#include <string.h>
+#include <json-glib/json-glib.h>
+
void
gss_transaction_redirect (GssTransaction * t, const char *target)
@@ -81,3 +83,246 @@ gss_transaction_delay (GssTransaction * t, int msec)
soup_server_pause_message (t->soupserver, t->msg);
g_timeout_add (msec, unpause, new_t);
}
+
+
+
+
+/* some stuff copied from json-glib because it needs a one-line
+ * modification to include all properties, not just non-default ones */
+
+static JsonNode *gss_json_serialize_pspec (const GValue * real_value,
+ GParamSpec * pspec);
+
+
+static JsonObject *
+gss_json_gobject_dump (GObject * gobject)
+{
+ JsonSerializableIface *iface = NULL;
+ JsonSerializable *serializable = NULL;
+ gboolean list_properties = FALSE;
+ gboolean serialize_property = FALSE;
+ gboolean get_property = FALSE;
+ JsonObject *object;
+ GParamSpec **pspecs;
+ guint n_pspecs, i;
+
+ if (JSON_IS_SERIALIZABLE (gobject)) {
+ serializable = JSON_SERIALIZABLE (gobject);
+ iface = JSON_SERIALIZABLE_GET_IFACE (gobject);
+ list_properties = (iface->list_properties != NULL);
+ serialize_property = (iface->serialize_property != NULL);
+ get_property = (iface->get_property != NULL);
+ }
+
+ object = json_object_new ();
+
+ if (list_properties)
+ pspecs = json_serializable_list_properties (serializable, &n_pspecs);
+ else
+ pspecs =
+ g_object_class_list_properties (G_OBJECT_GET_CLASS (gobject),
+ &n_pspecs);
+
+ for (i = 0; i < n_pspecs; i++) {
+ GParamSpec *pspec = pspecs[i];
+ GValue value = { 0, };
+ JsonNode *node = NULL;
+
+ /* read only what we can */
+ if (!(pspec->flags & G_PARAM_READABLE))
+ continue;
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (get_property)
+ json_serializable_get_property (serializable, pspec, &value);
+ else
+ g_object_get_property (gobject, pspec->name, &value);
+
+ /* if there is a serialization vfunc, then it is completely responsible
+ * for serializing the property, possibly by calling the implementation
+ * of the default JsonSerializable interface through chaining up
+ */
+ if (serialize_property) {
+ node = json_serializable_serialize_property (serializable,
+ pspec->name, &value, pspec);
+ } else
+ node = gss_json_serialize_pspec (&value, pspec);
+
+ if (node)
+ json_object_set_member (object, pspec->name, node);
+
+ g_value_unset (&value);
+ }
+
+ g_free (pspecs);
+
+ return object;
+}
+
+static JsonNode *
+gss_json_gobject_serialize (GObject * gobject)
+{
+ JsonNode *retval;
+
+ g_return_val_if_fail (G_IS_OBJECT (gobject), NULL);
+
+ retval = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (retval, gss_json_gobject_dump (gobject));
+
+ return retval;
+}
+
+gchar *
+gss_json_gobject_to_data (GObject * gobject, gsize * length)
+{
+ JsonGenerator *gen;
+ JsonNode *root;
+ gchar *data;
+
+ g_return_val_if_fail (G_OBJECT (gobject), NULL);
+
+ root = gss_json_gobject_serialize (gobject);
+
+ gen = g_object_new (JSON_TYPE_GENERATOR,
+ "root", root, "pretty", TRUE, "indent", 2, NULL);
+
+ data = json_generator_to_data (gen, length);
+ g_object_unref (gen);
+
+ json_node_free (root);
+
+ return data;
+}
+
+static JsonNode *
+gss_json_serialize_pspec (const GValue * real_value, GParamSpec * pspec)
+{
+ JsonNode *retval = NULL;
+ GValue value = { 0, };
+ JsonNodeType node_type;
+
+ switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (real_value))) {
+ case G_TYPE_INT64:
+ case G_TYPE_BOOLEAN:
+ case G_TYPE_DOUBLE:
+ /* JSON native types */
+ retval = json_node_new (JSON_NODE_VALUE);
+ g_value_init (&value, G_VALUE_TYPE (real_value));
+ g_value_copy (real_value, &value);
+ json_node_set_value (retval, &value);
+ g_value_unset (&value);
+ break;
+
+ case G_TYPE_STRING:
+ /* strings might be NULL, so we handle it differently */
+ if (!g_value_get_string (real_value))
+ retval = json_node_new (JSON_NODE_NULL);
+ else {
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_string (retval, g_value_get_string (real_value));
+ break;
+ }
+ break;
+
+ case G_TYPE_INT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_int (real_value));
+ break;
+
+ case G_TYPE_FLOAT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_double (retval, g_value_get_float (real_value));
+ break;
+
+ case G_TYPE_BOXED:
+ if (G_VALUE_HOLDS (real_value, G_TYPE_STRV)) {
+ gchar **strv = g_value_get_boxed (real_value);
+ gint i, strv_len;
+ JsonArray *array;
+
+ strv_len = g_strv_length (strv);
+ array = json_array_sized_new (strv_len);
+
+ for (i = 0; i < strv_len; i++) {
+ JsonNode *str = json_node_new (JSON_NODE_VALUE);
+
+ json_node_set_string (str, strv[i]);
+ json_array_add_element (array, str);
+ }
+
+ retval = json_node_new (JSON_NODE_ARRAY);
+ json_node_take_array (retval, array);
+ } else if (json_boxed_can_serialize (G_VALUE_TYPE (real_value),
+ &node_type)) {
+ gpointer boxed = g_value_get_boxed (real_value);
+
+ retval = json_boxed_serialize (G_VALUE_TYPE (real_value), boxed);
+ } else
+ g_warning ("Boxed type '%s' is not handled by JSON-GLib",
+ g_type_name (G_VALUE_TYPE (real_value)));
+ break;
+
+ case G_TYPE_UINT:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_uint (real_value));
+ break;
+
+ case G_TYPE_LONG:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_long (real_value));
+ break;
+
+ case G_TYPE_ULONG:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_long (real_value));
+ break;
+
+ case G_TYPE_CHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+#if GLIB_CHECK_VERSION (2, 31, 0)
+ json_node_set_int (retval, g_value_get_schar (real_value));
+#else
+ json_node_set_int (retval, g_value_get_char (real_value));
+#endif
+ break;
+
+ case G_TYPE_UCHAR:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_uchar (real_value));
+ break;
+
+ case G_TYPE_ENUM:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_enum (real_value));
+ break;
+
+ case G_TYPE_FLAGS:
+ retval = json_node_new (JSON_NODE_VALUE);
+ json_node_set_int (retval, g_value_get_flags (real_value));
+ break;
+
+ case G_TYPE_OBJECT:
+ {
+ GObject *object = g_value_get_object (real_value);
+
+ if (object != NULL) {
+ retval = json_node_new (JSON_NODE_OBJECT);
+ json_node_take_object (retval, gss_json_gobject_dump (object));
+ } else
+ retval = json_node_new (JSON_NODE_NULL);
+ }
+ break;
+
+ case G_TYPE_NONE:
+ retval = json_node_new (JSON_NODE_NULL);
+ break;
+
+ default:
+ g_warning ("Unsupported type `%s'",
+ g_type_name (G_VALUE_TYPE (real_value)));
+ break;
+ }
+
+ return retval;
+}
diff --git a/gst-streaming-server/gss-transaction.h b/gst-streaming-server/gss-transaction.h
index eda1910..363e909 100644
--- a/gst-streaming-server/gss-transaction.h
+++ b/gst-streaming-server/gss-transaction.h
@@ -48,6 +48,8 @@ void gss_transaction_redirect (GssTransaction * t, const char *target);
void gss_transaction_error (GssTransaction * t, const char *message);
void gss_transaction_delay (GssTransaction *t, int msec);
+gchar *gss_json_gobject_to_data (GObject * gobject, gsize * length);
+
G_END_DECLS