[epiphany/wip/ephy-sync: 123/126] sync-service: Move here the actual sync functions



commit 12a491660f649188506bd134bead45a217f748ae
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Tue Aug 16 02:32:10 2016 +0300

    sync-service: Move here the actual sync functions

 src/Makefile.am           |    2 -
 src/ephy-sync-bookmarks.c |  352 ---------------------------------------------
 src/ephy-sync-bookmarks.h |   38 -----
 src/ephy-sync-service.c   |  330 ++++++++++++++++++++++++++++++++++++++++++
 src/ephy-sync-service.h   |   70 +++++----
 src/prefs-dialog.c        |    3 +-
 6 files changed, 370 insertions(+), 425 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index a69db75..c42111e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -69,8 +69,6 @@ libephymain_la_SOURCES = \
        ephy-session.h                          \
        ephy-shell.c                            \
        ephy-shell.h                            \
-       ephy-sync-bookmarks.c                   \
-       ephy-sync-bookmarks.h                   \
        ephy-sync-crypto.c                      \
        ephy-sync-crypto.h                      \
        ephy-sync-secret.c                      \
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index 07ce082..b865751 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -19,8 +19,11 @@
 #include "config.h"
 #include "ephy-sync-service.h"
 
+#include "ephy-bookmark.h"
+#include "ephy-bookmarks-manager.h"
 #include "ephy-debug.h"
 #include "ephy-settings.h"
+#include "ephy-shell.h"
 #include "ephy-sync-crypto.h"
 #include "ephy-sync-secret.h"
 
@@ -29,6 +32,10 @@
 
 #define MOZILLA_TOKEN_SERVER_URL  "https://token.services.mozilla.com/1.0/sync/1.5";
 #define MOZILLA_FXA_SERVER_URL    "https://api.accounts.firefox.com/v1/";
+
+#define DUMMY_BOOKMARK_ID         "00000000000000000000000000000000"
+#define EPHY_BOOKMARKS_COLLECTION "ephy-bookmarks"
+
 #define EMAIL_REGEX               "^[a-zA-Z0-9_]([a-zA-Z0-9._]+[a-zA-Z0-9_])?@[a-z0-9.-]+$"
 
 struct _EphySyncService {
@@ -906,3 +913,326 @@ ephy_sync_service_release_next_storage_message (EphySyncService *self)
   else
     self->is_locked = FALSE;
 }
+
+static void
+log_all_message_info (const gchar *text,
+                      SoupMessage *message)
+{
+  LOG ("%s:", text);
+  LOG ("status_code: %u", message->status_code);
+  LOG ("response_body: %s", message->response_body->data);
+  LOG ("Retry-After: %s", soup_message_headers_get_one (message->response_headers, "Retry-After"));
+  LOG ("X-Weave-Backoff: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Backoff"));
+  LOG ("X-Last-Modified: %s", soup_message_headers_get_one (message->response_headers, "X-Last-Modified"));
+  LOG ("X-Weave-Timestamp: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Timestamp"));
+  LOG ("X-Weave-Records: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Records"));
+  LOG ("X-Weave-Next-Offset: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Next-Offset"));
+  LOG ("X-Weave-Quota-Remaining: %s", soup_message_headers_get_one (message->response_headers, 
"X-Weave-Quota-Remaining"));
+  LOG ("X-Weave-Alert: %s", soup_message_headers_get_one (message->response_headers, "X-Weave-Alert"));
+}
+
+static void
+create_bookmarks_storage_collection_response_cb (SoupSession *session,
+                                                 SoupMessage *message,
+                                                 gpointer     user_data)
+{
+  EphySyncService *service;
+
+  /* Code 412 means that the BSO already exists. Don't treat this as an error. */
+  if (message->status_code != 200 && message->status_code != 412)
+    LOG ("Failed to add the dummy BSO. Status code: %u, response: %s",
+         message->status_code, message->response_body->data);
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_create_bookmarks_storage_collection (EphySyncService *self)
+{
+  EphyBookmark *dummy;
+  gchar *endpoint;
+  gchar *bso;
+
+  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+  g_return_if_fail (ephy_sync_service_is_signed_in (self));
+
+  endpoint = g_strdup_printf ("storage/%s/%s", EPHY_BOOKMARKS_COLLECTION, DUMMY_BOOKMARK_ID);
+  dummy = ephy_bookmark_new (g_strdup (DUMMY_BOOKMARK_ID),
+                             g_strdup (DUMMY_BOOKMARK_ID),
+                             g_sequence_new (g_free));
+  ephy_bookmark_set_id (dummy, DUMMY_BOOKMARK_ID);
+  bso = ephy_bookmark_to_bso (dummy);
+
+  /* Send a dummy BSO to the Storage Server so it will create the
+   * EPHY_BOOKMARKS_COLLECTION collection if it doesn't exist already.
+   */
+  ephy_sync_service_send_storage_message (self, endpoint, SOUP_METHOD_PUT,
+                                          bso, -1, 0,
+                                          create_bookmarks_storage_collection_response_cb, NULL);
+
+  g_free (endpoint);
+  g_free (bso);
+}
+
+static void
+upload_bookmark_to_server_response_cb (SoupSession *session,
+                                       SoupMessage *message,
+                                       gpointer     user_data)
+{
+  EphySyncService *service;
+  EphyBookmarksManager *manager;
+  EphyBookmark *bookmark;
+  double last_modified;
+
+  if (message->status_code == 200) {
+    bookmark = EPHY_BOOKMARK (user_data);
+    last_modified = g_ascii_strtod (message->response_body->data, NULL);
+    ephy_bookmark_set_modified (bookmark, last_modified);
+    manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+    ephy_bookmarks_manager_save_to_file_async (manager, NULL, NULL, NULL);
+
+    LOG ("Successfully uploaded bookmark to server.");
+  } else if (message->status_code == 412) {
+    /* FIXME: A more recent value is on the server. See how to handle this. */
+  } else {
+    LOG ("Failed to upload bookmark to the server. Status code: %u, response: %s",
+         message->status_code, message->response_body->data);
+  }
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_upload_bookmark_to_server (EphySyncService *self,
+                                             EphyBookmark    *bookmark,
+                                             gboolean         force)
+{
+  gchar *endpoint;
+  gchar *bso;
+  double modified;
+
+  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+  g_return_if_fail (ephy_sync_service_is_signed_in (self));
+  g_return_if_fail (EPHY_IS_BOOKMARK (bookmark));
+
+  endpoint = g_strdup_printf ("storage/%s/%s",
+                              EPHY_BOOKMARKS_COLLECTION,
+                              ephy_bookmark_get_id (bookmark));
+  bso = ephy_bookmark_to_bso (bookmark);
+  modified = ephy_bookmark_get_modified (bookmark);
+  ephy_sync_service_send_storage_message (self, endpoint,
+                                          SOUP_METHOD_PUT, bso, -1,
+                                          force ? -1 : modified,
+                                          upload_bookmark_to_server_response_cb,
+                                          bookmark);
+
+  g_free (endpoint);
+  g_free (bso);
+}
+
+static void
+merge_local_and_remote_bookmarks_response_cb (SoupSession *session,
+                                              SoupMessage *message,
+                                              gpointer     user_data)
+{
+    EphySyncService *service;
+    EphyBookmarksManager *manager;
+    GSequence *bookmarks;
+    JsonParser *parser;
+    JsonArray *array;
+    GList *remotes = NULL;
+    GList *locals = NULL;
+    gboolean *marked_locals = NULL;
+    gboolean *marked_remotes = NULL;
+    gsize i;
+
+    service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+    manager = ephy_shell_get_bookmarks_manager (ephy_shell_get_default ());
+    bookmarks = ephy_bookmarks_manager_get_bookmarks (manager);
+    parser = json_parser_new ();
+    json_parser_load_from_data (parser, message->response_body->data, -1, NULL);
+    array = json_node_get_array (json_parser_get_root (parser));
+
+    /* Convert all BSOs to EphyBookmark objects. */
+    for (i = 0; i < json_array_get_length (array); i++) {
+      JsonObject *bso = json_array_get_object_element (array, i);
+      EphyBookmark *bookmark = ephy_bookmark_from_bso (bso);
+
+      if (g_strcmp0 (ephy_bookmark_get_id (bookmark), DUMMY_BOOKMARK_ID) == 0) {
+        g_object_unref (bookmark);
+        continue;
+      }
+
+      remotes = g_list_append (remotes, bookmark);
+    }
+
+    /* If we have no remote bookmarks, then we directly upload all the local
+     * bookmarks to the server.
+     */
+    if (g_list_length (remotes) == 0) {
+      for (GSequenceIter *iter = g_sequence_get_begin_iter (bookmarks);
+           !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+        ephy_sync_service_upload_bookmark_to_server (service, g_sequence_get (iter), TRUE);
+      goto out;
+    }
+
+    /* If we have no local bookmarks, then we add all the remote bookmarks to the
+     * local instance.
+     */
+    if (g_sequence_is_empty (bookmarks) == TRUE) {
+      for (GList *r = remotes; r != NULL; r = r->next)
+        ephy_bookmarks_manager_add_bookmark (manager, EPHY_BOOKMARK (r->data));
+      goto out;
+    }
+
+    /* If we have both local and remote bookmarks, then we merge them in the
+     * nicest way possible (see the two cases below).
+     */
+    for (GSequenceIter *iter = g_sequence_get_begin_iter (bookmarks);
+         !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter))
+      locals = g_list_append (locals, g_sequence_get (iter));
+
+    marked_locals = g_malloc0 (g_list_length (locals) * sizeof (gboolean));
+    marked_remotes = g_malloc0 (g_list_length (remotes) * sizeof (gboolean));
+
+    i = 0;
+    for (GList *l = locals; l != NULL; l = l->next, i++) {
+      EphyBookmark *local = EPHY_BOOKMARK (l->data);
+      const gchar *local_id = ephy_bookmark_get_id (local);
+      double local_modified = ephy_bookmark_get_modified (local);
+      const gchar *local_url = ephy_bookmark_get_url (local);
+      gsize j = 0;
+
+      for (GList *r = remotes; r != NULL; r = r->next, j++) {
+        if (marked_remotes[j] == FALSE) {
+          EphyBookmark *remote = EPHY_BOOKMARK (r->data);
+          const gchar *remote_id = ephy_bookmark_get_id (remote);
+          double remote_modified = ephy_bookmark_get_modified (remote);
+          const gchar *remote_url = ephy_bookmark_get_url (remote);
+
+          /* Case 1: same ids.
+           * Since ids are globally unique, having a bookmark on the server with
+           * the same id means that the bookmark has been synced before in the
+           * past. Keep the one with most recent modified timestamp.
+           */
+          if (g_strcmp0 (local_id, remote_id) == 0) {
+            if (local_modified > remote_modified) {
+              ephy_sync_service_upload_bookmark_to_server (service, local, TRUE);
+            } else if (remote_modified > local_modified) {
+              ephy_bookmarks_manager_remove_bookmark (manager, local);
+              ephy_bookmarks_manager_add_bookmark (manager, remote);
+            } else {
+              g_object_unref (remote);
+            }
+            marked_locals[i] = marked_remotes[j] = TRUE;
+            break;
+          }
+
+          /* Case 2: different ids, same urls.
+           * Merge tags into the local bookmark, keep the remote id and upload it
+           * to server. The add_tag functions will ignore the duplicates themselves.
+           */
+          if (g_strcmp0 (local_url, remote_url) == 0) {
+            GSequence *tags = ephy_bookmark_get_tags (remote);
+
+            for (GSequenceIter *it = g_sequence_get_begin_iter (tags);
+                 !g_sequence_iter_is_end (it); it = g_sequence_iter_next (it)) {
+              const gchar *tag = g_sequence_get (it);
+              ephy_bookmark_add_tag (local, tag);
+              ephy_bookmarks_manager_add_tag (manager, tag);
+            }
+
+            ephy_bookmark_set_id (local, remote_id);
+            ephy_sync_service_upload_bookmark_to_server (service, local, TRUE);
+            g_object_unref (remote);
+            marked_locals[i] = marked_remotes[j] = TRUE;
+            break;
+          }
+        }
+      }
+    }
+
+    /* The remaining unmarked local bookmarks will be directly uploaded to the server. */
+    i = 0;
+    for (GList *l = locals; l != NULL; l = l->next, i++)
+      if (marked_locals[i] == FALSE)
+        ephy_sync_service_upload_bookmark_to_server (service, EPHY_BOOKMARK (l->data), TRUE);
+
+    /* The remaining unmarked remote bookmarks will be added to the local instance. */
+    i = 0;
+    for (GList *r = remotes; r != NULL; r = r->next, i++)
+      if (marked_remotes[i] == FALSE)
+        ephy_bookmarks_manager_add_bookmark (manager, EPHY_BOOKMARK (r->data));
+
+    /* Save changes to file. */
+    ephy_bookmarks_manager_save_to_file_async (manager, NULL, NULL, NULL);
+
+  out:
+    g_object_unref (parser);
+    g_list_free (locals);
+    g_list_free (remotes);
+    g_free (marked_locals);
+    g_free (marked_remotes);
+
+    ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_merge_local_and_remote_bookmarks (EphySyncService *self)
+{
+  gchar *endpoint;
+
+  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+  g_return_if_fail (ephy_sync_service_is_signed_in (self));
+
+  endpoint = g_strdup_printf ("storage/%s?full=true", EPHY_BOOKMARKS_COLLECTION);
+  ephy_sync_service_send_storage_message (self, endpoint,
+                                          SOUP_METHOD_GET, NULL, -1, -1,
+                                          merge_local_and_remote_bookmarks_response_cb, NULL);
+  g_free (endpoint);
+}
+
+static void
+storage_server_response_default_cb (SoupSession *session,
+                                    SoupMessage *message,
+                                    gpointer     user_data)
+{
+  EphySyncService *service;
+
+  log_all_message_info ("storage_server_response_default_cb", message);
+
+  service = ephy_shell_get_global_sync_service (ephy_shell_get_default ());
+  ephy_sync_service_release_next_storage_message (service);
+}
+
+void
+ephy_sync_service_check_bookmarks_storage_collection (EphySyncService *self)
+{
+  gchar *endpoint;
+
+  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+  g_return_if_fail (ephy_sync_service_is_signed_in (self));
+
+  endpoint = g_strdup_printf ("storage/%s", EPHY_BOOKMARKS_COLLECTION);
+  ephy_sync_service_send_storage_message (self, endpoint,
+                                          SOUP_METHOD_GET, NULL, -1, -1,
+                                          storage_server_response_default_cb, NULL);
+  g_free (endpoint);
+}
+
+void
+ephy_sync_service_delete_bookmarks_storage_collection (EphySyncService *self)
+{
+  gchar *endpoint;
+
+  g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+  g_return_if_fail (ephy_sync_service_is_signed_in (self));
+
+  endpoint = g_strdup_printf ("storage/%s", EPHY_BOOKMARKS_COLLECTION);
+  ephy_sync_service_send_storage_message (self, endpoint,
+                                          SOUP_METHOD_DELETE, NULL, -1, -1,
+                                          storage_server_response_default_cb, NULL);
+  g_free (endpoint);
+}
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index d0a27f5..3246f70 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -19,6 +19,7 @@
 #ifndef EPHY_SYNC_SERVICE_H
 #define EPHY_SYNC_SERVICE_H
 
+#include "ephy-bookmark.h"
 #include "ephy-sync-utils.h"
 
 #include <glib-object.h>
@@ -30,37 +31,44 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (EphySyncService, ephy_sync_service, EPHY, SYNC_SERVICE, GObject)
 
-EphySyncService *ephy_sync_service_new                          (void);
-gboolean         ephy_sync_service_is_signed_in                 (EphySyncService *self);
-gchar           *ephy_sync_service_get_user_email               (EphySyncService *self);
-void             ephy_sync_service_set_user_email               (EphySyncService *self,
-                                                                 const gchar     *email);
-gchar           *ephy_sync_service_get_token                    (EphySyncService   *self,
-                                                                 EphySyncTokenType  type);
-void             ephy_sync_service_set_token                    (EphySyncService   *self,
-                                                                 gchar             *value,
-                                                                 EphySyncTokenType  type);
-void             ephy_sync_service_set_and_store_tokens         (EphySyncService   *self,
-                                                                 gchar             *value,
-                                                                 EphySyncTokenType  type,
-                                                                 ...) G_GNUC_NULL_TERMINATED;
-void             ephy_sync_service_clear_storage_credentials    (EphySyncService *self);
-void             ephy_sync_service_clear_tokens                 (EphySyncService *self);
-void             ephy_sync_service_destroy_session              (EphySyncService *self,
-                                                                 const gchar     *sessionToken);
-gboolean         ephy_sync_service_fetch_sync_keys              (EphySyncService *self,
-                                                                 const gchar     *email,
-                                                                 const gchar     *keyFetchToken,
-                                                                 const gchar     *unwrapBKey);
-void             ephy_sync_service_send_storage_message         (EphySyncService     *self,
-                                                                 gchar               *endpoint,
-                                                                 const gchar         *method,
-                                                                 gchar               *request_body,
-                                                                 double               modified_since,
-                                                                 double               unmodified_since,
-                                                                 SoupSessionCallback  callback,
-                                                                 gpointer             user_data);
-void             ephy_sync_service_release_next_storage_message (EphySyncService *self);
+EphySyncService *ephy_sync_service_new                                 (void);
+gboolean         ephy_sync_service_is_signed_in                        (EphySyncService *self);
+gchar           *ephy_sync_service_get_user_email                      (EphySyncService *self);
+void             ephy_sync_service_set_user_email                      (EphySyncService *self,
+                                                                        const gchar     *email);
+gchar           *ephy_sync_service_get_token                           (EphySyncService   *self,
+                                                                        EphySyncTokenType  type);
+void             ephy_sync_service_set_token                           (EphySyncService   *self,
+                                                                        gchar             *value,
+                                                                        EphySyncTokenType  type);
+void             ephy_sync_service_set_and_store_tokens                (EphySyncService   *self,
+                                                                        gchar             *value,
+                                                                        EphySyncTokenType  type,
+                                                                        ...) G_GNUC_NULL_TERMINATED;
+void             ephy_sync_service_clear_storage_credentials           (EphySyncService *self);
+void             ephy_sync_service_clear_tokens                        (EphySyncService *self);
+void             ephy_sync_service_destroy_session                     (EphySyncService *self,
+                                                                        const gchar     *sessionToken);
+gboolean         ephy_sync_service_fetch_sync_keys                     (EphySyncService *self,
+                                                                        const gchar     *email,
+                                                                        const gchar     *keyFetchToken,
+                                                                        const gchar     *unwrapBKey);
+void             ephy_sync_service_send_storage_message                (EphySyncService     *self,
+                                                                        gchar               *endpoint,
+                                                                        const gchar         *method,
+                                                                        gchar               *request_body,
+                                                                        double               modified_since,
+                                                                        double               
unmodified_since,
+                                                                        SoupSessionCallback  callback,
+                                                                        gpointer             user_data);
+void             ephy_sync_service_release_next_storage_message        (EphySyncService *self);
+void             ephy_sync_service_create_bookmarks_storage_collection (EphySyncService *self);
+void             ephy_sync_service_upload_bookmark_to_server           (EphySyncService *self,
+                                                                        EphyBookmark    *bookmark,
+                                                                        gboolean         force);
+void             ephy_sync_service_merge_local_and_remote_bookmarks    (EphySyncService *self);
+void             ephy_sync_service_check_bookmarks_storage_collection  (EphySyncService *self);
+void             ephy_sync_service_delete_bookmarks_storage_collection (EphySyncService *self);
 
 G_END_DECLS
 
diff --git a/src/prefs-dialog.c b/src/prefs-dialog.c
index d1e719c..d473129 100644
--- a/src/prefs-dialog.c
+++ b/src/prefs-dialog.c
@@ -35,7 +35,6 @@
 #include "ephy-session.h"
 #include "ephy-settings.h"
 #include "ephy-shell.h"
-#include "ephy-sync-bookmarks.h"
 #include "ephy-sync-secret.h"
 #include "ephy-sync-service.h"
 #include "clear-data-dialog.h"
@@ -297,7 +296,7 @@ server_message_received_cb (WebKitUserContentManager *manager,
                                             NULL);
 
     /* Create our own bookmarks BSO collection on the Storage Server. */
-    ephy_sync_bookmarks_create_storage_collection ();
+    ephy_sync_service_create_bookmarks_storage_collection (service);
 
     /* Translators: the %s refers to the email of the currently logged in user. */
     gtk_label_set_markup (GTK_LABEL (dialog->sync_sign_out_details),


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