[tracker] Add libtracker-remote



commit 2b63b4b33a1a80bbd5ebeeaadd26f3cdf2c58846
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Mar 20 12:50:38 2016 +0100

    Add libtracker-remote
    
    This is yet another libtracker-sparql backend to connect to remote
    HTTP SPARQL endpoints. Connections are made explicitly through the
    tracker_sparql_connection_remote_new() API call, passing a server
    to connect to. This commit introduces support for
    application/sparql-results+json as specified in
    https://www.w3.org/TR/sparql11-results-json/. XML format will be
    handled next.
    
    Just readonly queries are supported, and provided there's no
    authentication schemes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=773031

 configure.ac                                       |   10 ++
 src/Makefile.am                                    |    1 +
 src/libtracker-remote/Makefile.am                  |   34 +++++
 src/libtracker-remote/tracker-json-cursor.vala     |  139 ++++++++++++++++++++
 src/libtracker-remote/tracker-remote.vala          |   80 +++++++++++
 src/libtracker-sparql-backend/Makefile.am          |    6 +-
 src/libtracker-sparql-backend/tracker-backend.vala |    4 +
 src/libtracker-sparql/tracker-connection.vala      |   10 ++
 8 files changed, 283 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index d7ce9a2..25dcc2e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -232,6 +232,8 @@ GSTREAMER_REQUIRED=0.10.31
 GUPNP_DLNA_REQUIRED=0.9.4
 LIBPNG_REQUIRED=1.2
 LIBMEDIAART_REQUIRED=1.9.0
+JSON_GLIB_REQUIRED=1.0
+LIBSOUP_REQUIRED=2.40
 
 # 3.6.11 for sqlite_backup API
 # 3.6.16 to fix test failures
@@ -285,6 +287,13 @@ LIBTRACKER_DIRECT_REQUIRED="glib-2.0     >= $GLIB_REQUIRED
 
 PKG_CHECK_MODULES(LIBTRACKER_DIRECT, [$LIBTRACKER_DIRECT_REQUIRED])
 
+# Check requirements for libtracker-remote
+LIBTRACKER_REMOTE_REQUIRED="glib-2.0       >= $GLIB_REQUIRED
+                            libsoup-2.4    >= $LIBSOUP_REQUIRED
+                            json-glib-1.0  >= $JSON_GLIB_REQUIRED"
+
+PKG_CHECK_MODULES(LIBTRACKER_REMOTE, [$LIBTRACKER_REMOTE_REQUIRED])
+
 # Check requirements for libtracker-extract
 LIBTRACKER_EXTRACT_REQUIRED="glib-2.0     >= $GLIB_REQUIRED
                              gio-unix-2.0 >= $GLIB_REQUIRED
@@ -2622,6 +2631,7 @@ AC_CONFIG_FILES([
        src/libtracker-control/tracker-control.pc
        src/libtracker-data/Makefile
        src/libtracker-direct/Makefile
+       src/libtracker-remote/Makefile
        src/libtracker-sparql-backend/Makefile
        src/libtracker-fts/Makefile
        src/libtracker-extract/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index ae3be69..532165a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ SUBDIRS =                                              \
        libtracker-bus                                 \
        libtracker-data                                \
        libtracker-direct                              \
+       libtracker-remote                              \
        libtracker-sparql-backend                      \
        libtracker-extract                             \
        libtracker-miner                               \
diff --git a/src/libtracker-remote/Makefile.am b/src/libtracker-remote/Makefile.am
new file mode 100644
index 0000000..b92ddc2
--- /dev/null
+++ b/src/libtracker-remote/Makefile.am
@@ -0,0 +1,34 @@
+noinst_LTLIBRARIES = libtracker-remote.la
+
+AM_VALAFLAGS =                                         \
+       --includedir=libtracker-remote                 \
+       --header tracker-remote.h                      \
+       --vapi tracker-remote.vapi                     \
+       --pkg gio-2.0                                  \
+       --pkg libsoup-2.4                              \
+       --pkg json-glib-1.0                            \
+       $(BUILD_VALAFLAGS)                             \
+       $(top_srcdir)/src/libtracker-sparql/tracker-sparql-$(TRACKER_API_VERSION).vapi
+
+AM_CPPFLAGS =                                          \
+       $(BUILD_VALACFLAGS)                            \
+       -I$(top_srcdir)/src                            \
+       -I$(top_builddir)/src                          \
+       $(LIBTRACKER_REMOTE_CFLAGS)
+
+libtracker_remote_la_SOURCES =                         \
+       tracker-json-cursor.vala                       \
+       tracker-remote.vala
+
+libtracker_remote_la_LIBADD =                          \
+       $(BUILD_LIBS)                                  \
+       $(LIBTRACKER_REMOTE_LIBS)
+
+noinst_HEADERS =                                       \
+       tracker-remote.h
+
+BUILT_SOURCES =                                        \
+       libtracker_remote_la_vala.stamp
+
+DISTCLEANFILES =                                       \
+       libtracker_remote_la_vala.stamp
diff --git a/src/libtracker-remote/tracker-json-cursor.vala b/src/libtracker-remote/tracker-json-cursor.vala
new file mode 100644
index 0000000..e464947
--- /dev/null
+++ b/src/libtracker-remote/tracker-json-cursor.vala
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+public class Tracker.Remote.JsonCursor : Tracker.Sparql.Cursor {
+       internal Json.Parser _parser;
+       internal Json.Array _vars;
+       internal Json.Array _results;
+       internal Json.Object _cur_row;
+       internal uint _cur_idx = 0;
+       internal bool _started_iterating = false;
+
+       const string XSD_NS = "http://www.w3.org/2001/XMLSchema#";;
+
+       public JsonCursor (string document, long length) throws GLib.Error {
+               var parser = new Json.Parser ();
+               parser.load_from_data (document, length);
+
+               var root = parser.get_root ().get_object ();
+               var head = root.get_object_member ("head");
+               var results = root.get_object_member ("results");
+
+               _parser = parser;
+               _vars = head.get_array_member ("vars");
+               _results = results.get_array_member ("bindings");
+               _started_iterating = false;
+       }
+
+       public override int n_columns {
+               get { return (int) _vars.get_length (); }
+       }
+
+       public override Sparql.ValueType get_value_type (int column) requires (_cur_row != null) {
+               var col_node = _cur_row.get_member (get_variable_name (column));
+
+               if (col_node == null)
+                       return Sparql.ValueType.UNBOUND;
+
+               var object = col_node.get_object ();//_cur_row.get_object_member (get_variable_name (column));
+               unowned string str = object.get_string_member ("type");
+
+               switch (str) {
+               case "uri":
+                       return Sparql.ValueType.URI;
+               case "bnode":
+                       return Sparql.ValueType.BLANK_NODE;
+               case "literal": {
+                       var node = object.get_member ("datatype");
+
+                       if (node == null)
+                               return Sparql.ValueType.STRING;
+
+                       str = node.get_string ();
+
+                       switch (str) {
+                       case XSD_NS + "byte":
+                       case XSD_NS + "int":
+                       case XSD_NS + "integer":
+                       case XSD_NS + "long":
+                               return Sparql.ValueType.INTEGER;
+                       case XSD_NS + "decimal":
+                       case XSD_NS + "double":
+                               return Sparql.ValueType.DOUBLE;
+                       case XSD_NS + "dateTime":
+                               return Sparql.ValueType.DATETIME;
+                       default:
+                               return Sparql.ValueType.STRING;
+                       }
+               }
+
+               default:
+                       return Sparql.ValueType.STRING;
+               }
+       }
+
+       public override unowned string? get_variable_name (int column) {
+               return _vars.get_string_element (column);
+       }
+
+       public override unowned string? get_string (int column, out long length = null) requires (_cur_row != 
null) {
+               var col_node = _cur_row.get_member (get_variable_name (column));
+               length = 0;
+
+               if (col_node == null)
+                       return null;
+
+               var object = col_node.get_object ();
+
+               if (object == null)
+                       return null;
+
+               unowned string str = object.get_string_member ("value");
+               length = str.length;
+               return str;
+       }
+
+       public override bool next (Cancellable? cancellable = null) throws IOError, GLib.Error {
+               if (_started_iterating)
+                       _cur_idx++;
+
+               if (_cur_idx >= _results.get_length ())
+                       return false;
+
+               if (cancellable != null && cancellable.is_cancelled ())
+                       throw new IOError.CANCELLED ("Operation was cancelled");
+
+               _started_iterating = true;
+               _cur_row = _results.get_object_element (_cur_idx);
+               return true;
+       }
+
+       public async override bool next_async (Cancellable? cancellable = null) throws IOError, GLib.Error {
+               return next (cancellable);
+       }
+
+       public override void rewind () {
+               _started_iterating = false;
+       }
+
+       public override void close () {
+       }
+}
diff --git a/src/libtracker-remote/tracker-remote.vala b/src/libtracker-remote/tracker-remote.vala
new file mode 100644
index 0000000..395b1f6
--- /dev/null
+++ b/src/libtracker-remote/tracker-remote.vala
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 Carlos Garnacho <carlosg gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+public class Tracker.Remote.Connection : Tracker.Sparql.Connection {
+       internal Soup.Session _session;
+       internal string _base_uri;
+
+       const string JSON_TYPE = "application/sparql-results+json";
+
+       public Connection (string base_uri) {
+               _base_uri = base_uri;
+               _session = new Soup.Session ();
+       }
+
+       private Soup.Message create_request (string sparql) {
+               var uri = _base_uri + sparql;
+               var message = new Soup.Message ("GET", uri);
+               var headers = message.request_headers;
+
+               headers.append ("Accept", JSON_TYPE);
+
+               return message;
+       }
+
+       private Sparql.Cursor create_cursor (Soup.Message message) throws GLib.Error, Sparql.Error {
+               string document = (string) message.response_body.flatten ().data;
+
+               if (message.status_code != Soup.Status.OK) {
+                       throw new Sparql.Error.UNSUPPORTED ("Unhandled status code %u, document is: %s",
+                                                           message.status_code, document);
+               }
+
+               var headers = message.response_headers;
+               var content_type = headers.get_content_type (null);
+               long length = document.length;
+
+               if (content_type == JSON_TYPE) {
+                       return new Tracker.Remote.JsonCursor (document, length);
+               } else {
+                       throw new Sparql.Error.UNSUPPORTED ("Unknown content type '%s', document is: %s", 
content_type, document);
+               }
+       }
+
+       public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws GLib.Error, 
Sparql.Error, IOError {
+               var message = create_request (sparql);
+
+               _session.send_message (message);
+
+               if (cancellable != null && cancellable.is_cancelled ())
+                       throw new IOError.CANCELLED ("Operation was cancelled");
+
+               return create_cursor (message);
+       }
+
+       public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws 
GLib.Error, Sparql.Error, IOError {
+               var message = create_request (sparql);
+
+               yield _session.send_async (message, cancellable);
+
+               return create_cursor (message);
+       }
+}
diff --git a/src/libtracker-sparql-backend/Makefile.am b/src/libtracker-sparql-backend/Makefile.am
index 0db7186..8d7934d 100644
--- a/src/libtracker-sparql-backend/Makefile.am
+++ b/src/libtracker-sparql-backend/Makefile.am
@@ -5,12 +5,14 @@ AM_VALAFLAGS =                                         \
        $(BUILD_VALAFLAGS)                             \
        $(top_srcdir)/src/libtracker-sparql/tracker-sparql-$(TRACKER_API_VERSION).vapi \
        $(top_srcdir)/src/libtracker-bus/tracker-bus.vapi \
-       $(top_srcdir)/src/libtracker-direct/tracker-direct.vapi
+       $(top_srcdir)/src/libtracker-direct/tracker-direct.vapi \
+       $(top_srcdir)/src/libtracker-remote/tracker-remote.vapi
 
 AM_CPPFLAGS =                                          \
        $(BUILD_VALACFLAGS)                            \
        -I$(top_srcdir)/src                            \
        -I$(top_builddir)/src                          \
+       $(LIBTRACKER_REMOTE_CFLAGS)                    \
        $(LIBTRACKER_SPARQL_CFLAGS)
 
 libtracker_sparql_@TRACKER_API_VERSION@_la_SOURCES =   \
@@ -20,7 +22,9 @@ libtracker_sparql_@TRACKER_API_VERSION@_la_LIBADD =    \
        $(top_builddir)/src/libtracker-sparql/libtracker-sparql.la \
        $(top_builddir)/src/libtracker-bus/libtracker-bus.la \
        $(top_builddir)/src/libtracker-direct/libtracker-direct.la \
+       $(top_builddir)/src/libtracker-remote/libtracker-remote.la \
        $(BUILD_LIBS)                                  \
+       $(LIBTRACKER_REMOTE_LIBS)                      \
        $(LIBTRACKER_SPARQL_LIBS)
 
 libtracker_sparql_@TRACKER_API_VERSION@_la_LDFLAGS =   \
diff --git a/src/libtracker-sparql-backend/tracker-backend.vala 
b/src/libtracker-sparql-backend/tracker-backend.vala
index e3fdc2f..6d7e982 100644
--- a/src/libtracker-sparql-backend/tracker-backend.vala
+++ b/src/libtracker-sparql-backend/tracker-backend.vala
@@ -409,3 +409,7 @@ public async static Tracker.Sparql.Connection tracker_sparql_connection_get_dire
 public static Tracker.Sparql.Connection tracker_sparql_connection_get_direct (Cancellable? cancellable = 
null) throws Tracker.Sparql.Error, IOError, DBusError, SpawnError {
        return Tracker.Sparql.Backend.get_internal (cancellable);
 }
+
+public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string url_base) {
+       return new Tracker.Remote.Connection (url_base);
+}
diff --git a/src/libtracker-sparql/tracker-connection.vala b/src/libtracker-sparql/tracker-connection.vala
index ad97f98..b6e7fe9 100644
--- a/src/libtracker-sparql/tracker-connection.vala
+++ b/src/libtracker-sparql/tracker-connection.vala
@@ -211,6 +211,16 @@ public abstract class Tracker.Sparql.Connection : Object {
        public extern static new Connection get_direct (Cancellable? cancellable = null) throws Sparql.Error, 
IOError, DBusError, SpawnError;
 
        /**
+        * tracker_sparql_connection_remote_new:
+        *
+        * Returns: a new remote #TrackerSparqlConnection. Call g_object_unref() on the
+        * object when no longer used.
+        *
+        * Since: 1.12
+        */
+       public extern static new Connection remote_new (string uri_base);
+
+       /**
         * tracker_sparql_connection_query:
         * @self: a #TrackerSparqlConnection
         * @sparql: string containing the SPARQL query


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