/* * GNOME Online Miners - crawls through your online content * Copyright (C) 2014 Red Hat, Inc. * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * Author: Debarshi Ray * */ #include "config.h" #include "gom-application.h" #include "gom-dbus.h" #include "gom-miner.h" #define AUTOQUIT_TIMEOUT 5 /* seconds */ struct _GomApplication { GApplication parent; GCancellable *cancellable; GomDBus *skeleton; GomMiner *miner; GQueue *queue; GType miner_type; gboolean refreshing; }; struct _GomApplicationClass { GApplicationClass parent_class; }; enum { PROP_0, PROP_MINER_TYPE }; G_DEFINE_TYPE (GomApplication, gom_application, G_TYPE_APPLICATION); static void gom_application_refresh_db_cb (GObject *source, GAsyncResult *res, gpointer user_data); static void gom_application_insert_shared_content_cb (GObject *source, GAsyncResult *res, gpointer user_data) { GomApplication *self; GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data); GError *error; self = GOM_APPLICATION (g_application_get_default ()); g_application_release (G_APPLICATION (self)); error = NULL; if (!gom_miner_insert_shared_content_finish (GOM_MINER (source), res, &error)) { g_printerr ("Failed to insert shared content: %s\n", error->message); g_dbus_method_invocation_take_error (invocation, error); goto out; } gom_dbus_complete_insert_shared_content (self->skeleton, invocation); out: g_object_unref (invocation); } static gboolean gom_application_insert_shared_content (GomApplication *self, GDBusMethodInvocation *invocation, const gchar *account_id, const gchar *shared_id, const gchar *shared_type, const gchar *source_urn) { g_application_hold (G_APPLICATION (self)); gom_miner_insert_shared_content_async (self->miner, account_id, shared_id, shared_type, source_urn, self->cancellable, gom_application_insert_shared_content_cb, g_object_ref (invocation)); return TRUE; } static void gom_application_process_queue (GomApplication *self) { GDBusMethodInvocation *invocation = NULL; const gchar **index_types; if (self->refreshing) goto out; if (g_queue_is_empty (self->queue)) goto out; invocation = G_DBUS_METHOD_INVOCATION (g_queue_pop_head (self->queue)); index_types = g_object_get_data (G_OBJECT (invocation), "index-types"); gom_miner_set_index_types (self->miner, index_types); self->refreshing = TRUE; g_application_hold (G_APPLICATION (self)); gom_miner_refresh_db_async (self->miner, self->cancellable, gom_application_refresh_db_cb, g_object_ref (invocation)); out: g_clear_object (&invocation); } static void gom_application_refresh_db_cb (GObject *source, GAsyncResult *res, gpointer user_data) { GomApplication *self; GDBusMethodInvocation *invocation = user_data; GError *error = NULL; self = GOM_APPLICATION (g_application_get_default ()); g_application_release (G_APPLICATION (self)); self->refreshing = FALSE; gom_miner_refresh_db_finish (GOM_MINER (source), res, &error); if (error != NULL) { g_printerr ("Failed to refresh the DB cache: %s\n", error->message); g_dbus_method_invocation_take_error (invocation, error); goto out; } gom_dbus_complete_refresh_db (self->skeleton, invocation); out: g_object_unref (invocation); gom_application_process_queue (self); } static gboolean gom_application_refresh_db (GomApplication *self, GDBusMethodInvocation *invocation, const gchar *const *arg_index_types) { gchar **index_types; index_types = g_strdupv ((gchar **) arg_index_types); g_object_set_data_full (G_OBJECT (invocation), "index-types", index_types, (GDestroyNotify) g_strfreev); g_queue_push_tail (self->queue, g_object_ref (invocation)); gom_application_process_queue (self); return TRUE; } static gboolean gom_application_dbus_register (GApplication *application, GDBusConnection *connection, const gchar *object_path, GError **error) { GomApplication *self = GOM_APPLICATION (application); gboolean retval = FALSE; if (!G_APPLICATION_CLASS (gom_application_parent_class)->dbus_register (application, connection, object_path, error)) goto out; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton), connection, object_path, error)) goto out; retval = TRUE; out: return retval; } static void gom_application_dbus_unregister (GApplication *application, GDBusConnection *connection, const gchar *object_path) { GomApplication *self = GOM_APPLICATION (application); if (self->skeleton != NULL) { if (g_dbus_interface_skeleton_has_connection (G_DBUS_INTERFACE_SKELETON (self->skeleton), connection)) g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (self->skeleton), connection); } G_APPLICATION_CLASS (gom_application_parent_class)->dbus_unregister (application, connection, object_path); } static void gom_application_shutdown (GApplication *application) { GomApplication *self = GOM_APPLICATION (application); g_cancellable_cancel (self->cancellable); G_APPLICATION_CLASS (gom_application_parent_class)->shutdown (application); } static void gom_application_constructed (GObject *object) { GomApplication *self = GOM_APPLICATION (object); const gchar *display_name; G_OBJECT_CLASS (gom_application_parent_class)->constructed (object); self->miner = g_object_new (self->miner_type, NULL); display_name = gom_miner_get_display_name (self->miner); gom_dbus_set_display_name (self->skeleton, display_name); } static void gom_application_dispose (GObject *object) { GomApplication *self = GOM_APPLICATION (object); g_clear_object (&self->cancellable); g_clear_object (&self->miner); g_clear_object (&self->skeleton); if (self->queue != NULL) { g_queue_free_full (self->queue, g_object_unref); self->queue = NULL; } G_OBJECT_CLASS (gom_application_parent_class)->dispose (object); } static void gom_application_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GomApplication *self = GOM_APPLICATION (object); switch (prop_id) { case PROP_MINER_TYPE: self->miner_type = g_value_get_gtype (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gom_application_init (GomApplication *self) { self->cancellable = g_cancellable_new (); self->skeleton = gom_dbus_skeleton_new (); g_signal_connect_swapped (self->skeleton, "handle-insert-shared-content", G_CALLBACK (gom_application_insert_shared_content), self); g_signal_connect_swapped (self->skeleton, "handle-refresh-db", G_CALLBACK (gom_application_refresh_db), self); self->queue = g_queue_new (); } static void gom_application_class_init (GomApplicationClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); GApplicationClass *application_class = G_APPLICATION_CLASS (klass); oclass->constructed = gom_application_constructed; oclass->dispose = gom_application_dispose; oclass->set_property = gom_application_set_property; application_class->dbus_register = gom_application_dbus_register; application_class->dbus_unregister = gom_application_dbus_unregister; application_class->shutdown = gom_application_shutdown; g_object_class_install_property (oclass, PROP_MINER_TYPE, g_param_spec_gtype ("miner-type", "Miner type", "A GType representing the miner class", GOM_TYPE_MINER, G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE)); } GApplication * gom_application_new (const gchar *application_id, GType miner_type) { return g_object_new (GOM_TYPE_APPLICATION, "application-id", application_id, "flags", G_APPLICATION_IS_SERVICE, "inactivity-timeout", AUTOQUIT_TIMEOUT, "miner-type", miner_type, NULL); }