[gnome-documents] miner: refactor the crawling code to support multiple GOA accounts



commit b7be0f0925607b440b04b134741312adc863c46c
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Sep 15 12:53:54 2011 -0400

    miner: refactor the crawling code to support multiple GOA accounts

 src/miner/gd-gdata-miner.c   |  443 +++++++++++++++++++++++++++++-------------
 src/miner/gdata-miner-main.c |   55 +++++-
 2 files changed, 358 insertions(+), 140 deletions(-)
---
diff --git a/src/miner/gd-gdata-miner.c b/src/miner/gd-gdata-miner.c
index a996e48..dd7d34c 100644
--- a/src/miner/gd-gdata-miner.c
+++ b/src/miner/gd-gdata-miner.c
@@ -26,32 +26,21 @@
 #include "gd-gdata-goa-authorizer.h"
 #include "gd-gdata-miner.h"
 
-#define DATASOURCE_URN "urn:nepomuk:datasource:86ec9bc9-c242-427f-aa19-77b5a2c9b6f0"
+#define MINER_IDENTIFIER "gd:gdata:miner:86ec9bc9-c242-427f-aa19-77b5a2c9b6f0"
 #define STARRED_CATEGORY_TERM "http://schemas.google.com/g/2005/labels#starred";
 
 G_DEFINE_TYPE (GdGDataMiner, gd_gdata_miner, G_TYPE_OBJECT)
 
 struct _GdGDataMinerPrivate {
   GoaClient *client;
-  GDataDocumentsService *service;
   TrackerSparqlConnection *connection;
 
   GCancellable *cancellable;
   GSimpleAsyncResult *result;
 
-  GHashTable *previous_resources;
+  GList *pending_jobs;
 };
 
-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)
 {
@@ -370,6 +359,81 @@ _tracker_utils_iso8601_from_timestamp (gint64 timestamp)
   return g_time_val_to_iso8601 (&tv);
 }
 
+typedef struct {
+  GdGDataMiner *self;
+  TrackerSparqlConnection *connection; /* borrowed from GdGDataMiner */
+  gulong miner_cancellable_id;
+
+  GoaAccount *account;
+  GDataDocumentsService *service;
+  GSimpleAsyncResult *async_result;
+  GCancellable *cancellable;
+
+  GHashTable *previous_resources;
+} AccountMinerJob;
+
+static void
+miner_cancellable_cancelled_cb (GCancellable *cancellable,
+                                gpointer user_data)
+{
+  AccountMinerJob *job = user_data;
+
+  /* forward the cancel signal to the ongoing job */
+  g_cancellable_cancel (job->cancellable);
+}
+
+static void
+account_miner_job_free (AccountMinerJob *job)
+{
+  if (job->miner_cancellable_id != 0)
+    g_cancellable_disconnect (job->self->priv->cancellable,
+                              job->miner_cancellable_id);
+
+  g_clear_object (&job->service);
+  g_clear_object (&job->self);
+  g_clear_object (&job->account);
+  g_clear_object (&job->async_result);
+
+  g_hash_table_unref (job->previous_resources);
+
+  g_slice_free (AccountMinerJob, job);
+}
+
+static AccountMinerJob *
+account_miner_job_new (GdGDataMiner *self,
+                       GoaObject *object)
+{
+  AccountMinerJob *retval;
+  GdGDataGoaAuthorizer *authorizer;
+  GoaAccount *account;
+
+  account = goa_object_get_account (object);
+  g_assert (account != NULL);
+
+  retval = g_slice_new0 (AccountMinerJob);
+  retval->self = g_object_ref (self);
+  retval->cancellable = g_cancellable_new ();
+  retval->account = account;
+  retval->connection = self->priv->connection;
+  retval->previous_resources = 
+    g_hash_table_new_full (g_str_hash, g_str_equal,
+                           (GDestroyNotify) g_free, (GDestroyNotify) g_free);
+
+  if (self->priv->cancellable != NULL)
+      retval->miner_cancellable_id = 
+        g_cancellable_connect (self->priv->cancellable,
+                               G_CALLBACK (miner_cancellable_cancelled_cb),
+                               retval, NULL);
+
+  authorizer = gd_gdata_goa_authorizer_new (object);
+  retval->service = gdata_documents_service_new (GDATA_AUTHORIZER (authorizer));
+
+  /* the service takes ownership of the authorizer */
+  g_object_unref (authorizer);
+
+  return retval;
+}
+
 static void
 previous_resources_cleanup_foreach (gpointer key,
                                     gpointer value,
@@ -382,11 +446,11 @@ previous_resources_cleanup_foreach (gpointer key,
 }
 
 static void
-gd_gdata_miner_cleanup_previous (GdGDataMiner *self)
+account_miner_job_cleanup_previous (AccountMinerJob *job,
+                                    GError **error)
 {
   GString *delete;
   GList *values;
-  GError *error = NULL;
 
   delete = g_string_new (NULL);
   g_string_append (delete, "DELETE { ");
@@ -394,34 +458,29 @@ gd_gdata_miner_cleanup_previous (GdGDataMiner *self)
   /* the resources left here are those who were in the database,
    * but were not found during the query; remove them from the database.
    */
-  g_hash_table_foreach (self->priv->previous_resources,
+  g_hash_table_foreach (job->previous_resources,
                         previous_resources_cleanup_foreach,
                         delete);
 
   g_string_append (delete, "}");
 
-  tracker_sparql_connection_update (self->priv->connection,
+  tracker_sparql_connection_update (job->connection,
                                     delete->str,
                                     G_PRIORITY_DEFAULT,
-                                    self->priv->cancellable,
-                                    &error);
-
-  if (error != NULL) {
-    g_printerr ("Unable to cleanup the previous results: %s\n", error->message);
-    g_error_free (error);
-  }
+                                    job->cancellable,
+                                    error);
 
   g_string_free (delete, TRUE);
 }
 
-static void
-gd_gdata_miner_process_entry (GdGDataMiner *self,
-                              GDataDocumentsEntry *doc_entry,
-                              GError **error)
+static gboolean
+account_miner_job_process_entry (AccountMinerJob *job,
+                                 GDataDocumentsEntry *doc_entry,
+                                 GError **error)
 {
   GDataEntry *entry = GDATA_ENTRY (doc_entry);
   gchar *resource;
-  gchar *date, *resource_url;
+  gchar *date, *resource_url, *datasource_urn;
   const gchar *identifier, *class = NULL;
 
   GList *authors, *l;
@@ -439,8 +498,10 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
   if (!GDATA_IS_DOCUMENTS_DOCUMENT (doc_entry))
     {
       /* TODO: folders */
-      g_print ("found a folder?\n");
-      return;
+      g_set_error_literal (error, G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "Folders are not supported");
+      return FALSE;
     }
 
   identifier = gdata_entry_get_id (entry);
@@ -449,7 +510,7 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
      gdata_documents_entry_get_path (doc_entry));
 
   /* remove from the list of the previous resources */
-  g_hash_table_remove (self->priv->previous_resources, identifier);
+  g_hash_table_remove (job->previous_resources, identifier);
 
   if (GDATA_IS_DOCUMENTS_PRESENTATION (doc_entry))
     class = "nfo:Presentation";
@@ -459,8 +520,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
     class = "nfo:PaginatedTextDocument";
 
   resource = _tracker_sparql_connection_ensure_resource
-    (self->priv->connection, 
-     self->priv->cancellable, error,
+    (job->connection, 
+     job->cancellable, error,
      resource_url, identifier,
      "nfo:RemoteDataObject",
      class,
@@ -469,17 +530,24 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
   if (*error != NULL)
     goto out;
 
+  datasource_urn = g_strdup_printf ("gd:goa-account:%s", 
+                                    goa_account_get_id (job->account));
   _tracker_sparql_connection_set_triple 
-    (self->priv->connection, self->priv->cancellable, error,
+    (job->connection, job->cancellable, error,
      identifier, resource,
-     "nie:dataSource", DATASOURCE_URN);
+     "nie:dataSource", datasource_urn);
+
+  g_free (datasource_urn);
+
+  if (*error != NULL)
+    goto out;
 
   alternate = gdata_entry_look_up_link (entry, GDATA_LINK_ALTERNATE);
   alternate_uri = gdata_link_get_uri (alternate);
 
   _tracker_sparql_connection_insert_or_replace_triple
-    (self->priv->connection, 
-     self->priv->cancellable, error,
+    (job->connection, 
+     job->cancellable, error,
      identifier, resource,
      "nie:url", alternate_uri);
 
@@ -498,16 +566,16 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
     }
 
   _tracker_sparql_connection_toggle_favorite
-    (self->priv->connection, 
-     self->priv->cancellable, error,
+    (job->connection, 
+     job->cancellable, error,
      resource, starred);
 
   if (*error != NULL)
     goto out;
 
   _tracker_sparql_connection_insert_or_replace_triple
-    (self->priv->connection, 
-     self->priv->cancellable, error,
+    (job->connection, 
+     job->cancellable, error,
      identifier, resource,
      "nie:description", gdata_entry_get_summary (entry));
 
@@ -515,8 +583,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
     goto out;
 
   _tracker_sparql_connection_insert_or_replace_triple
-    (self->priv->connection, 
-     self->priv->cancellable, error,
+    (job->connection, 
+     job->cancellable, error,
      identifier, resource,
      "nie:title", gdata_entry_get_title (entry));
 
@@ -530,8 +598,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
 
       author = l->data;
 
-      contact_resource = _tracker_utils_ensure_contact_resource (self->priv->connection,
-                                                                 self->priv->cancellable, error,
+      contact_resource = _tracker_utils_ensure_contact_resource (job->connection,
+                                                                 job->cancellable, error,
                                                                  gdata_author_get_email_address (author),
                                                                  gdata_author_get_name (author));
 
@@ -539,8 +607,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
         goto out;
 
       _tracker_sparql_connection_insert_or_replace_triple
-        (self->priv->connection, 
-         self->priv->cancellable, error,
+        (job->connection, 
+         job->cancellable, error,
          identifier, resource,
          "nco:creator", contact_resource);
 
@@ -551,8 +619,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
     }
 
   access_rules = gdata_access_handler_get_rules (GDATA_ACCESS_HANDLER (entry),
-                                                 GDATA_SERVICE (self->priv->service),
-                                                 self->priv->cancellable,
+                                                 GDATA_SERVICE (job->service),
+                                                 job->cancellable,
                                                  NULL, NULL, error);
 
   if (*error != NULL)
@@ -575,14 +643,14 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
       if (g_strcmp0 (scope_type, GDATA_ACCESS_SCOPE_DOMAIN) == 0)
         continue;
 
-      contact_resource = _tracker_utils_ensure_contact_resource (self->priv->connection,
-                                                                 self->priv->cancellable, error,
+      contact_resource = _tracker_utils_ensure_contact_resource (job->connection,
+                                                                 job->cancellable, error,
                                                                  scope_value,
                                                                  "");
 
       _tracker_sparql_connection_insert_or_replace_triple
-        (self->priv->connection,
-         self->priv->cancellable, error,
+        (job->connection,
+         job->cancellable, error,
          identifier, resource,
          "nco:contributor", contact_resource);
 
@@ -594,8 +662,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
 
   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,
+    (job->connection, 
+     job->cancellable, error,
      identifier, resource,
      "nie:contentCreated", date);
   g_free (date);
@@ -605,8 +673,8 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
 
   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,
+    (job->connection, 
+     job->cancellable, error,
      identifier, resource,
      "nie:contentLastModified", date);
   g_free (date);
@@ -617,134 +685,217 @@ gd_gdata_miner_process_entry (GdGDataMiner *self,
  out:
   g_clear_object (&access_rules);
   g_free (resource_url);
+
+  if (*error != NULL)
+    return FALSE;
+
+  return TRUE;
 }
 
 static void
-gd_gdata_miner_query_gdata (GdGDataMiner *self)
+account_miner_job_query_gdata (AccountMinerJob *job,
+                               GError **error)
 {
   GDataDocumentsQuery *query;
   GDataDocumentsFeed *feed;
-  GError *error = NULL;
   GList *entries, *l;
 
   query = gdata_documents_query_new (NULL);
   feed = gdata_documents_service_query_documents 
-    (self->priv->service, query, 
-     self->priv->cancellable, NULL, NULL, &error);
+    (job->service, query, 
+     job->cancellable, NULL, NULL, error);
 
   g_object_unref (query);
 
-  if (error != NULL)
-    {
-      gd_gdata_miner_complete_error (self, error);
-      return;
-   }
+  if (feed == NULL)
+    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, &error);
+      account_miner_job_process_entry (job, l->data, error);
 
-      if (error != NULL)
-        {
-          gd_gdata_miner_complete_error (self, error);
-          g_object_unref (feed);
-
-          return;
-        }
+      if (*error != NULL)
+        break;
     }
 
-  gd_gdata_miner_cleanup_previous (self);
-
-  g_simple_async_result_complete_in_idle (self->priv->result);
   g_object_unref (feed);
 }
 
+
 static void
-gd_gdata_miner_query_existing (GdGDataMiner *self)
+account_miner_job_query_existing (AccountMinerJob *job,
+                                  GError **error)
 {
   GString *select;
   TrackerSparqlCursor *cursor;
-  GError *error = NULL;
+  gboolean valid;
 
   select = g_string_new (NULL);
   g_string_append_printf (select,
-                          "SELECT ?urn nao:identifier(?urn) WHERE { ?urn a nfo:RemoteDataObject . "
-                          "?urn nie:dataSource \"%s\" }", DATASOURCE_URN);
+                          "SELECT ?urn nao:identifier(?urn) WHERE { ?urn nie:dataSource <gd:goa-account:%s> }",
+                          goa_account_get_id (job->account));
 
-  cursor = tracker_sparql_connection_query (self->priv->connection,
+  cursor = tracker_sparql_connection_query (job->connection,
                                             select->str,
-                                            self->priv->cancellable,
-                                            &error);
+                                            job->cancellable,
+                                            error);
+  g_string_free (select, TRUE);
 
-  if (error != NULL) {
-    g_printerr ("Error while getting the previous resources: %s\n", error->message);
-    g_error_free (error);
+  if (cursor == NULL)
     return;
-  }
 
-  while (tracker_sparql_cursor_next (cursor, self->priv->cancellable, NULL)) {
-    g_hash_table_insert (self->priv->previous_resources, 
-                         g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL)),
-                         g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)));
-  }
-
-  g_object_unref (cursor);
-  g_string_free (select, TRUE);
+  while (tracker_sparql_cursor_next (cursor, job->cancellable, error))
+    {
+      g_hash_table_insert (job->previous_resources, 
+                           g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL)),
+                           g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)));
+    }
 }
 
 static void
-gd_gdata_ensure_tracker_connection (GdGDataMiner *self,
-                                    GoaObject *object,
-                                    GError **error)
+account_miner_job_ensure_datasource (AccountMinerJob *job,
+                                     GError **error)
 {
   GString *datasource_insert;
-  GoaAccount *account;
 
-  if (self->priv->connection != NULL)
-    return;
-
-  self->priv->connection = 
-    tracker_sparql_connection_get (self->priv->cancellable, error);
-
-  if (*error != NULL)
-    return;
-
-  account = goa_object_peek_account (object);
   datasource_insert = g_string_new (NULL);
   g_string_append_printf (datasource_insert,
-                          "INSERT { <%s> a nie:DataSource ; nao:identifier \"goa:documents:%s\" }",
-                          DATASOURCE_URN, goa_account_get_id (account));
+                          "INSERT OR REPLACE { <gd:goa-account:%s> a nie:DataSource ; nao:identifier \"%s\" }",
+                          goa_account_get_id (job->account), MINER_IDENTIFIER);
 
-  tracker_sparql_connection_update (self->priv->connection, datasource_insert->str,
-                                    G_PRIORITY_DEFAULT, self->priv->cancellable,
+  tracker_sparql_connection_update (job->connection, 
+                                    datasource_insert->str,
+                                    G_PRIORITY_DEFAULT,
+                                    job->cancellable,
                                     error);
+
+  g_string_free (datasource_insert, TRUE);
 }
 
-static void
-gd_gdata_miner_setup_account (GdGDataMiner *self,
-                              GoaObject *object)
+static gboolean
+account_miner_job (GIOSchedulerJob *sched_job,
+                   GCancellable *cancellable,
+                   gpointer user_data)
 {
-  GdGDataGoaAuthorizer *authorizer;
+  AccountMinerJob *job = user_data;
   GError *error = NULL;
 
-  authorizer = gd_gdata_goa_authorizer_new (object);
-  self->priv->service = 
-    gdata_documents_service_new (GDATA_AUTHORIZER (authorizer));
+  account_miner_job_ensure_datasource (job, &error);
 
-  /* the service takes ownership of the authorizer */
-  g_object_unref (authorizer);
+  if (error != NULL)
+    goto out;
+
+  account_miner_job_query_existing (job, &error);
+
+  if (error != NULL)
+    goto out;
+
+  account_miner_job_query_gdata (job, &error);
 
-  gd_gdata_ensure_tracker_connection (self, object, &error);
+  if (error != NULL)
+    goto out;
+
+  account_miner_job_cleanup_previous (job, &error);
+
+  if (error != NULL)
+    goto out;
+
+ out:
+  if (error != NULL)
+    g_simple_async_result_take_error (job->async_result, error);
+
+  g_simple_async_result_complete_in_idle (job->async_result);
+
+  return FALSE;
+}
+
+static void
+account_miner_job_process_async (AccountMinerJob *job,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+  g_assert (job->async_result == NULL);
+
+  job->async_result = g_simple_async_result_new (NULL, callback, user_data,
+                                                 account_miner_job_process_async);
+  g_simple_async_result_set_op_res_gpointer (job->async_result, job, NULL);
+
+  g_io_scheduler_push_job (account_miner_job, job, NULL,
+                           G_PRIORITY_DEFAULT,
+                           job->cancellable);
+}
+
+static gboolean
+account_miner_job_process_finish (GAsyncResult *res,
+                                  GError **error)
+{
+  GSimpleAsyncResult *simple_res = G_SIMPLE_ASYNC_RESULT (res);
+
+  g_assert (g_simple_async_result_is_valid (res, NULL,
+                                            account_miner_job_process_async));
+
+  if (g_simple_async_result_propagate_error (simple_res, error))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+gd_gdata_miner_complete_error (GdGDataMiner *self,
+                               GError *error)
+{
+  GList *l;
+
+  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 void
+gd_gdata_miner_check_pending_jobs (GdGDataMiner *self)
+{
+  if (g_list_length (self->priv->pending_jobs) == 0)
+    g_simple_async_result_complete_in_idle (self->priv->result);    
+}
+
+static void
+miner_job_process_ready_cb (GObject *source,
+                            GAsyncResult *res,
+                            gpointer user_data)
+{
+  AccountMinerJob *job = user_data;
+  GdGDataMiner *self = job->self;
+  GError *error = NULL;
+
+  account_miner_job_process_finish (res, &error);
 
   if (error != NULL)
     {
-      gd_gdata_miner_complete_error (self, error);
-      return;
+      g_printerr ("Error while refreshing account %s: %s", 
+                  goa_account_get_id (job->account), error->message);
+
+      g_error_free (error);
     }
 
-  gd_gdata_miner_query_existing (self);
-  gd_gdata_miner_query_gdata (self);
+  self->priv->pending_jobs = g_list_remove (self->priv->pending_jobs,
+                                            job);
+  account_miner_job_free (job);
+
+  gd_gdata_miner_check_pending_jobs (self);
+}
+
+static void
+gd_gdata_miner_setup_account (GdGDataMiner *self,
+                              GoaObject *object)
+{
+  AccountMinerJob *job;
+
+  job = account_miner_job_new (self, object);
+  self->priv->pending_jobs = g_list_prepend (self->priv->pending_jobs, job);
+
+  account_miner_job_process_async (job, miner_job_process_ready_cb, job);
 }
 
 static void
@@ -803,18 +954,41 @@ client_ready_cb (GObject *source,
 }
 
 static void
+sparql_connection_ready_cb (GObject *object,
+                            GAsyncResult *res,
+                            gpointer user_data)
+{
+  GError *error = NULL;
+  GdGDataMiner *self = user_data;
+
+  self->priv->connection = tracker_sparql_connection_get_finish (res, &error);
+
+  if (error != NULL)
+    {
+      gd_gdata_miner_complete_error (self, error);
+      return;
+    }
+
+  goa_client_new (self->priv->cancellable, client_ready_cb, self);
+}
+
+static void
 gd_gdata_miner_dispose (GObject *object)
 {
   GdGDataMiner *self = GD_GDATA_MINER (object);
 
-  g_clear_object (&self->priv->service);
+  if (self->priv->pending_jobs != NULL)
+    {
+      g_list_free_full (self->priv->pending_jobs,
+                        (GDestroyNotify) account_miner_job_free);
+      self->priv->pending_jobs = NULL;
+    }
+
   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_hash_table_unref (self->priv->previous_resources);
-
   G_OBJECT_CLASS (gd_gdata_miner_parent_class)->dispose (object);
 }
 
@@ -823,8 +997,6 @@ gd_gdata_miner_init (GdGDataMiner *self)
 {
   self->priv =
     G_TYPE_INSTANCE_GET_PRIVATE (self, GD_TYPE_GDATA_MINER, GdGDataMinerPrivate);
-  self->priv->previous_resources = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                                          (GDestroyNotify) g_free, (GDestroyNotify) g_free);
 }
 
 static void
@@ -856,7 +1028,8 @@ gd_gdata_miner_refresh_db_async (GdGDataMiner *self,
   self->priv->cancellable = 
     (cancellable != NULL) ? g_object_ref (cancellable) : NULL;
 
-  goa_client_new (self->priv->cancellable, client_ready_cb, self);  
+  tracker_sparql_connection_get_async (self->priv->cancellable,
+                                       sparql_connection_ready_cb, self);
 }
 
 gboolean
diff --git a/src/miner/gdata-miner-main.c b/src/miner/gdata-miner-main.c
index 4b7e967..1d6ed95 100644
--- a/src/miner/gdata-miner-main.c
+++ b/src/miner/gdata-miner-main.c
@@ -25,7 +25,7 @@
 #include "gd-gdata-miner.h"
 
 #define BUS_NAME "org.gnome.Documents.GDataMiner"
-#define AUTOQUIT_TIMEOUT 5
+#define AUTOQUIT_TIMEOUT 5 /* seconds */
 
 static const gchar introspection_xml[] =
   "<node>"
@@ -39,6 +39,43 @@ static GDBusNodeInfo *introspection_data = NULL;
 static GCancellable *cancellable = NULL;
 static GMainLoop *loop = NULL;
 static guint name_owner_id = 0;
+static guint autoquit_id = 0;
+static gboolean refreshing = FALSE;
+
+static gboolean
+autoquit_timeout_cb (gpointer _unused)
+{
+  g_debug ("Timeout reached, quitting...");
+
+  autoquit_id = 0;
+  g_main_loop_quit (loop);
+
+  return FALSE;
+}
+
+static void
+ensure_autoquit_off (void)
+{
+  if (g_getenv ("GDATA_MINER_PERSIST") != NULL)
+    return;
+
+  if (autoquit_id != 0)
+    {
+      g_source_remove (autoquit_id);
+      autoquit_id = 0;
+    }
+}
+
+static void
+ensure_autoquit_on (void)
+{
+  if (g_getenv ("GDATA_MINER_PERSIST") != NULL)
+    return;
+
+  autoquit_id = 
+    g_timeout_add_seconds (AUTOQUIT_TIMEOUT,
+                           autoquit_timeout_cb, NULL);
+}
 
 static gboolean
 signal_handler_cb (gpointer user_data)
@@ -62,6 +99,7 @@ miner_refresh_db_ready_cb (GObject *source,
   GError *error = NULL;
 
   gd_gdata_miner_refresh_db_finish (GD_GDATA_MINER (source), res, &error);
+  refreshing = FALSE;
 
   if (error != NULL)
     {
@@ -73,8 +111,7 @@ miner_refresh_db_ready_cb (GObject *source,
       g_dbus_method_invocation_return_value (invocation, NULL);
     }
 
-  g_object_unref (cancellable);
-  g_main_loop_quit (loop);
+  ensure_autoquit_on ();
 }
 
 static void
@@ -82,6 +119,13 @@ handle_refresh_db (GDBusMethodInvocation *invocation)
 {
   GdGDataMiner *miner;
 
+  ensure_autoquit_off ();
+
+  /* if we're refreshing already, compress with the current request */
+  if (refreshing)
+    return;
+
+  refreshing = TRUE;
   cancellable = g_cancellable_new ();
   miner = gd_gdata_miner_new ();
 
@@ -169,6 +213,8 @@ main (int argc,
       char **argv)
 {
   g_type_init ();
+
+  ensure_autoquit_on ();
   loop = g_main_loop_new (NULL, FALSE);
 
   g_unix_signal_add_full (G_PRIORITY_DEFAULT,
@@ -185,8 +231,7 @@ main (int argc,
 
   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,
+                                  G_BUS_NAME_OWNER_FLAGS_NONE,
                                   on_bus_acquired,
                                   on_name_acquired,
                                   on_name_lost,



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