From 0eed799ccffa4477ef9246dd0b67544a281a43c9 Mon Sep 17 00:00:00 2001 From: leizhe Date: Thu, 20 Jan 2022 23:25:30 +0800 Subject: [PATCH] fix(mobile): diff when write conflicts occur --- src/main/frontend/fs/capacitor_fs.cljs | 124 ++++++++++++++++++------- 1 file changed, 91 insertions(+), 33 deletions(-) diff --git a/src/main/frontend/fs/capacitor_fs.cljs b/src/main/frontend/fs/capacitor_fs.cljs index 6a755ef53..c9b3563e2 100644 --- a/src/main/frontend/fs/capacitor_fs.cljs +++ b/src/main/frontend/fs/capacitor_fs.cljs @@ -1,13 +1,16 @@ (ns frontend.fs.capacitor-fs - (:require [frontend.fs.protocol :as protocol] - [lambdaisland.glogi :as log] - [frontend.util :as futil] - [frontend.config :as config] + (:require ["@capacitor/filesystem" :refer [Encoding Filesystem]] [cljs-bean.core :as bean] - ["@capacitor/filesystem" :refer [Filesystem Encoding]] - [promesa.core :as p] [clojure.string :as string] - [frontend.mobile.util :as mobile-util])) + [frontend.config :as config] + [frontend.fs.protocol :as protocol] + [frontend.mobile.util :as mobile-util] + [frontend.util :as util] + [lambdaisland.glogi :as log] + [promesa.core :as p] + [frontend.encrypt :as encrypt] + [frontend.state :as state] + [frontend.db :as db])) (when (mobile-util/native-ios?) (defn iOS-ensure-documents! @@ -28,7 +31,7 @@ (when (string? uri) (-> uri (string/replace "file://" "") - (futil/url-decode)))) + (util/url-decode)))) (defn readdir "readdir recursively" @@ -51,10 +54,10 @@ (= file "bak"))))) files (->> files (map (fn [file] - (futil/node-path.join + (util/node-path.join d (if (mobile-util/native-ios?) - (futil/url-encode file) + (util/url-encode file) file))))) files-with-stats (p/all (mapv @@ -93,6 +96,70 @@ result (js->clj result :keywordize-keys true)] (map (fn [result] (update result :uri clean-uri)) result))) +(defn- contents-matched? + [disk-content db-content] + (when (and (string? disk-content) (string? db-content)) + (if (encrypt/encrypted-db? (state/get-current-repo)) + (p/let [decrypted-content (encrypt/decrypt disk-content)] + (= (string/trim decrypted-content) (string/trim db-content))) + (p/resolved (= (string/trim disk-content) (string/trim db-content)))))) + +(defn- write-file-impl! + [_this repo dir path content {:keys [ok-handler error-handler old-content skip-compare?]} stat] + (println (string/join "\n" [repo dir path content stat])) + (if skip-compare? + (p/catch + (p/let [result (.writeFile Filesystem (clj->js {:path path + :data content + :encoding (.-UTF8 Encoding) + :recursive true}))] + (when ok-handler + (ok-handler repo path result))) + (fn [error] + (if error-handler + (error-handler error) + (log/error :write-file-failed error)))) + + (p/let [disk-content (-> (p/chain (.readFile Filesystem (clj->js {:path path + :encoding (.-UTF8 Encoding)})) + #(js->clj % :keywordize-keys true) + :data) + (p/catch (fn [error] + (js/console.error error) + nil))) + disk-content (or disk-content "") + ext (string/lower-case (util/get-file-ext path)) + db-content (or old-content (db/get-file repo path) "") + contents-matched? (contents-matched? disk-content db-content) + pending-writes (state/get-write-chan-length)] + (cond + (and + (not= stat :not-found) ; file on the disk was deleted + (not contents-matched?) + (not (contains? #{"excalidraw" "edn" "css"} ext)) + (not (string/includes? path "/.recycle/")) + (zero? pending-writes)) + (p/let [disk-content (encrypt/decrypt disk-content)] + (state/pub-event! [:file/not-matched-from-disk path disk-content content])) + + :else + (-> + (p/let [result (.writeFile Filesystem (clj->js {:path path + :data content + :encoding (.-UTF8 Encoding) + :recursive true}))] + (p/let [content (if (encrypt/encrypted-db? (state/get-current-repo)) + (encrypt/decrypt content) + content)] + (db/set-file-content! repo path content)) + (when ok-handler + (ok-handler repo path result)) + result) + (p/catch (fn [error] + (if error-handler + (error-handler error) + (log/error :write-file-failed error))))))))) + (defrecord Capacitorfs [] protocol/Fs (mkdir! [_this dir] @@ -145,16 +212,16 @@ (-> (str dir "/" path) (string/replace "//" "/")))] (p/catch - (p/let [result (.deleteFile Filesystem - (clj->js - {:path path}))] - (when ok-handler - (ok-handler repo path result))) - (fn [error] - (if error-handler - (error-handler error) - (log/error :delete-file-failed error)))))) - (write-file! [_this repo dir path content {:keys [ok-handler error-handler]}] + (p/let [result (.deleteFile Filesystem + (clj->js + {:path path}))] + (when ok-handler + (ok-handler repo path result))) + (fn [error] + (if error-handler + (error-handler error) + (log/error :delete-file-failed error)))))) + (write-file! [this repo dir path content opts] (let [path (cond (= (mobile-util/platform) "ios") (js/encodeURI (js/decodeURI path)) @@ -165,19 +232,10 @@ :else (-> (str dir "/" path) (string/replace "//" "/")))] - (p/catch - (p/let [result (.writeFile Filesystem - (clj->js - {:path path - :data content - :encoding (.-UTF8 Encoding) - :recursive true}))] - (when ok-handler - (ok-handler repo path result))) - (fn [error] - (if error-handler - (error-handler error) - (log/error :write-file-failed error)))))) + (p/let [stat (p/catch + (.stat Filesystem (clj->js {:path path})) + (fn [_e] :not-found))] + (write-file-impl! this repo dir path content opts stat)))) (rename! [_this _repo _old-path _new-path] nil) (stat [_this dir path]