Bladeren bron

Add (broken) support for local storage

Matthias Vogelgesang 7 jaren geleden
bovenliggende
commit
5d21dd9e97
3 gewijzigde bestanden met toevoegingen van 259 en 12 verwijderingen
  1. 190 5
      src/iridium-storage.c
  2. 13 0
      src/iridium-storage.h
  3. 56 7
      src/iridium-window.c

+ 190 - 5
src/iridium-storage.c

@@ -16,19 +16,206 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <string.h>
+#include <json-glib/json-glib.h>
 #include "iridium-config.h"
+#include "iridium-crypto.h"
 #include "iridium-storage.h"
+#include "iridium-note.h"
 
 struct _IridiumStorage
 {
   GObject  parent_instance;
-
-  GList *tags;
-  GList *notes;
+  gchar   *email;
+  gchar   *password;
+  gchar   *server;
 };
 
+typedef struct {
+  GFile *file;
+  GFileInputStream *stream;
+  JsonParser *parser;
+  gchar *email;
+  gchar *server;
+  gchar *password;
+} TaskData;
+
 G_DEFINE_TYPE (IridiumStorage, iridium_storage, G_TYPE_OBJECT)
 
+IridiumStorage *
+iridium_storage_new (void)
+{
+  return g_object_new (IRIDIUM_TYPE_STORAGE, NULL);
+}
+
+static void
+free_task_data (TaskData *data)
+{
+  g_free (data->email);
+  g_free (data->server);
+  g_free (data->password);
+  g_object_unref (data->parser);
+  g_object_unref (data->stream);
+  g_object_unref (data->file);
+  g_free (data);
+}
+
+static IridiumNote *
+deserialize_note (JsonObject *meta, JsonObject *data)
+{
+  IridiumNote *note;
+  GTimeVal time;
+  GDateTime *last_modified;
+
+  if (!g_time_val_from_iso8601 (json_object_get_string_member (meta, "created_at"), &time)) {
+    g_print ("Problem parsing\n");
+  }
+
+  last_modified = g_date_time_new_from_timeval_local (&time);
+
+  note = iridium_note_new (json_object_get_string_member (data, "title"),
+                           json_object_get_string_member (data, "text"),
+                           last_modified);
+
+  return note;
+}
+
+static GObject *
+deserialize_item (JsonObject *meta, const gchar *data)
+{
+  JsonObject *root;
+  g_autoptr(JsonParser) parser;
+  const gchar *type;
+  GError *error = NULL;
+
+  parser = json_parser_new_immutable ();
+  json_parser_load_from_data (parser, data, -1, &error);
+  type = json_object_get_string_member (meta, "content_type");
+  root = json_node_get_object (json_parser_get_root (parser));
+
+  if (!g_strcmp0 (type, "Note"))
+    return G_OBJECT (deserialize_note (meta, root));
+
+  return NULL;
+}
+
+static void
+on_json_parsed (GObject *object,
+                GAsyncResult *result,
+                gpointer user_data)
+{
+  GTask *task;
+  TaskData *data;
+  JsonObject *root;
+  JsonArray *array;
+  IridiumAuthParams *params;
+  GList *items = NULL;
+  GError *error = NULL;
+
+  task = G_TASK (user_data);
+  data = g_task_get_task_data (task);
+
+  if (!json_parser_load_from_stream_finish (data->parser, result, &error)) {
+    g_task_return_error (task, error);
+    return;
+  }
+
+  root = json_node_get_object (json_parser_get_root (data->parser));
+  array = json_object_get_array_member (root, "items");
+  params = iridium_crypto_auth_params_new ();
+  iridium_crypto_derive_keys (params, data->password);
+
+  for (guint i = 0; i < json_array_get_length (array); i++) {
+    JsonObject *data;
+    GObject *item;
+    const gchar *uuid;
+    const gchar *enc_item_key;
+    const gchar *enc_content;
+    gchar *content;
+
+    data = json_array_get_object_element (array, i);
+    uuid = json_object_get_string_member (data, "uuid");
+    enc_item_key = json_object_get_string_member (data, "enc_item_key");
+
+    if (!g_strcmp0 (enc_item_key, ""))
+      continue;
+
+    enc_content = json_object_get_string_member (data, "content");
+    content = iridium_crypto_decrypt_item (enc_content, params, enc_item_key, uuid);
+
+    if (content) {
+      item = deserialize_item (data, content);
+
+      if (item)
+        items = g_list_append (items, item);
+    }
+
+    g_free (content);
+  }
+
+  iridium_crypto_auth_params_free (params),
+  g_task_return_pointer (task, items, NULL);
+  g_object_unref (task);
+}
+
+static void
+on_json_read (GObject *object,
+              GAsyncResult *result,
+              gpointer user_data)
+{
+  GTask *task;
+  TaskData *data;
+  GError *error = NULL;
+
+  task = G_TASK (user_data);
+  data = g_task_get_task_data (task);
+  data->stream = g_file_read_finish (data->file, result, &error);
+
+  if (data->stream == NULL) {
+    g_task_return_error (task, error);
+    return;
+  }
+
+  data->parser = json_parser_new ();
+  json_parser_load_from_stream_async (data->parser, G_INPUT_STREAM (data->stream),
+                                      g_task_get_cancellable (task), on_json_parsed, task);
+}
+
+void
+iridium_storage_sync_local_async (IridiumStorage *storage,
+                                  const gchar *email,
+                                  const gchar *server,
+                                  const gchar *password,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+  /*
+   * The main purpose of this is to load dumped and encrypted JSON notes and
+   * store them if something changed.
+   */
+  GTask *task;
+  TaskData *data;
+
+  task = g_task_new (storage, cancellable, callback, user_data);
+  data = g_new0 (TaskData, 1);
+  data->file = g_file_new_for_path ("sn.json");
+  data->email = g_strdup (email);
+  data->server = g_strdup (server);
+  data->password = g_strdup (password);
+
+  g_task_set_task_data (task, data, (GDestroyNotify) free_task_data);
+  g_file_read_async (data->file, G_PRIORITY_DEFAULT, cancellable, on_json_read, task);
+}
+
+GList *
+iridium_storage_sync_local_finish (IridiumStorage *storage,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, storage), FALSE);
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
 
 static void
 iridium_storage_class_init (IridiumStorageClass *klass)
@@ -38,6 +225,4 @@ iridium_storage_class_init (IridiumStorageClass *klass)
 static void
 iridium_storage_init (IridiumStorage *self)
 {
-  self->tags = NULL;
-  self->notes = NULL;
 }

+ 13 - 0
src/iridium-storage.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
@@ -8,4 +9,16 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IridiumStorage, iridium_storage, IRIDIUM, STORAGE, GObject)
 
+IridiumStorage *iridium_storage_new                 (void);
+void            iridium_storage_sync_local_async    (IridiumStorage       *storage,
+                                                     const gchar          *email,
+                                                     const gchar          *server,
+                                                     const gchar          *password,
+                                                     GCancellable         *cancellable,
+                                                     GAsyncReadyCallback   callback,
+                                                     gpointer              user_data);
+GList *         iridium_storage_sync_local_finish   (IridiumStorage       *storage,
+                                                     GAsyncResult         *result,
+                                                     GError              **error);
+
 G_END_DECLS

+ 56 - 7
src/iridium-window.c

@@ -25,6 +25,7 @@
 #include "iridium-note.h"
 #include "iridium-note-row.h"
 #include "iridium-standard-file.h"
+#include "iridium-storage.h"
 #include "iridium-signin-dialog.h"
 #include "iridium-tag-row.h"
 #include "iridium-window.h"
@@ -55,6 +56,7 @@ struct _IridiumWindow
   guint              compile_handler;
 
   IridiumMarkdown       *markdown;
+  IridiumStorage        *storage;
   IridiumStandardFile   *client;
 };
 
@@ -274,20 +276,61 @@ on_standard_file_connected (GObject *object,
   }
 }
 
+static void
+on_storage_loaded (GObject *object,
+                   GAsyncResult *result,
+                   gpointer user_data)
+{
+  IridiumWindow *self;
+  IridiumStorage *storage;
+  GList *notes;
+  GError *error = NULL;
+
+  self = IRIDIUM_WINDOW (user_data);
+  storage = IRIDIUM_STORAGE (object);
+
+  notes = iridium_storage_sync_local_finish (storage, result, &error);
+
+  if (notes) {
+    IridiumTag *tag_all;
+
+    tag_all = iridium_tag_new ("All");
+
+    for (GList *it = g_list_first (notes); it != NULL; it = g_list_next (it)) {
+      IridiumNote *note;
+
+      note = IRIDIUM_NOTE (it->data);
+      iridium_note_add_tag (note, tag_all);
+      gtk_list_box_insert (self->note_list, iridium_note_row_new (note), -1);
+    }
+
+    g_list_free (notes);
+    gtk_widget_show_all (GTK_WIDGET (self->note_list));
+  }
+  else if (error != NULL) {
+    show_error_dialog (self, error);
+    g_error_free (error);
+  }
+}
+
 static void
 on_show (IridiumWindow *self, gpointer user_data)
 {
-  gchar *server;
   gchar *email;
+  gchar *server = NULL;
   gchar *password = NULL;
-  gboolean valid = TRUE;
+  gboolean valid_input;
 
-  server = g_settings_get_string (self->preferences, "server");
+  /* server = g_settings_get_string (self->preferences, "server"); */
   email = g_settings_get_string (self->preferences, "email");
 
-  if (strlen (server) > 0 && strlen (email) > 0) {
+  if (strlen (email) > 0) {
+  /* if (strlen (server) > 0 && strlen (email) > 0) { */
     password = secret_password_lookup_sync (STANDARD_FILE_SCHEMA, NULL, NULL,
-        "email", email, "server", server, NULL);
+        "email", email,
+        /* "server", server, */
+        NULL);
+    valid_input = TRUE;
   }
 
   if (password == NULL) {
@@ -309,13 +352,14 @@ on_show (IridiumWindow *self, gpointer user_data)
       g_settings_set_string (self->preferences, "email", email);
     }
     else {
-      valid = FALSE;
+      valid_input = FALSE;
     }
 
     gtk_widget_destroy (GTK_WIDGET (dialog));
   }
 
-  if (valid) {
+  if (valid_input) {
+#if 0
     gchar *text;
 
     text = g_strdup_printf ("Connecting to %s …", server);
@@ -324,6 +368,9 @@ on_show (IridiumWindow *self, gpointer user_data)
     gtk_revealer_set_reveal_child (self->notification_revealer, TRUE);
     iridium_standard_file_connect_async (self->client, server, email, password, NULL,
                                          on_standard_file_connected, self);
+#endif
+    iridium_storage_sync_local_async (self->storage, email, server, password, NULL,
+                                      on_storage_loaded, self);
   }
 
   secret_password_free (password);
@@ -382,6 +429,7 @@ iridium_window_constructed (GObject *object)
 
   self->markdown = iridium_markdown_new ();
   self->client = iridium_standard_file_new ();
+  self->storage = iridium_storage_new ();
   self->source_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
 
   style_data = g_resources_lookup_data ("/net/bloerg/Iridium/css/iridium-theme.css", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
@@ -418,6 +466,7 @@ iridium_window_dispose (GObject *object)
   g_clear_object (&self->content_binding);
   g_clear_object (&self->markdown);
   g_clear_object (&self->client);
+  g_clear_object (&self->storage);
   g_clear_object (&self->preferences);
   G_OBJECT_CLASS (iridium_window_parent_class)->dispose (object);
 }