Browse Source

refactor: add frontend.db.listener

Tienson Qin 2 years ago
parent
commit
e01846188a

+ 1 - 63
src/main/frontend/db.cljs

@@ -73,73 +73,11 @@
 
  [logseq.db.default built-in-pages-names built-in-pages])
 
-;; persisting DBs between page reloads
-(defn persist! [repo]
-  (let [key (datascript-db repo)
-        db (get-db repo)]
-    (when db
-      (let [db-str (if db (db->string db) "")]
-        (p/let [_ (db-persist/save-graph! key db-str)])))))
-
-(defonce persistent-jobs (atom {}))
-
-(defn clear-repo-persistent-job!
-  [repo]
-  (when-let [old-job (get @persistent-jobs repo)]
-    (js/clearTimeout old-job)))
-
-(defn persist-if-idle!
-  [repo]
-  (clear-repo-persistent-job! repo)
-  (let [job (js/setTimeout
-             (fn []
-               (if (and (state/input-idle? repo)
-                        (state/db-idle? repo)
-                        ;; It's ok to not persist here since new changes
-                        ;; will be notified when restarting the app.
-                        (not (state/whiteboard-route?)))
-                 (persist! repo)
-                 ;; (state/set-db-persisted! repo true)
-
-                 (persist-if-idle! repo)))
-             3000)]
-    (swap! persistent-jobs assoc repo job)))
-
-;; only save when user's idle
-
-(defonce *db-listener (atom nil))
-
-(defn- repo-listen-to-tx!
-  [repo conn]
-  (d/listen! conn :persistence
-             (fn [tx-report]
-               (when (not (:new-graph? (:tx-meta tx-report))) ; skip initial txs
-                 (if (util/electron?)
-                   (when-not (:dbsync? (:tx-meta tx-report))
-                     ;; sync with other windows if needed
-                     (p/let [graph-has-other-window? (ipc/ipc "graphHasOtherWindow" repo)]
-                       (when graph-has-other-window?
-                         (ipc/ipc "dbsync" repo {:data (db->string (:tx-data tx-report))}))))
-                   (do
-                     (state/set-last-transact-time! repo (util/time-ms))
-                     (persist-if-idle! repo)))
-
-                 (when-let [db-listener @*db-listener]
-                   (db-listener repo tx-report))))))
-
-(defn listen-and-persist!
-  [repo]
-  (when-let [conn (get-db repo false)]
-    (d/unlisten! conn :persistence)
-    (repo-listen-to-tx! repo conn)))
-
 (defn start-db-conn!
   ([repo]
    (start-db-conn! repo {}))
   ([repo option]
-   (conn/start! repo
-                (assoc option
-                       :listen-handler listen-and-persist!))))
+   (conn/start! repo option)))
 
 (defn new-block-id
   []

+ 70 - 0
src/main/frontend/db/listener.cljs

@@ -0,0 +1,70 @@
+(ns frontend.db.listener
+  "DB listeners"
+  (:require [frontend.db.conn :as conn]
+            [frontend.db.utils :as db-utils]
+            [frontend.db.persist :as db-persist]
+            [frontend.state :as state]
+            [frontend.util :as util]
+            [promesa.core :as p]
+            [electron.ipc :as ipc]
+            [datascript.core :as d]))
+
+;; persisting DBs between page reloads
+(defn persist! [repo]
+  (let [key (conn/datascript-db repo)
+        db (conn/get-db repo)]
+    (when db
+      (let [db-str (if db (db-utils/db->string db) "")]
+        (p/let [_ (db-persist/save-graph! key db-str)])))))
+
+(defonce persistent-jobs (atom {}))
+
+(defn clear-repo-persistent-job!
+  [repo]
+  (when-let [old-job (get @persistent-jobs repo)]
+    (js/clearTimeout old-job)))
+
+(defn persist-if-idle!
+  [repo]
+  (clear-repo-persistent-job! repo)
+  (let [job (js/setTimeout
+             (fn []
+               (if (and (state/input-idle? repo)
+                        (state/db-idle? repo)
+                        ;; It's ok to not persist here since new changes
+                        ;; will be notified when restarting the app.
+                        (not (state/whiteboard-route?)))
+                 (persist! repo)
+                 ;; (state/set-db-persisted! repo true)
+
+                 (persist-if-idle! repo)))
+             3000)]
+    (swap! persistent-jobs assoc repo job)))
+
+;; only save when user's idle
+
+(defonce *db-listener (atom nil))
+
+(defn repo-listen-to-tx!
+  [repo conn]
+  (d/listen! conn :persistence
+             (fn [tx-report]
+               (when (not (:new-graph? (:tx-meta tx-report))) ; skip initial txs
+                 (if (util/electron?)
+                   (when-not (:dbsync? (:tx-meta tx-report))
+                     ;; sync with other windows if needed
+                     (p/let [graph-has-other-window? (ipc/ipc "graphHasOtherWindow" repo)]
+                       (when graph-has-other-window?
+                         (ipc/ipc "dbsync" repo {:data (db-utils/db->string (:tx-data tx-report))}))))
+                   (do
+                     (state/set-last-transact-time! repo (util/time-ms))
+                     (persist-if-idle! repo)))
+
+                 (when-let [db-listener @*db-listener]
+                   (db-listener repo tx-report))))))
+
+(defn listen-and-persist!
+  [repo]
+  (when-let [conn (conn/get-db repo false)]
+    (d/unlisten! conn :persistence)
+    (repo-listen-to-tx! repo conn)))

+ 9 - 5
src/main/frontend/db/restore.cljs

@@ -18,8 +18,8 @@
             [promesa.core :as p]
             [frontend.util :as util]
             [cljs-time.core :as t]
-            [clojure.set :as set]))
-
+            [clojure.set :as set]
+            [frontend.db.listener :as db-listener]))
 
 (defn- old-schema?
   "Requires migration if the schema version is older than db-schema/version"
@@ -120,22 +120,25 @@
                                    data)
                                  (concat unloaded-pages)
                                  (remove nil?)))]
-    (d/unlisten! conn :persistence)
     (state/set-state! [repo :restore/unloaded-blocks] unloaded-block-ids)
     (state/set-state! [repo :restore/unloaded-pages :unloaded-pages] (set unloaded-pages))
     (p/loop [data (get-loading-data repo *data per-length)]
+      (d/unlisten! conn :persistence)
       (cond
         (or (not= repo (state/get-current-repo)) ; switched to another graph
             (empty? data))
         (do
           (state/set-state! [repo :restore/unloaded-blocks] nil)
           (state/set-state! [repo :restore/unloaded-pages] nil)
+          (db-listener/repo-listen-to-tx! repo conn)
           (let [end (util/time-ms)]
             (println "[debug] load others from SQLite: " (int (/ (- end start) 1000)) " seconds.")))
 
         (not (state/input-idle? repo {:diff 6000}))  ; wait until input is idle
-        (p/do! (p/delay 5000)
-               (p/recur (get-loading-data repo *data per-length)))
+        (p/do!
+         (db-listener/repo-listen-to-tx! repo conn)
+         (p/delay 5000)
+         (p/recur (get-loading-data repo *data per-length)))
 
         :else
         (let [datoms (->> data
@@ -154,6 +157,7 @@
           (util/profile (str "DB transact! " (count datoms) " datoms") (d/transact! conn datoms {:skip-persist? true}))
           (state/update-state! [repo :restore/unloaded-blocks]
                                (fn [ids] (set/difference ids (set (map #(gobj/get % "uuid") data)))))
+          (db-listener/repo-listen-to-tx! repo conn)
           (p/let [_ (p/delay 0)]
             (p/recur (get-loading-data repo *data per-length))))))))
 

+ 4 - 3
src/main/frontend/handler.cljs

@@ -44,7 +44,8 @@
             [lambdaisland.glogi :as log]
             [promesa.core :as p]
             [frontend.mobile.core :as mobile]
-            [frontend.db.react :as db-react]))
+            [frontend.db.react :as db-react]
+            [frontend.db.listener :as db-listener]))
 
 (defn set-global-error-notification!
   []
@@ -86,7 +87,7 @@
     (-> (db-restore/restore-graph! repo)
         (p/then
          (fn []
-           (db/listen-and-persist! repo)
+           (db-listener/listen-and-persist! repo)
            ;; try to load custom css only for current repo
            (ui-handler/add-style-if-exists!)
 
@@ -197,7 +198,7 @@
   (state/set-component! :editor/box editor/box)
   (command-palette/register-global-shortcut-commands))
 
-(reset! db/*db-listener outliner-db/after-transact-pipelines)
+(reset! db-listener/*db-listener outliner-db/after-transact-pipelines)
 
 (defn start!
   [render]

+ 4 - 9
src/main/frontend/handler/editor.cljs

@@ -56,7 +56,8 @@
             [logseq.graph-parser.util.block-ref :as block-ref]
             [logseq.graph-parser.util.page-ref :as page-ref]
             [promesa.core :as p]
-            [rum.core :as rum]))
+            [rum.core :as rum]
+            [frontend.db.listener :as db-listener]))
 
 ;; FIXME: should support multiple images concurrently uploading
 
@@ -1816,12 +1817,6 @@
         new-value (string/replace value full_text new-full-text)]
     (save-block-aux! block new-value {})))
 
-(defn- mark-last-input-time!
-  [repo]
-  (when repo
-    (state/set-editor-last-input-time! repo (util/time-ms))
-    (db/clear-repo-persistent-job! repo)))
-
 (defonce *auto-save-timeout (atom nil))
 (defn edit-box-on-change!
   [e _block id]
@@ -1830,7 +1825,7 @@
     (state/set-edit-content! id value false)
     (when @*auto-save-timeout
       (js/clearTimeout @*auto-save-timeout))
-    (mark-last-input-time! repo)
+    (editor-property/mark-last-input-time! repo)
     (reset! *auto-save-timeout
             (js/setTimeout
              (fn []
@@ -2690,7 +2685,7 @@
         top-block? (= (:block/left block) (:block/page block))
         single-block? (inside-of-single-block (.-target e))
         root-block? (= (:block.temp/container block) (str (:block/uuid block)))]
-    (mark-last-input-time! repo)
+    (editor-property/mark-last-input-time! repo)
     (cond
       (not= selected-start selected-end)
       (do

+ 11 - 2
src/main/frontend/handler/editor/property.cljs

@@ -10,7 +10,8 @@
             [frontend.util.drawer :as drawer]
             [frontend.util.property :as property]
             [goog.object :as gobj]
-            [logseq.graph-parser.util :as gp-util]))
+            [logseq.graph-parser.util :as gp-util]
+            [frontend.db.listener :as db-listener]))
 
 (defn clear-selection!
   []
@@ -35,6 +36,12 @@
         (or "")
         (subs 0 pos))))
 
+(defn mark-last-input-time!
+  [repo]
+  (when repo
+    (state/set-editor-last-input-time! repo (util/time-ms))
+    (db-listener/clear-repo-persistent-job! repo)))
+
 (defn edit-block!
   ([block pos id]
    (edit-block! block pos id nil))
@@ -69,7 +76,9 @@
                            (drawer/remove-logbook))]
            (clear-selection!)
            (if edit-input-id
-             (state/set-editing! edit-input-id content block text-range)
+             (do
+               (state/set-editing! edit-input-id content block text-range)
+               (mark-last-input-time! (state/get-current-repo)))
              ;; Block may not be rendered yet
              (js/setTimeout (fn [] (edit-block! block pos id (update opts :retry-times inc))) 10))))))))
 

+ 5 - 4
src/main/frontend/handler/events.cljs

@@ -70,7 +70,8 @@
             [logseq.db.schema :as db-schema]
             [logseq.graph-parser.config :as gp-config]
             [promesa.core :as p]
-            [rum.core :as rum]))
+            [rum.core :as rum]
+            [frontend.db.listener :as db-listener]))
 
 ;; TODO: should we move all events here?
 
@@ -130,7 +131,7 @@
 (defmethod handle :graph/added [[_ repo {:keys [empty-graph?]}]]
   (db/set-key-value repo :ast/version db-schema/ast-version)
   (search-handler/rebuild-indices!)
-  (db/persist! repo)
+  (db-listener/persist! repo)
   (plugin-handler/hook-plugin-app :graph-after-indexed {:repo repo :empty-graph? empty-graph?})
   (when (state/setups-picker?)
     (if empty-graph?
@@ -562,8 +563,8 @@
                 (catch :default e
                   (js/console.error e)))
               (state/set-current-repo! current-repo)
-              (db/listen-and-persist! current-repo)
-              (db/persist-if-idle! current-repo)
+              (db-listener/listen-and-persist! current-repo)
+              (db-listener/persist-if-idle! current-repo)
               (repo-config-handler/restore-repo-config! current-repo)
               (.watch mobile-util/fs-watcher #js {:path current-repo-dir})
               (when graph-switch-f (graph-switch-f current-repo true))

+ 6 - 5
src/main/frontend/handler/repo.cljs

@@ -33,7 +33,8 @@
             [medley.core :as medley]
             [logseq.common.path :as path]
             [logseq.common.config :as common-config]
-            [frontend.db.react :as react]))
+            [frontend.db.react :as react]
+            [frontend.db.listener :as db-listener]))
 
 ;; Project settings should be checked in two situations:
 ;; 1. User changes the config.edn directly in logseq.com (fn: alter-file)
@@ -359,7 +360,7 @@
 (defn start-repo-db-if-not-exists!
   [repo]
   (state/set-current-repo! repo)
-  (db/start-db-conn! repo))
+  (db/start-db-conn! repo {:listen-handler db-listener/listen-and-persist!}))
 
 (defn- setup-local-repo-if-not-exists-impl!
   []
@@ -369,7 +370,7 @@
           repo-dir (config/get-repo-dir repo)]
       (p/do! (fs/mkdir-if-not-exists repo-dir) ;; create memory://local
              (state/set-current-repo! repo)
-             (db/start-db-conn! repo)
+             (db/start-db-conn! repo {:listen-handler db-listener/listen-and-persist!})
              (when-not config/publishing?
                (let [dummy-notes (t :tutorial/dummy-notes)]
                  (create-dummy-notes-page repo dummy-notes)))
@@ -407,7 +408,7 @@
    (when (config/global-config-enabled?)
      (global-config-handler/restore-global-config!))
     ;; Don't have to unlisten the old listener, as it will be destroyed with the conn
-   (db/listen-and-persist! repo)
+   (db-listener/listen-and-persist! repo)
    (ui-handler/add-style-if-exists!)
    (state/set-db-restoring! false)))
 
@@ -447,7 +448,7 @@
     (p/do!
      (when before
        (before))
-     (db/persist! repo)
+     (db-listener/persist! repo)
      (when on-success
        (on-success)))
     (p/catch (fn [error]

+ 4 - 3
src/main/frontend/handler/web/nfs.cljs

@@ -20,7 +20,8 @@
             [goog.object :as gobj]
             [lambdaisland.glogi :as log]
             [logseq.graph-parser.util :as gp-util]
-            [promesa.core :as p]))
+            [promesa.core :as p]
+            [frontend.db.listener :as db-listener]))
 
 (defn remove-ignore-files
   [files dir-name nfs?]
@@ -138,7 +139,7 @@
                                      (state/add-repo! {:url repo :nfs? true})
                                      (state/set-loading-files! repo false)
                                      (when ok-handler (ok-handler {:url repo}))
-                                     (db/persist-if-idle! repo))))))
+                                     (db-listener/persist-if-idle! repo))))))
                 (p/catch (fn [error]
                            (log/error :nfs/load-files-error repo)
                            (log/error :exception error)))))))
@@ -275,7 +276,7 @@
       (search/reset-indice! repo)
       (db/remove-conn! repo)
       (db/clear-query-state!)
-      (db/start-db-conn! repo)
+      (db/start-db-conn! repo {:listen-handler db-listener/listen-and-persist!})
       (reload-dir! repo {:re-index? true
                          :ok-handler ok-handler}))))