feat: db export && backup on Electron

This commit is contained in:
Tienson Qin
2023-12-11 18:04:36 +08:00
parent df7264f016
commit f25b7e06f9
7 changed files with 138 additions and 58 deletions

View File

@@ -37,14 +37,16 @@
"backup CONTENT under DIR :backup-dir or :version-file-dir
:backup-dir = `backup-dir`
:version-file-dir = `version-file-dir`"
[repo dir relative-path ext content]
[repo dir relative-path ext content & {:keys [add-desktop?]
:or {add-desktop? true}}]
{:pre [(contains? #{:backup-dir :version-file-dir} dir)]}
(let [dir* (case dir
:backup-dir (get-backup-dir repo relative-path)
:version-file-dir (get-version-file-dir repo relative-path))
new-path (node-path/join dir*
(str (string/replace (.toISOString (js/Date.)) ":" "_")
".Desktop" ext))]
(when add-desktop? ".Desktop")
ext))]
(fs-extra/ensureDirSync dir*)
(fs/writeFileSync new-path content)
(fs/statSync new-path)

View File

@@ -3,8 +3,9 @@
(:require ["path" :as node-path]
["fs-extra" :as fs]
["electron" :refer [app]]
[electron.logger :as logger]
[logseq.db.sqlite.db :as sqlite-db]))
;; [electron.logger :as logger]
[logseq.db.sqlite.db :as sqlite-db]
[electron.backup-file :as backup-file]))
(def close! sqlite-db/close!)
@@ -17,21 +18,23 @@
[]
(fs/ensureDirSync (get-graphs-dir)))
(defn open-db!
[db-name]
(let [graphs-dir (get-graphs-dir)]
(try (sqlite-db/open-db! graphs-dir db-name)
(catch :default e
(js/console.error e)
(logger/error (str e ": " db-name))
;; (fs/unlinkSync db-full-path)
))))
(defn new-db!
(defn ensure-graph-dir!
[db-name]
(ensure-graphs-dir!)
(let [graph-dir (node-path/join (get-graphs-dir) (sqlite-db/sanitize-db-name db-name))]
(fs/ensureDirSync graph-dir)
(open-db! db-name)))
graph-dir))
(defn save-db!
[db-name data]
(let [graph-dir (ensure-graph-dir! db-name)
[_db-name db-path] (sqlite-db/get-db-full-path (get-graphs-dir) db-name)]
(fs/writeFileSync db-path data)
(backup-file/backup-file graph-dir :backup-dir
""
".sqlite"
data
{:add-desktop? false})))
(def unlinked-graphs-dir "Unlinked graphs")
@@ -48,3 +51,19 @@
(when (fs/existsSync path)
(fs/ensureDirSync unlinked)
(fs/moveSync path new-path'))))
(comment
(defn open-db!
[db-name]
(let [graphs-dir (get-graphs-dir)]
(try (sqlite-db/open-db! graphs-dir db-name)
(catch :default e
(js/console.error e)
(logger/error (str e ": " db-name))
;; (fs/unlinkSync db-full-path)
))))
(defn new-db!
[db-name]
(ensure-graph-dir! db-name)
(open-db! db-name)))

View File

@@ -364,22 +364,9 @@
;; DB related IPCs start
;; Needs to be called first for a new graph
(defmethod handle :db-new [_window [_ repo]]
(db/new-db! repo))
(defmethod handle :db-transact-data [_window [_ repo data-str]]
(let [{:keys [tx-data tx-meta]} (reader/read-string data-str)]
(sqlite-db/transact! repo tx-data tx-meta)
nil))
;; Needs to be called first for an existing graph
(defmethod handle :get-initial-data [_window [_ repo _opts]]
(db/open-db! repo)
(dt/write-transit-str (sqlite-db/get-initial-data repo)))
(defmethod handle :get-other-data [_window [_ _repo _journal-block-uuids _opts]]
nil)
(defmethod handle :db-export [_window [_ repo data]]
(db/ensure-graph-dir! repo)
(db/save-db! repo data))
;; DB related IPCs End
@@ -737,6 +724,21 @@
(defmethod handle :system/info [^js _win _]
{:home-dir (.homedir os)})
(comment
;; Needs to be called first for a new graph
(defmethod handle :db-new [_window [_ repo]]
(db/new-db! repo))
;; Needs to be called first for an existing graph
(defmethod handle :get-initial-data [_window [_ repo _opts]]
(db/open-db! repo)
(dt/write-transit-str (sqlite-db/get-initial-data repo)))
(defmethod handle :db-transact-data [_window [_ repo data-str]]
(let [{:keys [tx-data tx-meta]} (reader/read-string data-str)]
(sqlite-db/transact! repo tx-data tx-meta)
nil)))
(defn set-ipc-handler! [window]
(let [main-channel "main"]
(.handle ipcMain main-channel

View File

@@ -48,14 +48,18 @@
[repo]
(str "/" repo ".sqlite"))
(comment
(defn- export-db-file
[repo]
;; TODO: get file name by repo
(p/let [^js pool (<get-opfs-pool repo)
path (get-repo-path repo)]
(when pool
(.exportFile ^js pool path)))))
(defn- <export-db-file
[repo]
(p/let [^js pool (<get-opfs-pool repo)
path (get-repo-path repo)]
(when pool
(.exportFile ^js pool path))))
(defn- <import-db
[repo data]
(p/let [^js pool (<get-opfs-pool repo)]
(when pool
(.importDB ^js pool (get-repo-path repo) data))))
(defn upsert-addr-content!
"Upsert addr+data-seq"
@@ -244,7 +248,19 @@
[_this repo]
(p/let [_ (close-db! repo)]
(remove-vfs! repo)
nil)))
nil))
(exportDB
[_this repo]
(<export-db-file repo))
(importDB
[this repo data]
;; FIXME: repo not exists yet
(when-not (string/blank? repo)
(p/let [_ (.createOrOpenDB this repo)
data (<import-db repo data)]
nil))))
(defn init
"web worker entry"

View File

@@ -2,7 +2,8 @@
"Backend of DB based graph"
(:require [frontend.persist-db.browser :as browser]
[frontend.persist-db.protocol :as protocol]
[promesa.core :as p]))
[promesa.core :as p]
[frontend.state :as state]))
(defonce opfs-db (browser/->InBrowser))
@@ -17,12 +18,6 @@
(defn <unsafe-delete [repo]
(protocol/<unsafe-delete (get-impl) repo))
;; FIXME: limit repo name's length
;; @shuyu Do we still need this?
(defn <new [repo]
{:pre [(<= (count repo) 56)]}
(protocol/<new (get-impl) repo))
(defn <transact-data [repo tx-data tx-meta]
(protocol/<transact-data (get-impl) repo tx-data tx-meta))
@@ -33,3 +28,22 @@
(p/let [ret (protocol/<fetch-initial-data (get-impl) repo opts)]
(js/console.log "fetch-initial-data" ret)
ret)))
(defn <export-db
[repo]
(protocol/<export-db (get-impl) repo))
(defn <import-db
[repo data]
(protocol/<import-db (get-impl) repo data))
;; FIXME: limit repo name's length
;; @shuyu Do we still need this?
(defn <new [repo]
{:pre [(<= (count repo) 56)]}
(p/do!
(let [current-repo (state/get-current-repo)]
(when-not (= repo current-repo)
;; switch graph
(<export-db current-repo))
(protocol/<new (get-impl) repo))))

View File

@@ -10,7 +10,8 @@
[frontend.util :as util]
[frontend.handler.notification :as notification]
[cljs-bean.core :as bean]
[frontend.state :as state]))
[frontend.state :as state]
[electron.ipc :as ipc]))
(defonce *sqlite (atom nil))
@@ -37,6 +38,15 @@
(ask-persist-permission!))
(notification/show! "It seems that OPFS is not supported on this browser, please upgrade it to the latest version or use another browser." :error))))))
(defn <export-db!
[repo data]
(cond
(util/electron?)
(ipc/ipc :db-export repo data)
:else
nil))
(defrecord InBrowser []
protocol/PersistentDB
(<new [_this repo]
@@ -76,6 +86,23 @@
(-> (p/let [_ (.createOrOpenDB sqlite repo)]
(.getInitialData sqlite repo))
(p/catch (fn [error]
(prn :debug :fetch-initial-data-error)
(prn :debug :fetch-initial-data-error repo)
(js/console.error error)
(notification/show! [:div (str "SQLiteDB fetch error: " error)] :error) {}))))))
(notification/show! [:div (str "SQLiteDB fetch error: " error)] :error) {})))))
(<export-db [_this repo]
(when-let [^js sqlite @*sqlite]
(-> (p/let [data (.exportDB sqlite repo)]
(<export-db! repo data))
(p/catch (fn [error]
(prn :debug :save-db-error repo)
(js/console.error error)
(notification/show! [:div (str "SQLiteDB save error: " error)] :error) {})))))
(<import-db [_this repo data]
(when-let [^js sqlite @*sqlite]
(-> (.importDB sqlite repo data)
(p/catch (fn [error]
(prn :debug :import-db-error repo)
(js/console.error error)
(notification/show! [:div (str "SQLiteDB import error: " error)] :error) {}))))))

View File

@@ -1,11 +1,11 @@
(ns frontend.persist-db.protocol
"Provides protocol for persisting db"
(:require))
"Provides protocol for persisting db")
;; TODO: exporting, importing support
(defprotocol PersistentDB
(<list-db [this])
(<new [this repo])
(<unsafe-delete [this repo])
(<list-db [this] "List all databases")
(<new [this repo] "Create or open a graph")
(<unsafe-delete [this repo] "Delete graph and its vfs")
(<transact-data [this repo tx-data tx-meta] "Transact data to db")
(<fetch-initial-data [this repo opts]))
(<fetch-initial-data [this repo opts] "Fetch Initial data")
(<export-db [this repo] "Save SQLite db")
(<import-db [this repo data] "Import SQLite db"))