Blame src/gom-miner.c

Packit f01ec2
/*
Packit f01ec2
 * GNOME Online Miners - crawls through your online content
Packit f01ec2
 * Copyright (C) 2012 Red Hat, Inc.
Packit f01ec2
 *
Packit f01ec2
 * This program is free software; you can redistribute it and/or
Packit f01ec2
 * modify it under the terms of the GNU General Public License
Packit f01ec2
 * as published by the Free Software Foundation; either version 2
Packit f01ec2
 * of the License, or (at your option) any later version.
Packit f01ec2
 *
Packit f01ec2
 * This program is distributed in the hope that it will be useful,
Packit f01ec2
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit f01ec2
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit f01ec2
 * GNU General Public License for more details.
Packit f01ec2
 *
Packit f01ec2
 * You should have received a copy of the GNU General Public License
Packit f01ec2
 * along with this program; if not, write to the Free Software
Packit f01ec2
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit f01ec2
 * 02110-1301, USA.
Packit f01ec2
 *
Packit f01ec2
 * Author: Cosimo Cecchi <cosimoc@redhat.com>
Packit f01ec2
 * Author: Jasper St. Pierre <jstpierre@mecheye.net>
Packit f01ec2
 *
Packit f01ec2
 */
Packit f01ec2
Packit f01ec2
#include "config.h"
Packit f01ec2
Packit f01ec2
#include <stdio.h>
Packit f01ec2
Packit f01ec2
#include "gom-miner.h"
Packit f01ec2
Packit f01ec2
G_DEFINE_TYPE (GomMiner, gom_miner, G_TYPE_OBJECT)
Packit f01ec2
Packit f01ec2
struct _GomMinerPrivate {
Packit f01ec2
  GoaClient *client;
Packit f01ec2
  GError *client_error;
Packit f01ec2
Packit f01ec2
  TrackerSparqlConnection *connection;
Packit f01ec2
  GError *connection_error;
Packit f01ec2
Packit f01ec2
  gchar *display_name;
Packit f01ec2
  gchar **index_types;
Packit f01ec2
};
Packit f01ec2
Packit f01ec2
typedef struct {
Packit f01ec2
  GomMiner *self;
Packit f01ec2
  GList *content_objects;
Packit f01ec2
  GList *acc_objects;
Packit f01ec2
  GList *old_datasources;
Packit f01ec2
  GList *pending_jobs;
Packit f01ec2
} CleanupJob;
Packit f01ec2
Packit f01ec2
typedef struct {
Packit f01ec2
  GomMiner *self;
Packit f01ec2
  gchar *account_id;
Packit f01ec2
  gchar *shared_id;
Packit f01ec2
  gchar *shared_type;
Packit f01ec2
  gchar *source_urn;
Packit f01ec2
  gpointer service;
Packit f01ec2
} InsertSharedContentData;
Packit f01ec2
Packit f01ec2
static GThreadPool *cleanup_pool;
Packit f01ec2
Packit f01ec2
static void cleanup_job (gpointer data, gpointer user_data);
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job_free (GomAccountMinerJob *job)
Packit f01ec2
{
Packit f01ec2
  g_hash_table_unref (job->services);
Packit f01ec2
  g_clear_object (&job->miner);
Packit f01ec2
  g_clear_object (&job->account);
Packit f01ec2
  g_clear_object (&job->connection);
Packit f01ec2
  g_clear_object (&job->task);
Packit f01ec2
  g_clear_object (&job->parent_task);
Packit f01ec2
Packit f01ec2
  g_free (job->datasource_urn);
Packit f01ec2
  g_free (job->root_element_urn);
Packit f01ec2
Packit f01ec2
  g_hash_table_unref (job->previous_resources);
Packit f01ec2
Packit f01ec2
  g_slice_free (GomAccountMinerJob, job);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_insert_shared_content_data_free (InsertSharedContentData *data)
Packit f01ec2
{
Packit f01ec2
  GOM_MINER_GET_CLASS (data->self)->destroy_service (data->self, data->service);
Packit f01ec2
Packit f01ec2
  g_object_unref (data->self);
Packit f01ec2
  g_free (data->account_id);
Packit f01ec2
  g_free (data->shared_id);
Packit f01ec2
  g_free (data->shared_type);
Packit f01ec2
  g_free (data->source_urn);
Packit f01ec2
Packit f01ec2
  g_slice_free (InsertSharedContentData, data);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static InsertSharedContentData *
Packit f01ec2
gom_insert_shared_content_data_new (GomMiner *self,
Packit f01ec2
                                    const gchar *account_id,
Packit f01ec2
                                    const gchar *shared_id,
Packit f01ec2
                                    const gchar *shared_type,
Packit f01ec2
                                    const gchar *source_urn,
Packit f01ec2
                                    gpointer service)
Packit f01ec2
{
Packit f01ec2
  InsertSharedContentData *retval;
Packit f01ec2
Packit f01ec2
  retval = g_slice_new0 (InsertSharedContentData);
Packit f01ec2
  retval->self = g_object_ref (self);
Packit f01ec2
  retval->account_id = g_strdup (account_id);
Packit f01ec2
  retval->shared_id = g_strdup (shared_id);
Packit f01ec2
  retval->shared_type = g_strdup (shared_type);
Packit f01ec2
  retval->source_urn = g_strdup (source_urn);
Packit f01ec2
  retval->service = service;
Packit f01ec2
Packit f01ec2
  return retval;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_dispose (GObject *object)
Packit f01ec2
{
Packit f01ec2
  GomMiner *self = GOM_MINER (object);
Packit f01ec2
Packit f01ec2
  g_clear_object (&self->priv->client);
Packit f01ec2
  g_clear_object (&self->priv->connection);
Packit f01ec2
Packit f01ec2
  g_free (self->priv->display_name);
Packit f01ec2
  g_strfreev (self->priv->index_types);
Packit f01ec2
  g_clear_error (&self->priv->client_error);
Packit f01ec2
  g_clear_error (&self->priv->connection_error);
Packit f01ec2
Packit f01ec2
  G_OBJECT_CLASS (gom_miner_parent_class)->dispose (object);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_init_goa (GomMiner *self)
Packit f01ec2
{
Packit f01ec2
  GoaAccount *account;
Packit f01ec2
  GoaObject *object;
Packit f01ec2
  const gchar *provider_type;
Packit f01ec2
  GList *accounts, *l;
Packit f01ec2
  GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
Packit f01ec2
Packit f01ec2
  self->priv->client = goa_client_new_sync (NULL, &self->priv->client_error);
Packit f01ec2
Packit f01ec2
  if (self->priv->client_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_critical ("Unable to create GoaClient: %s - indexing for %s will not work",
Packit f01ec2
                  self->priv->client_error->message, miner_class->goa_provider_type);
Packit f01ec2
      return;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  accounts = goa_client_get_accounts (self->priv->client);
Packit f01ec2
  for (l = accounts; l != NULL; l = l->next)
Packit f01ec2
    {
Packit f01ec2
      object = l->data;
Packit f01ec2
Packit f01ec2
      account = goa_object_peek_account (object);
Packit f01ec2
      if (account == NULL)
Packit f01ec2
        continue;
Packit f01ec2
Packit f01ec2
      provider_type = goa_account_get_provider_type (account);
Packit f01ec2
      if (g_strcmp0 (provider_type, miner_class->goa_provider_type) == 0)
Packit f01ec2
        {
Packit f01ec2
          g_free (self->priv->display_name);
Packit f01ec2
          self->priv->display_name = goa_account_dup_provider_name (account);
Packit f01ec2
          break;
Packit f01ec2
        }
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  g_list_free_full (accounts, g_object_unref);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_constructed (GObject *obj)
Packit f01ec2
{
Packit f01ec2
  GomMiner *self = GOM_MINER (obj);
Packit f01ec2
Packit f01ec2
  G_OBJECT_CLASS (gom_miner_parent_class)->constructed (obj);
Packit f01ec2
Packit f01ec2
  gom_miner_init_goa (self);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_init (GomMiner *self)
Packit f01ec2
{
Packit f01ec2
  GomMinerClass *klass = GOM_MINER_GET_CLASS (self);
Packit f01ec2
Packit f01ec2
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GOM_TYPE_MINER, GomMinerPrivate);
Packit f01ec2
  self->priv->display_name = g_strdup ("");
Packit f01ec2
Packit f01ec2
  self->priv->connection = tracker_sparql_connection_get (NULL, &self->priv->connection_error);
Packit f01ec2
  if (self->priv->connection_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_critical ("Unable to create TrackerSparqlConnection: %s - indexing for %s will not work",
Packit f01ec2
                  self->priv->connection_error->message,
Packit f01ec2
                  klass->goa_provider_type);
Packit f01ec2
    }
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_class_init (GomMinerClass *klass)
Packit f01ec2
{
Packit f01ec2
  GObjectClass *oclass = G_OBJECT_CLASS (klass);
Packit f01ec2
Packit f01ec2
  oclass->constructed = gom_miner_constructed;
Packit f01ec2
  oclass->dispose = gom_miner_dispose;
Packit f01ec2
Packit f01ec2
  cleanup_pool = g_thread_pool_new (cleanup_job, NULL, 1, FALSE, NULL);
Packit f01ec2
Packit f01ec2
  g_type_class_add_private (klass, sizeof (GomMinerPrivate));
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_check_pending_jobs (GTask *task)
Packit f01ec2
{
Packit f01ec2
  CleanupJob *cleanup_job;
Packit f01ec2
Packit f01ec2
  cleanup_job = (CleanupJob *) g_task_get_task_data (task);
Packit f01ec2
Packit f01ec2
  if (g_list_length (cleanup_job->pending_jobs) > 0)
Packit f01ec2
    return;
Packit f01ec2
Packit f01ec2
  g_task_return_boolean (task, TRUE);
Packit f01ec2
  g_slice_free (CleanupJob, cleanup_job);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_ensure_datasource (GomMiner *self,
Packit f01ec2
                             const gchar *datasource_urn,
Packit f01ec2
                             const gchar *root_element_urn,
Packit f01ec2
                             GCancellable *cancellable,
Packit f01ec2
                             GError **error)
Packit f01ec2
{
Packit f01ec2
  GString *datasource_insert;
Packit f01ec2
  GomMinerClass *klass = GOM_MINER_GET_CLASS (self);
Packit f01ec2
Packit f01ec2
  datasource_insert = g_string_new (NULL);
Packit f01ec2
  g_string_append_printf (datasource_insert,
Packit f01ec2
                          "INSERT OR REPLACE INTO <%s> {"
Packit f01ec2
                          "  <%s> a nie:DataSource ; nao:identifier \"%s\" . "
Packit f01ec2
                          "  <%s> a nie:InformationElement ; nie:rootElementOf <%s> ; nie:version \"%d\""
Packit f01ec2
                          "}",
Packit f01ec2
                          datasource_urn,
Packit f01ec2
                          datasource_urn, klass->miner_identifier,
Packit f01ec2
                          root_element_urn, datasource_urn, klass->version);
Packit f01ec2
Packit f01ec2
  tracker_sparql_connection_update (self->priv->connection,
Packit f01ec2
                                    datasource_insert->str,
Packit f01ec2
                                    G_PRIORITY_DEFAULT,
Packit f01ec2
                                    cancellable,
Packit f01ec2
                                    error);
Packit f01ec2
Packit f01ec2
  g_string_free (datasource_insert, TRUE);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job_query_existing (GomAccountMinerJob *job,
Packit f01ec2
                                      GError **error)
Packit f01ec2
{
Packit f01ec2
  GCancellable *cancellable;
Packit f01ec2
  GString *select;
Packit f01ec2
  TrackerSparqlCursor *cursor;
Packit f01ec2
Packit f01ec2
  cancellable = g_task_get_cancellable (job->task);
Packit f01ec2
Packit f01ec2
  select = g_string_new (NULL);
Packit f01ec2
  g_string_append_printf (select,
Packit f01ec2
                          "SELECT ?urn nao:identifier(?urn) WHERE { ?urn nie:dataSource <%s> }",
Packit f01ec2
                          job->datasource_urn);
Packit f01ec2
Packit f01ec2
  cursor = tracker_sparql_connection_query (job->connection,
Packit f01ec2
                                            select->str,
Packit f01ec2
                                            cancellable,
Packit f01ec2
                                            error);
Packit f01ec2
  g_string_free (select, TRUE);
Packit f01ec2
Packit f01ec2
  if (cursor == NULL)
Packit f01ec2
    return;
Packit f01ec2
Packit f01ec2
  while (tracker_sparql_cursor_next (cursor, cancellable, error))
Packit f01ec2
    {
Packit f01ec2
      g_hash_table_insert (job->previous_resources,
Packit f01ec2
                           g_strdup (tracker_sparql_cursor_get_string (cursor, 1, NULL)),
Packit f01ec2
                           g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)));
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  g_object_unref (cursor);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
previous_resources_cleanup_foreach (gpointer key,
Packit f01ec2
                                    gpointer value,
Packit f01ec2
                                    gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  const gchar *resource = value;
Packit f01ec2
  GString *delete = user_data;
Packit f01ec2
Packit f01ec2
  g_string_append_printf (delete, "<%s> a rdfs:Resource . ", resource);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job_cleanup_previous (GomAccountMinerJob *job,
Packit f01ec2
                                        GError **error)
Packit f01ec2
{
Packit f01ec2
  GCancellable *cancellable;
Packit f01ec2
  GString *delete;
Packit f01ec2
Packit f01ec2
  cancellable = g_task_get_cancellable (job->task);
Packit f01ec2
Packit f01ec2
  delete = g_string_new (NULL);
Packit f01ec2
  g_string_append (delete, "DELETE { ");
Packit f01ec2
Packit f01ec2
  /* the resources left here are those who were in the database,
Packit f01ec2
   * but were not found during the query; remove them from the database.
Packit f01ec2
   */
Packit f01ec2
  g_hash_table_foreach (job->previous_resources,
Packit f01ec2
                        previous_resources_cleanup_foreach,
Packit f01ec2
                        delete);
Packit f01ec2
Packit f01ec2
  g_string_append (delete, "}");
Packit f01ec2
Packit f01ec2
  tracker_sparql_connection_update (job->connection,
Packit f01ec2
                                    delete->str,
Packit f01ec2
                                    G_PRIORITY_DEFAULT,
Packit f01ec2
                                    cancellable,
Packit f01ec2
                                    error);
Packit f01ec2
Packit f01ec2
  g_string_free (delete, TRUE);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job_query (GomAccountMinerJob *job,
Packit f01ec2
                             GError **error)
Packit f01ec2
{
Packit f01ec2
  GomMinerClass *miner_class = GOM_MINER_GET_CLASS (job->miner);
Packit f01ec2
  GCancellable *cancellable;
Packit f01ec2
Packit f01ec2
  cancellable = g_task_get_cancellable (job->task);
Packit f01ec2
  miner_class->query (job, job->connection, job->previous_resources, job->datasource_urn, cancellable, error);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job (GTask *task,
Packit f01ec2
                       gpointer source_object,
Packit f01ec2
                       gpointer task_data,
Packit f01ec2
                       GCancellable *cancellable)
Packit f01ec2
{
Packit f01ec2
  GomAccountMinerJob *job = task_data;
Packit f01ec2
  GError *error = NULL;
Packit f01ec2
Packit f01ec2
  gom_miner_ensure_datasource (job->miner, job->datasource_urn, job->root_element_urn, cancellable, &error);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    goto out;
Packit f01ec2
Packit f01ec2
  gom_account_miner_job_query_existing (job, &error);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    goto out;
Packit f01ec2
Packit f01ec2
  gom_account_miner_job_query (job, &error);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    goto out;
Packit f01ec2
Packit f01ec2
  gom_account_miner_job_cleanup_previous (job, &error);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    goto out;
Packit f01ec2
Packit f01ec2
 out:
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    g_task_return_error (job->task, error);
Packit f01ec2
  else
Packit f01ec2
    g_task_return_boolean (job->task, TRUE);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_account_miner_job_process_async (GomAccountMinerJob *job,
Packit f01ec2
                                     GAsyncReadyCallback callback,
Packit f01ec2
                                     gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  GCancellable *cancellable;
Packit f01ec2
Packit f01ec2
  g_assert (job->task == NULL);
Packit f01ec2
Packit f01ec2
  cancellable = g_task_get_cancellable (job->parent_task);
Packit f01ec2
Packit f01ec2
  job->task = g_task_new (NULL, cancellable, callback, user_data);
Packit f01ec2
  g_task_set_source_tag (job->task, gom_account_miner_job_process_async);
Packit f01ec2
  g_task_set_task_data (job->task, job, NULL);
Packit f01ec2
  g_task_run_in_thread (job->task, gom_account_miner_job);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static gboolean
Packit f01ec2
gom_account_miner_job_process_finish (GAsyncResult *res,
Packit f01ec2
                                      GError **error)
Packit f01ec2
{
Packit f01ec2
  GTask *task;
Packit f01ec2
Packit f01ec2
  g_assert (g_task_is_valid (res, NULL));
Packit f01ec2
  task = G_TASK (res);
Packit f01ec2
Packit f01ec2
  g_assert (g_task_get_source_tag (task) == gom_account_miner_job_process_async);
Packit f01ec2
Packit f01ec2
  return g_task_propagate_boolean (task, error);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static GomAccountMinerJob *
Packit f01ec2
gom_account_miner_job_new (GomMiner *self,
Packit f01ec2
                           GoaObject *object,
Packit f01ec2
                           GTask *parent_task)
Packit f01ec2
{
Packit f01ec2
  GomAccountMinerJob *retval;
Packit f01ec2
  GoaAccount *account;
Packit f01ec2
  GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
Packit f01ec2
Packit f01ec2
  account = goa_object_get_account (object);
Packit f01ec2
  g_assert (account != NULL);
Packit f01ec2
Packit f01ec2
  retval = g_slice_new0 (GomAccountMinerJob);
Packit f01ec2
  retval->miner = g_object_ref (self);
Packit f01ec2
  retval->parent_task = g_object_ref (parent_task);
Packit f01ec2
  retval->account = account;
Packit f01ec2
  retval->connection = g_object_ref (self->priv->connection);
Packit f01ec2
  retval->previous_resources =
Packit f01ec2
    g_hash_table_new_full (g_str_hash, g_str_equal,
Packit f01ec2
                           (GDestroyNotify) g_free, (GDestroyNotify) g_free);
Packit f01ec2
Packit f01ec2
  retval->services = miner_class->create_services (self, object);
Packit f01ec2
  retval->datasource_urn = g_strdup_printf ("gd:goa-account:%s",
Packit f01ec2
                                            goa_account_get_id (retval->account));
Packit f01ec2
  retval->root_element_urn = g_strdup_printf ("gd:goa-account:%s:root-element",
Packit f01ec2
                                              goa_account_get_id (retval->account));
Packit f01ec2
Packit f01ec2
  return retval;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
miner_job_process_ready_cb (GObject *source,
Packit f01ec2
                            GAsyncResult *res,
Packit f01ec2
                            gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  CleanupJob *cleanup_job;
Packit f01ec2
  GomAccountMinerJob *account_miner_job = user_data;
Packit f01ec2
  GomMiner *self = account_miner_job->miner;
Packit f01ec2
  GError *error = NULL;
Packit f01ec2
Packit f01ec2
  cleanup_job = (CleanupJob *) g_task_get_task_data (account_miner_job->parent_task);
Packit f01ec2
Packit f01ec2
  gom_account_miner_job_process_finish (res, &error);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_printerr ("Error while refreshing account %s: %s",
Packit f01ec2
                  goa_account_get_id (account_miner_job->account), error->message);
Packit f01ec2
Packit f01ec2
      g_error_free (error);
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  cleanup_job->pending_jobs = g_list_remove (cleanup_job->pending_jobs,
Packit f01ec2
                                             account_miner_job);
Packit f01ec2
Packit f01ec2
  gom_miner_check_pending_jobs (account_miner_job->parent_task);
Packit f01ec2
  gom_account_miner_job_free (account_miner_job);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_setup_account (GomMiner *self,
Packit f01ec2
                         GoaObject *object,
Packit f01ec2
                         GTask *task)
Packit f01ec2
{
Packit f01ec2
  CleanupJob *cleanup_job;
Packit f01ec2
  GomAccountMinerJob *account_miner_job;
Packit f01ec2
Packit f01ec2
  cleanup_job = (CleanupJob *) g_task_get_task_data (task);
Packit f01ec2
Packit f01ec2
  account_miner_job = gom_account_miner_job_new (self, object, task);
Packit f01ec2
  cleanup_job->pending_jobs = g_list_prepend (cleanup_job->pending_jobs, account_miner_job);
Packit f01ec2
Packit f01ec2
  gom_account_miner_job_process_async (account_miner_job, miner_job_process_ready_cb, account_miner_job);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static gboolean
Packit f01ec2
cleanup_old_accounts_done (gpointer data)
Packit f01ec2
{
Packit f01ec2
  GTask *task = G_TASK (data);
Packit f01ec2
  CleanupJob *job;
Packit f01ec2
  GList *l;
Packit f01ec2
  GoaObject *object;
Packit f01ec2
  GomMiner *self;
Packit f01ec2
Packit f01ec2
  job = (CleanupJob *) g_task_get_task_data (task);
Packit f01ec2
  self = job->self;
Packit f01ec2
Packit f01ec2
  /* now setup all the current accounts */
Packit f01ec2
  for (l = job->content_objects; l != NULL; l = l->next)
Packit f01ec2
    {
Packit f01ec2
      object = l->data;
Packit f01ec2
      gom_miner_setup_account (self, object, task);
Packit f01ec2
Packit f01ec2
      g_object_unref (object);
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (job->content_objects != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_list_free (job->content_objects);
Packit f01ec2
      job->content_objects = NULL;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (job->acc_objects != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_list_free_full (job->acc_objects, g_object_unref);
Packit f01ec2
      job->acc_objects = NULL;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (job->old_datasources != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_list_free_full (job->old_datasources, g_free);
Packit f01ec2
      job->old_datasources = NULL;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  gom_miner_check_pending_jobs (task);
Packit f01ec2
Packit f01ec2
  g_clear_object (&job->self);
Packit f01ec2
Packit f01ec2
  return FALSE;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
cleanup_job_do_cleanup (CleanupJob *job, GCancellable *cancellable)
Packit f01ec2
{
Packit f01ec2
  GomMiner *self = job->self;
Packit f01ec2
  GList *l;
Packit f01ec2
  GString *update;
Packit f01ec2
  GError *error = NULL;
Packit f01ec2
Packit f01ec2
  if (job->old_datasources == NULL)
Packit f01ec2
    return;
Packit f01ec2
Packit f01ec2
  update = g_string_new (NULL);
Packit f01ec2
Packit f01ec2
  for (l = job->old_datasources; l != NULL; l = l->next)
Packit f01ec2
    {
Packit f01ec2
      const gchar *resource;
Packit f01ec2
Packit f01ec2
      resource = l->data;
Packit f01ec2
      g_debug ("Cleaning up old datasource %s", resource);
Packit f01ec2
Packit f01ec2
      g_string_append_printf (update,
Packit f01ec2
                              "DELETE {"
Packit f01ec2
                              "  ?u a rdfs:Resource"
Packit f01ec2
                              "} WHERE {"
Packit f01ec2
                              "  ?u nie:dataSource <%s>"
Packit f01ec2
                              "}",
Packit f01ec2
                              resource);
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  tracker_sparql_connection_update (self->priv->connection,
Packit f01ec2
                                    update->str,
Packit f01ec2
                                    G_PRIORITY_DEFAULT,
Packit f01ec2
                                    cancellable,
Packit f01ec2
                                    &error);
Packit f01ec2
  g_string_free (update, TRUE);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_printerr ("Error while cleaning up old accounts: %s\n", error->message);
Packit f01ec2
      g_error_free (error);
Packit f01ec2
    }
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static gint
Packit f01ec2
cleanup_datasource_compare (gconstpointer a,
Packit f01ec2
                            gconstpointer b)
Packit f01ec2
{
Packit f01ec2
  GoaObject *object = GOA_OBJECT (a);
Packit f01ec2
  const gchar *datasource = b;
Packit f01ec2
  gint res;
Packit f01ec2
Packit f01ec2
  GoaAccount *account;
Packit f01ec2
  gchar *object_datasource;
Packit f01ec2
Packit f01ec2
  account = goa_object_peek_account (object);
Packit f01ec2
  g_assert (account != NULL);
Packit f01ec2
Packit f01ec2
  object_datasource = g_strdup_printf ("gd:goa-account:%s", goa_account_get_id (account));
Packit f01ec2
  res = g_strcmp0 (datasource, object_datasource);
Packit f01ec2
Packit f01ec2
  g_free (object_datasource);
Packit f01ec2
Packit f01ec2
  return res;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
cleanup_job (gpointer data,
Packit f01ec2
             gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  GCancellable *cancellable;
Packit f01ec2
  GSource *source;
Packit f01ec2
  GString *select;
Packit f01ec2
  GTask *task = G_TASK (data);
Packit f01ec2
  GError *error = NULL;
Packit f01ec2
  TrackerSparqlCursor *cursor;
Packit f01ec2
  const gchar *datasource, *old_version_str;
Packit f01ec2
  gint old_version;
Packit f01ec2
  GList *element;
Packit f01ec2
  CleanupJob *job;
Packit f01ec2
  GomMiner *self;
Packit f01ec2
  GomMinerClass *klass;
Packit f01ec2
Packit f01ec2
  cancellable = g_task_get_cancellable (task);
Packit f01ec2
  job = (CleanupJob *) g_task_get_task_data (task);
Packit f01ec2
  self = job->self;
Packit f01ec2
  klass = GOM_MINER_GET_CLASS (self);
Packit f01ec2
Packit f01ec2
  /* find all our datasources in the tracker DB */
Packit f01ec2
  select = g_string_new (NULL);
Packit f01ec2
  g_string_append_printf (select, "SELECT ?datasource nie:version(?root) WHERE { "
Packit f01ec2
                          "?datasource a nie:DataSource . "
Packit f01ec2
                          "?datasource nao:identifier \"%s\" . "
Packit f01ec2
                          "OPTIONAL { ?root nie:rootElementOf ?datasource } }",
Packit f01ec2
                          klass->miner_identifier);
Packit f01ec2
Packit f01ec2
  cursor = tracker_sparql_connection_query (self->priv->connection,
Packit f01ec2
                                            select->str,
Packit f01ec2
                                            cancellable,
Packit f01ec2
                                            &error);
Packit f01ec2
  g_string_free (select, TRUE);
Packit f01ec2
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_printerr ("Error while cleaning up old accounts: %s\n", error->message);
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  while (tracker_sparql_cursor_next (cursor, cancellable, NULL))
Packit f01ec2
    {
Packit f01ec2
      /* If the source we found is not in the current list, add
Packit f01ec2
       * it to the cleanup list.
Packit f01ec2
       * Note that the objects here in the list might *not* support
Packit f01ec2
       * documents, in case the switch has been disabled in System Settings.
Packit f01ec2
       * In fact, we only remove all the account data in case the account
Packit f01ec2
       * is really removed from the panel.
Packit f01ec2
       *
Packit f01ec2
       * Also, cleanup sources for which the version has increased.
Packit f01ec2
       */
Packit f01ec2
      datasource = tracker_sparql_cursor_get_string (cursor, 0, NULL);
Packit f01ec2
      element = g_list_find_custom (job->acc_objects, datasource,
Packit f01ec2
                                    cleanup_datasource_compare);
Packit f01ec2
Packit f01ec2
      if (element == NULL)
Packit f01ec2
        job->old_datasources = g_list_prepend (job->old_datasources,
Packit f01ec2
                                               g_strdup (datasource));
Packit f01ec2
Packit f01ec2
      old_version_str = tracker_sparql_cursor_get_string (cursor, 1, NULL);
Packit f01ec2
      if (old_version_str == NULL)
Packit f01ec2
        old_version = 1;
Packit f01ec2
      else
Packit f01ec2
        sscanf (old_version_str, "%d", &old_version);
Packit f01ec2
Packit f01ec2
      g_debug ("Stored version: %d - new version %d", old_version, klass->version);
Packit f01ec2
Packit f01ec2
      if ((element == NULL) || (old_version < klass->version))
Packit f01ec2
        {
Packit f01ec2
          job->old_datasources = g_list_prepend (job->old_datasources,
Packit f01ec2
                                                 g_strdup (datasource));
Packit f01ec2
        }
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  g_object_unref (cursor);
Packit f01ec2
Packit f01ec2
  /* cleanup the DB */
Packit f01ec2
  cleanup_job_do_cleanup (job, cancellable);
Packit f01ec2
Packit f01ec2
 out:
Packit f01ec2
  source = g_idle_source_new ();
Packit f01ec2
  g_source_set_name (source, "[gnome-online-miners] cleanup_old_accounts_done");
Packit f01ec2
  g_task_attach_source (task, source, cleanup_old_accounts_done);
Packit f01ec2
  g_source_unref (source);
Packit f01ec2
Packit f01ec2
  g_object_unref (task);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_cleanup_old_accounts (GomMiner *self,
Packit f01ec2
                                GList *content_objects,
Packit f01ec2
                                GList *acc_objects,
Packit f01ec2
                                GTask *task)
Packit f01ec2
{
Packit f01ec2
  CleanupJob *job = g_slice_new0 (CleanupJob);
Packit f01ec2
Packit f01ec2
  job->self = g_object_ref (self);
Packit f01ec2
  job->content_objects = content_objects;
Packit f01ec2
  job->acc_objects = acc_objects;
Packit f01ec2
Packit f01ec2
  g_task_set_task_data (task, job, NULL);
Packit f01ec2
  g_thread_pool_push (cleanup_pool, g_object_ref (task), NULL);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_refresh_db_real (GomMiner *self, GTask *task)
Packit f01ec2
{
Packit f01ec2
  GoaDocuments *documents;
Packit f01ec2
  GoaPhotos *photos;
Packit f01ec2
  GoaAccount *account;
Packit f01ec2
  GoaObject *object;
Packit f01ec2
  const gchar *provider_type;
Packit f01ec2
  GList *accounts, *content_objects, *acc_objects, *l;
Packit f01ec2
  GomMinerClass *miner_class = GOM_MINER_GET_CLASS (self);
Packit f01ec2
  gboolean skip_photos, skip_documents;
Packit f01ec2
Packit f01ec2
  content_objects = NULL;
Packit f01ec2
  acc_objects = NULL;
Packit f01ec2
Packit f01ec2
  accounts = goa_client_get_accounts (self->priv->client);
Packit f01ec2
  for (l = accounts; l != NULL; l = l->next)
Packit f01ec2
    {
Packit f01ec2
      object = l->data;
Packit f01ec2
Packit f01ec2
      account = goa_object_peek_account (object);
Packit f01ec2
      if (account == NULL)
Packit f01ec2
        continue;
Packit f01ec2
Packit f01ec2
      provider_type = goa_account_get_provider_type (account);
Packit f01ec2
      if (g_strcmp0 (provider_type, miner_class->goa_provider_type) != 0)
Packit f01ec2
        continue;
Packit f01ec2
Packit f01ec2
      acc_objects = g_list_append (acc_objects, g_object_ref (object));
Packit f01ec2
      skip_photos = skip_documents = TRUE;
Packit f01ec2
Packit f01ec2
      documents = goa_object_peek_documents (object);
Packit f01ec2
      photos = goa_object_peek_photos (object);
Packit f01ec2
Packit f01ec2
      if (gom_miner_supports_type (self, "photos") && photos != NULL)
Packit f01ec2
        skip_photos = FALSE;
Packit f01ec2
Packit f01ec2
      if (gom_miner_supports_type (self, "documents") && documents != NULL)
Packit f01ec2
        skip_documents = FALSE;
Packit f01ec2
Packit f01ec2
      if (skip_photos && skip_documents)
Packit f01ec2
        continue;
Packit f01ec2
Packit f01ec2
      content_objects = g_list_append (content_objects, g_object_ref (object));
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  g_list_free_full (accounts, g_object_unref);
Packit f01ec2
Packit f01ec2
  gom_miner_cleanup_old_accounts (self, content_objects, acc_objects, task);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
const gchar *
Packit f01ec2
gom_miner_get_display_name (GomMiner *self)
Packit f01ec2
{
Packit f01ec2
  return self->priv->display_name;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
static void
Packit f01ec2
gom_miner_insert_shared_content_in_thread_func (GTask *task,
Packit f01ec2
                                                gpointer source_object,
Packit f01ec2
                                                gpointer task_data,
Packit f01ec2
                                                GCancellable *cancellable)
Packit f01ec2
{
Packit f01ec2
  GomMiner *self = GOM_MINER (source_object);
Packit f01ec2
  GError *error;
Packit f01ec2
  InsertSharedContentData *data = (InsertSharedContentData *) task_data;
Packit f01ec2
  gchar *datasource_urn = NULL;
Packit f01ec2
  gchar *root_element_urn = NULL;
Packit f01ec2
Packit f01ec2
  datasource_urn = g_strdup_printf ("gd:goa-account:%s", data->account_id);
Packit f01ec2
  root_element_urn = g_strdup_printf ("gd:goa-account:%s:root-element", data->account_id);
Packit f01ec2
Packit f01ec2
  error = NULL;
Packit f01ec2
  gom_miner_ensure_datasource (self, datasource_urn, root_element_urn, cancellable, &error);
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, error);
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  error = NULL;
Packit f01ec2
  GOM_MINER_GET_CLASS (self)->insert_shared_content (self,
Packit f01ec2
                                                     data->service,
Packit f01ec2
                                                     self->priv->connection,
Packit f01ec2
                                                     datasource_urn,
Packit f01ec2
                                                     data->shared_id,
Packit f01ec2
                                                     data->shared_type,
Packit f01ec2
                                                     data->source_urn,
Packit f01ec2
                                                     cancellable,
Packit f01ec2
                                                     &error);
Packit f01ec2
  if (error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, error);
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  g_task_return_boolean (task, TRUE);
Packit f01ec2
Packit f01ec2
 out:
Packit f01ec2
  g_free (datasource_urn);
Packit f01ec2
  g_free (root_element_urn);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
void
Packit f01ec2
gom_miner_insert_shared_content_async (GomMiner *self,
Packit f01ec2
                                       const gchar *account_id,
Packit f01ec2
                                       const gchar *shared_id,
Packit f01ec2
                                       const gchar *shared_type,
Packit f01ec2
                                       const gchar *source_urn,
Packit f01ec2
                                       GCancellable *cancellable,
Packit f01ec2
                                       GAsyncReadyCallback callback,
Packit f01ec2
                                       gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  GTask *task = NULL;
Packit f01ec2
  GoaDocuments *documents;
Packit f01ec2
  GoaObject *object = NULL;
Packit f01ec2
  GoaPhotos *photos;
Packit f01ec2
  InsertSharedContentData *data;
Packit f01ec2
  gpointer service;
Packit f01ec2
Packit f01ec2
  task = g_task_new (self, cancellable, callback, user_data);
Packit f01ec2
  g_task_set_source_tag (task, gom_miner_insert_shared_content_async);
Packit f01ec2
Packit f01ec2
  if (self->priv->client_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, g_error_copy (self->priv->client_error));
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (self->priv->connection_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, g_error_copy (self->priv->connection_error));
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  object = goa_client_lookup_by_id (self->priv->client, account_id);
Packit f01ec2
  if (object == NULL)
Packit f01ec2
    {
Packit f01ec2
      /* throw error */
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  documents = goa_object_peek_documents (object);
Packit f01ec2
  photos = goa_object_peek_photos (object);
Packit f01ec2
Packit f01ec2
  if (g_strcmp0 (shared_type, "documents") == 0 && documents == NULL)
Packit f01ec2
    {
Packit f01ec2
      /* throw error */
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (g_strcmp0 (shared_type, "photos") == 0 && photos == NULL)
Packit f01ec2
    {
Packit f01ec2
      /* throw error */
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  service = GOM_MINER_GET_CLASS (self)->create_service (self, object, shared_type);
Packit f01ec2
  if (service == NULL)
Packit f01ec2
    {
Packit f01ec2
      /* throw error */
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  data = gom_insert_shared_content_data_new (self, account_id, shared_id, shared_type, source_urn, service);
Packit f01ec2
  g_task_set_task_data (task, data, (GDestroyNotify) gom_insert_shared_content_data_free);
Packit f01ec2
Packit f01ec2
  g_task_run_in_thread (task, gom_miner_insert_shared_content_in_thread_func);
Packit f01ec2
Packit f01ec2
 out:
Packit f01ec2
  g_clear_object (&object);
Packit f01ec2
  g_clear_object (&task);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
gboolean
Packit f01ec2
gom_miner_insert_shared_content_finish (GomMiner *self, GAsyncResult *res, GError **error)
Packit f01ec2
{
Packit f01ec2
  GTask *task;
Packit f01ec2
Packit f01ec2
  g_assert (g_task_is_valid (res, self));
Packit f01ec2
  task = G_TASK (res);
Packit f01ec2
Packit f01ec2
  g_assert (g_task_get_source_tag (task) == gom_miner_insert_shared_content_async);
Packit f01ec2
Packit f01ec2
  return g_task_propagate_boolean (task, error);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
void
Packit f01ec2
gom_miner_refresh_db_async (GomMiner *self,
Packit f01ec2
                            GCancellable *cancellable,
Packit f01ec2
                            GAsyncReadyCallback callback,
Packit f01ec2
                            gpointer user_data)
Packit f01ec2
{
Packit f01ec2
  GTask *task = NULL;
Packit f01ec2
Packit f01ec2
  task = g_task_new (self, cancellable, callback, user_data);
Packit f01ec2
  g_task_set_source_tag (task, gom_miner_refresh_db_async);
Packit f01ec2
Packit f01ec2
  if (self->priv->client_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, g_error_copy (self->priv->client_error));
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  if (self->priv->connection_error != NULL)
Packit f01ec2
    {
Packit f01ec2
      g_task_return_error (task, g_error_copy (self->priv->connection_error));
Packit f01ec2
      goto out;
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  gom_miner_refresh_db_real (self, task);
Packit f01ec2
Packit f01ec2
 out:
Packit f01ec2
  g_clear_object (&task);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
gboolean
Packit f01ec2
gom_miner_refresh_db_finish (GomMiner *self,
Packit f01ec2
                             GAsyncResult *res,
Packit f01ec2
                             GError **error)
Packit f01ec2
{
Packit f01ec2
  GTask *task;
Packit f01ec2
Packit f01ec2
  g_assert (g_task_is_valid (res, self));
Packit f01ec2
  task = G_TASK (res);
Packit f01ec2
Packit f01ec2
  g_assert (g_task_get_source_tag (task) == gom_miner_refresh_db_async);
Packit f01ec2
Packit f01ec2
  return g_task_propagate_boolean (task, error);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
void
Packit f01ec2
gom_miner_set_index_types (GomMiner *self, const char **index_types)
Packit f01ec2
{
Packit f01ec2
  g_strfreev (self->priv->index_types);
Packit f01ec2
  self->priv->index_types = g_strdupv ((gchar **) index_types);
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
const gchar **
Packit f01ec2
gom_miner_get_index_types (GomMiner *self)
Packit f01ec2
{
Packit f01ec2
  return (const gchar **) self->priv->index_types;
Packit f01ec2
}
Packit f01ec2
Packit f01ec2
gboolean
Packit f01ec2
gom_miner_supports_type (GomMiner *self, gchar *type)
Packit f01ec2
{
Packit f01ec2
  gboolean retval = FALSE;
Packit f01ec2
  guint i;
Packit f01ec2
Packit f01ec2
  for (i = 0; self->priv->index_types[i] != NULL; i++)
Packit f01ec2
    {
Packit f01ec2
      if (g_strcmp0 (self->priv->index_types[i], type) == 0)
Packit f01ec2
        {
Packit f01ec2
          retval = TRUE;
Packit f01ec2
          break;
Packit f01ec2
        }
Packit f01ec2
    }
Packit f01ec2
Packit f01ec2
  return retval;
Packit f01ec2
}