[gnome-documents] miner: turn the miner into an activatable service



commit a5984954813d80498312949613ca7b6712f60b5e
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Tue Aug 23 14:10:59 2011 -0400

    miner: turn the miner into an activatable service
    
    And start it together with the documents application.
    We don't have any way to get changes from resources from libgdata yet,
    so we'll have to periodically retrigger the miner from the application.

 data/Makefile.am                               |   15 ++-
 data/org.gnome.Documents.GDataMiner.service.in |    3 +
 src/Makefile-js.am                             |    1 +
 src/gDataMiner.js                              |   41 ++++++
 src/miner/gd-gdata-miner.c                     |  164 ++++++++++++++----------
 src/miner/gd-gdata-miner.h                     |   12 ++-
 src/miner/gdata-miner-main.c                   |  150 +++++++++++++++++++++-
 src/trackerModel.js                            |   17 ++-
 8 files changed, 323 insertions(+), 80 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 9225565..39500ae 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -4,6 +4,15 @@ desktop_in_files = gnome-documents.desktop.in
 
 @INTLTOOL_DESKTOP_RULE@
 
+servicedir = $(datadir)/dbus-1/services
+service_DATA = $(service_in_files:.service.in=.service)
+$(service_DATA): $(service_in_files) Makefile
+	$(AM_V_GEN)	\
+		[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
+		sed -e "s|\ libexecdir\@|$(libexecdir)|" $< > $  tmp && mv $  tmp $@
+
+service_in_files = org.gnome.Documents.GDataMiner.service.in
+
 gsettingsschema_in_files = org.gnome.documents.gschema.xml.in
 gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml)
 .PRECIOUS: $(gsettings_SCHEMAS)
@@ -18,9 +27,11 @@ dist_style_DATA = \
 
 EXTRA_DIST= \
     gnome-documents.desktop \
+    $(service_in_files) \
     $(desktop_in_files) \
-    $(gsettingsschame_in_files)
+    $(gsettingsschema_in_files)
 
 CLEANFILES = \
     $(desktop_DATA) \
-    $(gsettings_SCHEMAS)
+    $(gsettings_SCHEMAS) \
+    $(service_DATA)
diff --git a/data/org.gnome.Documents.GDataMiner.service.in b/data/org.gnome.Documents.GDataMiner.service.in
new file mode 100644
index 0000000..1e23823
--- /dev/null
+++ b/data/org.gnome.Documents.GDataMiner.service.in
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.Documents.GDataMiner
+Exec= libexecdir@/gd-tracker-gdata-miner
diff --git a/src/Makefile-js.am b/src/Makefile-js.am
index b12f87d..4f5a44c 100644
--- a/src/Makefile-js.am
+++ b/src/Makefile-js.am
@@ -2,6 +2,7 @@ jsdir = $(pkgdatadir)/js/
 dist_js_DATA = \
     application.js \
     docFactory.js \
+    gDataMiner.js \
     iconView.js \
     listView.js \
     main.js \
diff --git a/src/gDataMiner.js b/src/gDataMiner.js
new file mode 100644
index 0000000..8ce9a5c
--- /dev/null
+++ b/src/gDataMiner.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011 Red Hat, Inc.
+ *
+ * Gnome Documents is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Documents 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 General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Documents; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Cosimo Cecchi <cosimoc redhat com>
+ *
+ */
+
+const DBus = imports.dbus;
+
+const GDataMinerIface = {
+    name: 'org.gnome.Documents.GDataMiner',
+    methods: [{ name: 'RefreshDB',
+                inSignature: '' }]
+};
+
+const GDataMiner = function() {
+    this._init();
+};
+
+GDataMiner.prototype = {
+    _init: function() {
+        DBus.session.proxifyObject(this,
+                                   'org.gnome.Documents.GDataMiner',
+                                   '/org/gnome/Documents/GDataMiner');
+    }
+};
+DBus.proxifyPrototype(GDataMiner.prototype, GDataMinerIface);
diff --git a/src/miner/gd-gdata-miner.c b/src/miner/gd-gdata-miner.c
index 692887b..dac73b3 100644
--- a/src/miner/gd-gdata-miner.c
+++ b/src/miner/gd-gdata-miner.c
@@ -28,7 +28,7 @@
 
 #define DATASOURCE_URN "urn:nepomuk:datasource:86ec9bc9-c242-427f-aa19-77b5a2c9b6f0"
 
-G_DEFINE_TYPE (GdGDataMiner, gd_gdata_miner, TRACKER_TYPE_MINER)
+G_DEFINE_TYPE (GdGDataMiner, gd_gdata_miner, G_TYPE_OBJECT)
 
 struct _GdGDataMinerPrivate {
   GoaClient *client;
@@ -36,8 +36,19 @@ struct _GdGDataMinerPrivate {
   TrackerSparqlConnection *connection;
 
   GCancellable *cancellable;
+  GSimpleAsyncResult *result;
 };
 
+static void
+gd_gdata_miner_complete_error (GdGDataMiner *self,
+                               GError *error)
+{
+  g_assert (self->priv->result != NULL);
+
+  g_simple_async_result_take_error (self->priv->result, error);
+  g_simple_async_result_complete_in_idle (self->priv->result);
+}
+
 static gchar *
 _tracker_utils_format_into_graph (const gchar *graph)
 {
@@ -164,7 +175,7 @@ _tracker_utils_ensure_contact_resource (TrackerSparqlConnection *connection,
 
   insert_res = 
     tracker_sparql_connection_update_blank (connection, insert->str,
-                                            G_PRIORITY_DEFAULT, NULL, error);
+                                            G_PRIORITY_DEFAULT, cancellable, error);
 
   g_string_free (insert, TRUE);
 
@@ -318,12 +329,13 @@ _tracker_utils_iso8601_from_timestamp (gint64 timestamp)
 
 static void
 gd_gdata_miner_process_entry (GdGDataMiner *self,
-                              GDataDocumentsEntry *doc_entry)
+                              GDataDocumentsEntry *doc_entry,
+                              GError **error)
 {
   GDataEntry *entry = GDATA_ENTRY (doc_entry);
-  GError *error = NULL;
   gchar *resource;
   gchar *date, *resource_url;
+
   const gchar *path, *identifier, *class;
   GList *authors, *l;
   GDataAuthor *author;
@@ -351,28 +363,31 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
 
   resource = _tracker_sparql_connection_ensure_resource
     (self->priv->connection, 
-     self->priv->cancellable, &error,
+     self->priv->cancellable, error,
      resource_url, identifier,
      "nfo:RemoteDataObject",
      class,
      NULL);
 
-  if (error != NULL)
+  if (*error != NULL)
     goto out;
 
   _tracker_sparql_connection_insert_or_replace_triple
     (self->priv->connection, 
-     self->priv->cancellable, &error,
+     self->priv->cancellable, error,
      identifier, resource,
      "nie:description", gdata_entry_get_summary (entry));
 
+  if (*error != NULL)
+    goto out;
+
   _tracker_sparql_connection_insert_or_replace_triple
     (self->priv->connection, 
-     self->priv->cancellable, &error,
+     self->priv->cancellable, error,
      identifier, resource,
      "nie:title", gdata_entry_get_title (entry));
 
-  if (error != NULL)
+  if (*error != NULL)
     goto out;
 
   authors = gdata_entry_get_authors (entry);
@@ -383,51 +398,48 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
       author = l->data;
 
       contact_resource = _tracker_utils_ensure_contact_resource (self->priv->connection,
-                                                                 self->priv->cancellable, &error,
+                                                                 self->priv->cancellable, error,
                                                                  gdata_author_get_email_address (author),
                                                                  gdata_author_get_name (author));
 
-      if (error != NULL)
+      if (*error != NULL)
         goto out;
 
       _tracker_sparql_connection_insert_or_replace_triple
         (self->priv->connection, 
-         self->priv->cancellable, &error,
+         self->priv->cancellable, error,
          identifier, resource,
          "nco:creator", contact_resource);
 
+      if (*error != NULL)
+        goto out;
+
       g_free (contact_resource);
     }
 
   date = _tracker_utils_iso8601_from_timestamp (gdata_entry_get_published (entry));
   _tracker_sparql_connection_insert_or_replace_triple
     (self->priv->connection, 
-     self->priv->cancellable, &error,
+     self->priv->cancellable, error,
      identifier, resource,
      "nie:contentCreated", date);
   g_free (date);
 
-  if (error != NULL)
+  if (*error != NULL)
     goto out;
 
   date = _tracker_utils_iso8601_from_timestamp (gdata_entry_get_updated (entry));
   _tracker_sparql_connection_insert_or_replace_triple
     (self->priv->connection, 
-     self->priv->cancellable, &error,
+     self->priv->cancellable, error,
      identifier, resource,
      "nie:contentLastModified", date);
   g_free (date);
 
-  if (error != NULL)
+  if (*error != NULL)
     goto out;
 
  out:
-  if (error != NULL)
-    {
-      g_printerr ("Error updating tracker: %s\n", error->message);
-      g_error_free (error);
-    }
-
   g_free (resource_url);
 }
 
@@ -444,22 +456,30 @@ gd_gdata_miner_query (GdGDataMiner *self)
     (self->priv->service, query, 
      self->priv->cancellable, NULL, NULL, &error);
 
+  g_object_unref (query);
+
   if (error != NULL)
     {
-      g_printerr ("Error executing query: %s\n", error->message);
-
-      g_error_free (error);
-      g_object_unref (query);
-
+      gd_gdata_miner_complete_error (self, error);
       return;
    }
 
   entries = gdata_feed_get_entries (GDATA_FEED (feed));
   for (l = entries; l != NULL; l = l->next)
-    gd_gdata_miner_process_entry (self, l->data);
+    {
+      gd_gdata_miner_process_entry (self, l->data, &error);
+
+      if (error != NULL)
+        {
+          gd_gdata_miner_complete_error (self, error);
+          g_object_unref (feed);
+
+          return;
+        }
+    }
 
+  g_simple_async_result_complete_in_idle (self->priv->result);
   g_object_unref (feed);
-  g_object_unref (query);
 }
 
 static void
@@ -508,9 +528,7 @@ gd_gdata_miner_setup_account (GdGDataMiner *self,
 
   if (error != NULL)
     {
-      g_printerr ("Unable to initialize the tracker connection: %s\n", error->message);
-      g_error_free (error);
-
+      gd_gdata_miner_complete_error (self, error);
       return;
     }
 
@@ -529,13 +547,14 @@ client_ready_cb (GObject *source,
   const gchar *provider_type;
   GError *error = NULL;
   GList *accounts, *l;
+  gboolean found = FALSE;
 
   self->priv->client = goa_client_new_finish (res, &error);
 
   if (error != NULL)
     {
-      g_printerr ("Unable to get the GoaClient object: %s\n", error->message);
-      g_error_free (error);
+      gd_gdata_miner_complete_error (self, error);
+      return;
     }
 
   accounts = goa_client_get_accounts (self->priv->client);
@@ -555,39 +574,20 @@ client_ready_cb (GObject *source,
       if (g_strcmp0 (provider_type, "google") != 0)
         continue;
 
+      found = TRUE;
       gd_gdata_miner_setup_account (self, object);
     }
 
   g_list_free_full (accounts, g_object_unref);
-}
-
-static void
-gd_gdata_miner_started (TrackerMiner *miner)
-{
-  GdGDataMiner *self = GD_GDATA_MINER (miner);
-
-  goa_client_new (self->priv->cancellable, client_ready_cb, self);
-}
-
-static void
-gd_gdata_miner_stopped (TrackerMiner *miner)
-{
-  GdGDataMiner *self = GD_GDATA_MINER (miner);
-
-  g_cancellable_cancel (self->priv->cancellable);
-  g_cancellable_reset (self->priv->cancellable);
-}
-
-static void
-gd_gdata_miner_resumed (TrackerMiner *miner)
-{
-
-}
-
-static void
-gd_gdata_miner_paused (TrackerMiner *miner)
-{
 
+  if (!found)
+    {
+      gd_gdata_miner_complete_error (self,
+                                     g_error_new_literal (G_IO_ERROR,
+                                                          G_IO_ERROR_NOT_FOUND,
+                                                          "No GOA resource found supporting documents"));
+      return;
+    }
 }
 
 static void
@@ -598,6 +598,8 @@ gd_gdata_miner_dispose (GObject *object)
   g_clear_object (&self->priv->service);
   g_clear_object (&self->priv->client);
   g_clear_object (&self->priv->connection);
+  g_clear_object (&self->priv->cancellable);
+  g_clear_object (&self->priv->result);
 
   G_OBJECT_CLASS (gd_gdata_miner_parent_class)->dispose (object);
 }
@@ -612,16 +614,10 @@ gd_gdata_miner_init (GdGDataMiner *self)
 static void
 gd_gdata_miner_class_init (GdGDataMinerClass *klass)
 {
-  TrackerMinerClass *mclass = TRACKER_MINER_CLASS (klass);
   GObjectClass *oclass = G_OBJECT_CLASS (klass);
 
   oclass->dispose = gd_gdata_miner_dispose;
 
-  mclass->started = gd_gdata_miner_started;
-  mclass->stopped = gd_gdata_miner_stopped;
-  mclass->paused = gd_gdata_miner_paused;
-  mclass->resumed = gd_gdata_miner_resumed;
-
   g_type_class_add_private (klass, sizeof (GdGDataMinerPrivate));
 }
 
@@ -630,3 +626,35 @@ gd_gdata_miner_new (void)
 {
   return g_object_new (GD_TYPE_GDATA_MINER, NULL);
 }
+
+void
+gd_gdata_miner_refresh_db_async (GdGDataMiner *self,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+  self->priv->result = 
+    g_simple_async_result_new (G_OBJECT (self),
+                               callback, user_data,
+                               gd_gdata_miner_refresh_db_async);
+  self->priv->cancellable = 
+    (cancellable != NULL) ? g_object_ref (cancellable) : NULL;
+
+  goa_client_new (self->priv->cancellable, client_ready_cb, self);  
+}
+
+gboolean
+gd_gdata_miner_refresh_db_finish (GdGDataMiner *self,
+                                  GAsyncResult *res,
+                                  GError **error)
+{
+  GSimpleAsyncResult *simple_res = G_SIMPLE_ASYNC_RESULT (res);
+
+  g_assert (g_simple_async_result_is_valid (res, G_OBJECT (self),
+                                            gd_gdata_miner_refresh_db_async));
+
+  if (g_simple_async_result_propagate_error (simple_res, error))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/src/miner/gd-gdata-miner.h b/src/miner/gd-gdata-miner.h
index a8438dd..aabb014 100644
--- a/src/miner/gd-gdata-miner.h
+++ b/src/miner/gd-gdata-miner.h
@@ -54,17 +54,25 @@ typedef struct _GdGDataMinerClass GdGDataMinerClass;
 typedef struct _GdGDataMinerPrivate GdGDataMinerPrivate;
 
 struct _GdGDataMiner {
-  TrackerMiner parent;
+  GObject parent;
 
   GdGDataMinerPrivate *priv;
 };
 
 struct _GdGDataMinerClass {
-  TrackerMinerClass parent_class;
+  GObjectClass parent_class;
 };
 
 GdGDataMiner * gd_gdata_miner_new (void);
 
+void           gd_gdata_miner_refresh_db_async (GdGDataMiner *self,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       gd_gdata_miner_refresh_db_finish (GdGDataMiner *self,
+                                                 GAsyncResult *res,
+                                                 GError **error);
+
 G_END_DECLS
 
 #endif /* __GD_GDATA_MINER_H__ */
diff --git a/src/miner/gdata-miner-main.c b/src/miner/gdata-miner-main.c
index 615b437..308f804 100644
--- a/src/miner/gdata-miner-main.c
+++ b/src/miner/gdata-miner-main.c
@@ -24,23 +24,150 @@
 
 #include "gd-gdata-miner.h"
 
+#define BUS_NAME "org.gnome.Documents.GDataMiner"
+#define AUTOQUIT_TIMEOUT 5
+
+static const gchar introspection_xml[] =
+  "<node>"
+  "  <interface name='org.gnome.Documents.GDataMiner'>"
+  "    <method name='RefreshDB'>"
+  "    </method>"
+  "  </interface>"
+  "</node>";
+
+static GDBusNodeInfo *introspection_data = NULL;
+static GCancellable *cancellable = NULL;
+static GMainLoop *loop = NULL;
+static guint name_owner_id = 0;
+
 static gboolean
 signal_handler_cb (gpointer user_data)
 {
   GMainLoop *loop = user_data;
 
+  if (cancellable != NULL)
+    g_cancellable_cancel (cancellable);
+
   g_main_loop_quit (loop);
 
   return FALSE;
 }
 
+static void
+miner_refresh_db_ready_cb (GObject *source,
+                           GAsyncResult *res,
+                           gpointer user_data)
+{
+  GDBusMethodInvocation *invocation = user_data;
+  GError *error = NULL;
+
+  gd_gdata_miner_refresh_db_finish (GD_GDATA_MINER (source), res, &error);
+
+  if (error != NULL)
+    {
+      g_printerr ("Failed to refresh the DB cache: %s\n", error->message);
+      g_dbus_method_invocation_return_gerror (invocation, error);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_value (invocation, NULL);
+    }
+
+  g_object_unref (cancellable);
+  g_main_loop_quit (loop);
+}
+
+static void
+handle_refresh_db (GDBusMethodInvocation *invocation)
+{
+  GdGDataMiner *miner;
+
+  cancellable = g_cancellable_new ();
+  miner = gd_gdata_miner_new ();
+
+  gd_gdata_miner_refresh_db_async (miner, cancellable,
+                                   miner_refresh_db_ready_cb, invocation);
+
+  g_object_unref (miner);
+}
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+  if (g_strcmp0 (method_name, "RefreshDB") == 0)
+    handle_refresh_db (g_object_ref (invocation));
+  else
+    g_assert_not_reached ();
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+  handle_method_call,
+  NULL, /* get_property */
+  NULL, /* set_property */
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar *name,
+                 gpointer user_data)
+{
+  GError *error = NULL;
+
+  g_debug ("Connected to the session bus: %s", name);
+
+  g_dbus_connection_register_object (connection,
+                                     "/org/gnome/Documents/GDataMiner",
+                                     introspection_data->interfaces[0],
+                                     &interface_vtable,
+                                     NULL,
+                                     NULL,
+                                     &error);
+
+  if (error != NULL)
+    {
+      g_printerr ("Error exporting object on the session bus: %s",
+                  error->message);
+      g_error_free (error);
+
+      _exit (1);
+    }
+
+  g_debug ("Object exported on the session bus");
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar *name,
+              gpointer user_data)
+{
+  g_debug ("Lost bus name: %s, exiting", name);
+
+  if (cancellable != NULL)
+    g_cancellable_cancel (cancellable);
+
+  name_owner_id = 0;
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar *name,
+                  gpointer user_data)
+{
+  g_debug ("Acquired bus name: %s", name);
+}
+
 int
 main (int argc,
       char **argv)
 {
-  GMainLoop *loop;
-  GdGDataMiner *miner;
-
   g_type_init ();
   loop = g_main_loop_new (NULL, FALSE);
 
@@ -53,12 +180,23 @@ main (int argc,
                                 signal_handler_cb,
                                 loop, NULL);
 
-  miner = gd_gdata_miner_new ();
-  tracker_miner_start (TRACKER_MINER (miner));
+  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+  g_assert (introspection_data != NULL);
+
+  name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                                  BUS_NAME,
+                                  G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+                                  G_BUS_NAME_OWNER_FLAGS_REPLACE,
+                                  on_bus_acquired,
+                                  on_name_acquired,
+                                  on_name_lost,
+                                  NULL, NULL);
 
   g_main_loop_run (loop);
   g_main_loop_unref (loop);
-  g_object_unref (miner);
+
+  if (name_owner_id != 0)
+    g_bus_unown_name (name_owner_id);
 
   return 0;
 }
diff --git a/src/trackerModel.js b/src/trackerModel.js
index 3942c9e..52900e8 100644
--- a/src/trackerModel.js
+++ b/src/trackerModel.js
@@ -19,17 +19,17 @@
  *
  */
 
+const DBus = imports.dbus;
 const Lang = imports.lang;
 const Signals = imports.signals;
 
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
 const Tracker = imports.gi.Tracker;
 const Gd = imports.gi.Gd;
 
 const DocFactory = imports.docFactory;
+const GDataMiner = imports.gDataMiner;
 const Main = imports.main;
 const TrackerUtils = imports.trackerUtils;
 const Utils = imports.utils;
@@ -195,6 +195,19 @@ TrackerModel.prototype = {
 
         this.model = Gd.create_list_store();
         this._connection = connection;
+
+        // startup a refresh of the gdocs cache
+        this._miner = new GDataMiner.GDataMiner();
+        this._miner.RefreshDBRemote(DBus.CALL_FLAG_START, Lang.bind(this,
+            function(res, error) {
+                if (error) {
+                    log('Error updating the GData cache: ' + error.toString());
+                    return;
+                }
+
+                this.model.clear();
+                this._performCurrentQuery();
+            }));
     },
 
     _onSettingsChanged: function() {



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