summaryrefslogtreecommitdiffstats
path: root/sync/src/sync_collection.c
diff options
context:
space:
mode:
Diffstat (limited to 'sync/src/sync_collection.c')
-rw-r--r--sync/src/sync_collection.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/sync/src/sync_collection.c b/sync/src/sync_collection.c
new file mode 100644
index 0000000..88b2d05
--- /dev/null
+++ b/sync/src/sync_collection.c
@@ -0,0 +1,406 @@
+
+#include <glib.h>
+#include "sync_group.h"
+#include "sync_collection.h"
+
+G_DEFINE_TYPE (SyncCollection, sync_collection, G_TYPE_OBJECT);
+
+#define COLLECTION_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), SYNC_TYPE_COLLECTION, SyncCollectionPrivate))
+
+typedef struct _SyncCollectionPrivate SyncCollectionPrivate;
+
+enum {
+ STARTED,
+ PROGRESS,
+ CONFLICT,
+ FINISHED,
+ FAILED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct {
+ SyncGroup *group;
+ gdouble progress;
+ gchar *error;
+} SyncCollectionGroup;
+
+struct _SyncCollectionPrivate
+{
+ GList *groups;
+
+ gboolean started;
+ gdouble progress;
+ gint num_groups;
+ gint num_finished;
+};
+
+static void
+sync_collection_finalize (GObject *object)
+{
+ SyncCollection *collection = SYNC_COLLECTION (object);
+/* SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);*/
+
+ /* TODO: Guard against, or cater for this happening during a sync */
+ sync_collection_remove_all (collection);
+
+ G_OBJECT_CLASS (sync_collection_parent_class)->finalize (object);
+}
+
+static void
+sync_collection_class_init (SyncCollectionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ signals[STARTED] =
+ g_signal_new ("started",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SyncCollectionClass, started),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[PROGRESS] =
+ g_signal_new ("progress",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SyncCollectionClass, progress),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE, 1, G_TYPE_DOUBLE);
+ signals[CONFLICT] =
+ g_signal_new ("conflict",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SyncCollectionClass, conflict),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 0, G_TYPE_OBJECT);
+ signals[FINISHED] =
+ g_signal_new ("finished",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SyncCollectionClass, finished),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[FAILED] =
+ g_signal_new ("failed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SyncCollectionClass, failed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ g_type_class_add_private (klass, sizeof (SyncCollectionPrivate));
+
+ object_class->finalize = sync_collection_finalize;
+}
+
+static void
+sync_collection_init (SyncCollection *self)
+{
+}
+
+SyncCollection*
+sync_collection_new (void)
+{
+ return g_object_new (SYNC_TYPE_COLLECTION, NULL);
+}
+
+static void
+sync_collection_namespace_func (gpointer data, gpointer user_data)
+{
+ SyncCollectionGroup *col_group = data;
+ const gchar *namespace = user_data;
+
+ sync_group_set_namespace (col_group->group, namespace);
+}
+
+static void
+sync_collection_start_func (gpointer data, gpointer user_data)
+{
+ SyncCollectionGroup *col_group = data;
+ gboolean *success = user_data;
+
+ if (!sync_group_start (col_group->group))
+ *success = FALSE;
+}
+
+static void
+sync_collection_abort_func (gpointer data, gpointer user_data)
+{
+ SyncCollectionGroup *col_group = data;
+
+ sync_group_abort (col_group->group);
+}
+
+static void
+sync_collection_save_func (gpointer data, gpointer user_data)
+{
+ SyncCollectionGroup *col_group = data;
+ gboolean *success = user_data;
+
+ if (!sync_group_save (col_group->group))
+ *success = FALSE;
+}
+
+static void
+sync_collection_delete_func (gpointer data, gpointer user_data)
+{
+ SyncCollectionGroup *col_group = data;
+ gboolean *success = user_data;
+
+ if (!sync_group_delete (col_group->group))
+ *success = FALSE;
+}
+
+static gint
+sync_collection_find_func (gconstpointer a, gconstpointer b)
+{
+ const SyncCollectionGroup *col_group = a;
+ const SyncGroup *group = b;
+
+ if (col_group->group == group) return 0;
+ else return -1;
+}
+
+static void
+sync_collection_started_cb (SyncGroup *group, SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ if (!priv->started) {
+ priv->started = TRUE;
+ g_signal_emit (collection, signals[STARTED], 0);
+ }
+}
+
+static void
+sync_collection_progress_cb (SyncGroup *group, gdouble progress,
+ SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ SyncCollectionGroup *col_group = (SyncCollectionGroup *)
+ ((g_list_find_custom (priv->groups, group,
+ sync_collection_find_func))->data);
+
+ priv->progress -= col_group->progress;
+ col_group->progress = progress;
+ priv->progress += col_group->progress;
+
+ g_signal_emit (collection, signals[PROGRESS], 0,
+ priv->progress / (gdouble)priv->num_groups);
+}
+
+static void
+sync_collection_conflict_cb (SyncGroup *group, SyncCollection *collection)
+{
+ g_signal_emit (collection, signals[CONFLICT], 0, group);
+}
+
+static void
+sync_collection_finished (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ priv->num_finished ++;
+ if (priv->num_finished == priv->num_groups) {
+ GList *c;
+ gchar *error = NULL;
+ for (c = priv->groups; c; c = c->next) {
+ gchar *new_error;
+ SyncCollectionGroup *col_group = c->data;
+
+ col_group->progress = 0;
+ if (!col_group->error) continue;
+
+ if (!error) {
+ error = g_strdup (col_group->error);
+ continue;
+ }
+ new_error = g_strconcat (error, "\n",
+ col_group->error, NULL);
+ g_free (error);
+ error = new_error;
+
+ g_free (col_group->error);
+ col_group->error = NULL;
+ }
+ priv->num_finished = 0;
+ priv->progress = 0;
+ priv->started = FALSE;
+ if (!error) {
+ g_signal_emit (collection, signals[FINISHED], 0);
+ } else {
+ g_signal_emit (collection, signals[FAILED], 0, error);
+ g_free (error);
+ }
+ }
+}
+
+static void
+sync_collection_finished_cb (SyncGroup *group, SyncCollection *collection)
+{
+ sync_collection_finished (collection);
+}
+
+static void
+sync_collection_failed_cb (SyncGroup *group, const gchar *error,
+ SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ SyncCollectionGroup *col_group = (SyncCollectionGroup *)
+ ((g_list_find_custom (priv->groups, group,
+ sync_collection_find_func))->data);
+
+ col_group->error = g_strdup (error);
+ sync_collection_finished (collection);
+}
+
+static SyncCollectionGroup *
+sync_collection_group_new (SyncCollection *collection, SyncGroup *group)
+{
+ SyncCollectionGroup *col_group = g_new0 (SyncCollectionGroup, 1);
+ col_group->group = g_object_ref (group);
+
+ g_signal_connect (G_OBJECT (group), "started",
+ G_CALLBACK (sync_collection_started_cb), collection);
+ g_signal_connect (G_OBJECT (group), "progress",
+ G_CALLBACK (sync_collection_progress_cb), collection);
+ g_signal_connect (G_OBJECT (group), "conflict",
+ G_CALLBACK (sync_collection_conflict_cb), collection);
+ g_signal_connect (G_OBJECT (group), "finished",
+ G_CALLBACK (sync_collection_finished_cb), collection);
+ g_signal_connect (G_OBJECT (group), "failed",
+ G_CALLBACK (sync_collection_failed_cb), collection);
+
+ return col_group;
+}
+
+static void
+sync_collection_group_free (SyncCollection *collection,
+ SyncCollectionGroup *col_group)
+{
+ g_signal_handlers_disconnect_by_func (
+ col_group->group, sync_collection_started_cb, collection);
+ g_signal_handlers_disconnect_by_func (
+ col_group->group, sync_collection_progress_cb, collection);
+ g_signal_handlers_disconnect_by_func (
+ col_group->group, sync_collection_conflict_cb, collection);
+ g_signal_handlers_disconnect_by_func (
+ col_group->group, sync_collection_finished_cb, collection);
+ g_signal_handlers_disconnect_by_func (
+ col_group->group, sync_collection_failed_cb, collection);
+
+ g_object_unref (col_group->group);
+ g_free (col_group->error);
+ g_free (col_group);
+}
+
+void
+sync_collection_add_group (SyncCollection *collection,
+ SyncGroup *group)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ priv->groups = g_list_prepend (priv->groups, sync_collection_group_new (
+ collection, group));
+ priv->num_groups ++;
+}
+
+void
+sync_collection_set_namespace (SyncCollection *collection,
+ const gchar *namespace)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ g_list_foreach (priv->groups,
+ sync_collection_namespace_func, (gpointer)namespace);
+}
+
+GList *
+sync_collection_get_groups (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ return g_list_copy (priv->groups);
+}
+
+gboolean
+sync_collection_start (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ gboolean success = TRUE;
+
+ g_list_foreach (priv->groups,
+ sync_collection_start_func, &success);
+
+ return success;
+}
+
+void
+sync_collection_abort (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ g_list_foreach (priv->groups,
+ sync_collection_abort_func, collection);
+}
+
+void
+sync_collection_remove_group (SyncCollection *collection,
+ SyncGroup *group)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ GList *col_group;
+
+ col_group = g_list_find_custom (
+ priv->groups, group, sync_collection_find_func);
+ if (col_group) {
+ sync_collection_group_free (collection, (SyncCollectionGroup *)
+ col_group->data);
+ priv->groups = g_list_delete_link (priv->groups, col_group);
+ }
+}
+
+void
+sync_collection_remove_all (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+
+ while (priv->groups) {
+ SyncCollectionGroup *col_group = priv->groups->data;
+
+ sync_collection_group_free (collection, col_group);
+ priv->groups = g_list_delete_link (priv->groups, priv->groups);
+ }
+}
+
+gboolean
+sync_collection_delete (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ gboolean success = TRUE;
+
+ g_list_foreach (priv->groups,
+ sync_collection_delete_func, &success);
+
+ return success;
+}
+
+gboolean
+sync_collection_save (SyncCollection *collection)
+{
+ SyncCollectionPrivate *priv = COLLECTION_PRIVATE (collection);
+ gboolean success = TRUE;
+
+ g_list_foreach (priv->groups,
+ sync_collection_save_func, &success);
+
+ return success;
+}
+