Files
logseq/src/main/frontend/fs.cljs
Gabriel Horner 51ed2f94f1 Encapsulate global config state and add global watcher
Correct merge with local state and testing is still TODO
2022-09-08 12:34:27 +08:00

219 lines
6.4 KiB
Clojure

(ns frontend.fs
(:require [cljs-bean.core :as bean]
[frontend.config :as config]
[frontend.fs.nfs :as nfs]
[frontend.fs.node :as node]
[frontend.fs.capacitor-fs :as mobile]
[frontend.fs.bfs :as bfs]
[frontend.mobile.util :as mobile-util]
[frontend.fs.protocol :as protocol]
[frontend.util :as util]
[lambdaisland.glogi :as log]
[promesa.core :as p]
[frontend.db :as db]
[clojure.string :as string]
[frontend.encrypt :as encrypt]
[frontend.state :as state]))
(defonce nfs-record (nfs/->Nfs))
(defonce bfs-record (bfs/->Bfs))
(defonce node-record (node/->Node))
(defonce mobile-record (mobile/->Capacitorfs))
(defn local-db?
[dir]
(and (string? dir)
(config/local-db? (subs dir 1))))
(defn get-fs
[dir]
(let [bfs-local? (or (string/starts-with? dir "/local")
(string/starts-with? dir "local"))]
(cond
(and (util/electron?) (not bfs-local?))
node-record
(mobile-util/native-platform?)
mobile-record
(local-db? dir)
nfs-record
:else
bfs-record)))
(defn mkdir!
[dir]
(protocol/mkdir! (get-fs dir) dir))
(defn mkdir-recur!
[dir]
(protocol/mkdir-recur! (get-fs dir) dir))
(defn readdir
[dir]
(protocol/readdir (get-fs dir) dir))
(defn unlink!
"Should move the path to logseq/recycle instead of deleting it."
[repo path opts]
(protocol/unlink! (get-fs path) repo path opts))
(defn rmdir!
"Remove the directory recursively.
Warning: only run it for browser cache."
[dir]
(when-let [fs (get-fs dir)]
(when (= fs bfs-record)
(protocol/rmdir! fs dir))))
(defn write-file!
[repo dir path content opts]
(when content
(let [fs-record (get-fs dir)]
(p/let [md-or-org? (contains? #{"md" "markdown" "org"} (util/get-file-ext path))
content (if-not md-or-org? content (encrypt/encrypt content))]
(->
(p/let [opts (assoc opts
:error-handler
(fn [error]
(state/pub-event! [:instrument {:type :write-file/failed
:payload {:fs (type fs-record)
:user-agent (when js/navigator js/navigator.userAgent)
:path path
:content-length (count content)
:error-str (str error)
:error error}}])))
_ (protocol/write-file! (get-fs dir) repo dir path content opts)]
(when (= bfs-record fs-record)
(db/set-file-last-modified-at! repo (config/get-file-path repo path) (js/Date.))))
(p/catch (fn [error]
(log/error :file/write-failed {:dir dir
:path path
:error error})
;; Disable this temporarily
;; (js/alert "Current file can't be saved! Please copy its content to your local file system and click the refresh button.")
)))))))
(defn read-file
([dir path]
(let [fs (get-fs dir)
options (if (= fs bfs-record)
{:encoding "utf8"}
{})]
(read-file dir path options)))
([dir path options]
(protocol/read-file (get-fs dir) dir path options)))
(defn rename!
[repo old-path new-path]
(cond
; See https://github.com/isomorphic-git/lightning-fs/issues/41
(= old-path new-path)
(p/resolved nil)
:else
(let [[old-path new-path]
(map #(if (or (util/electron?) (mobile-util/native-platform?))
%
(str (config/get-repo-dir repo) "/" %))
[old-path new-path])]
(protocol/rename! (get-fs old-path) repo old-path new-path))))
(defn copy!
[repo old-path new-path]
(cond
(= old-path new-path)
(p/resolved nil)
:else
(let [[old-path new-path]
(map #(if (or (util/electron?) (mobile-util/native-platform?))
%
(str (config/get-repo-dir repo) "/" %))
[old-path new-path])]
(protocol/copy! (get-fs old-path) repo old-path new-path))))
(defn stat
[dir path]
(protocol/stat (get-fs dir) dir path))
(defn- get-record
[]
(cond
(util/electron?)
node-record
(mobile-util/native-platform?)
mobile-record
:else
nfs-record))
(defn open-dir
[ok-handler]
(let [record (get-record)]
(p/let [result (protocol/open-dir record ok-handler)]
(if (or (util/electron?)
(mobile-util/native-platform?))
(let [[dir & paths] (bean/->clj result)]
[(:path dir) paths])
result))))
(defn get-files
[path-or-handle ok-handler]
(let [record (get-record)
electron? (util/electron?)
mobile? (mobile-util/native-platform?)]
(p/let [result (protocol/get-files record path-or-handle ok-handler)]
(if (or electron? mobile?)
(let [result (bean/->clj result)]
(if electron? (rest result) result))
result))))
(defn watch-dir!
([dir] (watch-dir! dir {}))
([dir options] (protocol/watch-dir! (get-record) dir options)))
(defn unwatch-dir!
[dir]
(protocol/unwatch-dir! (get-record) dir))
(defn mkdir-if-not-exists
[dir]
(->
(when dir
(util/p-handle
(stat dir nil)
(fn [_stat])
(fn [_error]
(mkdir! dir))))
(p/catch (fn [error] (js/console.error error)))))
(defn create-if-not-exists
([repo dir path]
(create-if-not-exists repo dir path ""))
([repo dir path initial-content]
(let [path (if (util/absolute-path? path) path
(if (util/starts-with? path "/")
path
(str "/" path)))]
(->
(p/let [_stat (stat dir path)]
true)
(p/catch
(fn [_error]
(p/let [_ (write-file! repo dir path initial-content nil)]
false)))))))
(defn file-exists?
[dir path]
(util/p-handle
(stat dir path)
(fn [_stat] true)
(fn [_e] false)))
(defn dir-exists?
[dir]
(file-exists? dir ""))