fix: multiple windows clash (#8874)

* fix: multiple windows clash

* enhance: force all the ipc callback result to be nil
pull/8907/head
Tienson Qin 2023-03-25 10:32:32 +08:00 committed by GitHub
parent b1c61c7241
commit 011860e486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 120 deletions

View File

@ -21,6 +21,11 @@
[frontend.ui :as ui]
[promesa.core :as p]))
(defn- safe-api-call
"Force the callback result to be nil, otherwise, ipc calls could lead to
window crash."
[k f]
(js/window.apis.on k (fn [data] (f data) nil)))
(defn persist-dbs!
[]
@ -35,153 +40,148 @@
(defn listen-persistent-dbs!
[]
;; TODO: move "file-watcher" to electron.ipc.channels
(js/window.apis.on
"persistent-dbs"
(fn [_req]
(persist-dbs!))))
(safe-api-call "persistent-dbs" (fn [_data] (persist-dbs!))))
(defn ^:large-vars/cleanup-todo listen-to-electron!
[]
;; TODO: move "file-watcher" to electron.ipc.channels
(js/window.apis.on "file-watcher"
(safe-api-call "file-watcher"
(fn [data]
(let [{:keys [type payload]} (bean/->clj data)]
(watcher-handler/handle-changed! type payload)
(when (file-sync-handler/enable-sync?)
(sync/file-watch-handler type payload)))))
(js/window.apis.on "file-sync-progress"
(fn [data]
(let [payload (bean/->clj data)]
(state/set-state! [:file-sync/graph-state (:graphUUID payload) :file-sync/progress (:file payload)] payload))))
(safe-api-call "file-sync-progress"
(fn [data]
(let [payload (bean/->clj data)]
(state/set-state! [:file-sync/graph-state (:graphUUID payload) :file-sync/progress (:file payload)] payload))))
(js/window.apis.on "notification"
(fn [data]
(let [{:keys [type payload]} (bean/->clj data)
type (keyword type)
comp [:div (str payload)]]
(notification/show! comp type false))))
(safe-api-call "notification"
(fn [data]
(let [{:keys [type payload]} (bean/->clj data)
type (keyword type)
comp [:div (str payload)]]
(notification/show! comp type false))))
(js/window.apis.on "graphUnlinked"
(fn [data]
(let [repo (bean/->clj data)]
(repo-handler/remove-repo! repo))))
(safe-api-call "graphUnlinked"
(fn [data]
(let [repo (bean/->clj data)]
(repo-handler/remove-repo! repo))))
(js/window.apis.on "setGitUsernameAndEmail"
(fn []
(state/pub-event! [:modal/set-git-username-and-email])))
(safe-api-call "setGitUsernameAndEmail"
(fn []
(state/pub-event! [:modal/set-git-username-and-email])))
(js/window.apis.on "getCurrentGraph"
(fn []
(when-let [graph (state/get-current-repo)]
(ipc/ipc "setCurrentGraph" graph))))
(safe-api-call "getCurrentGraph"
(fn []
(when-let [graph (state/get-current-repo)]
(ipc/ipc "setCurrentGraph" graph))))
(js/window.apis.on "redirect"
(fn [data]
(let [{:keys [payload]} (bean/->clj data)
payload (update payload :to keyword)]
(route-handler/redirect! payload))))
(safe-api-call "redirect"
(fn [data]
(let [{:keys [payload]} (bean/->clj data)
payload (update payload :to keyword)]
(route-handler/redirect! payload))))
(js/window.apis.on "redirectWhenExists"
;; Redirect to the given page or block when the provided page or block exists.
;; Either :page-name or :block-id is required.
;; :page-name : the original-name of the page.
;; :block-id : uuid.
(fn [data]
(let [{:keys [page-name block-id file]} (bean/->clj data)]
(cond
page-name
(let [db-page-name (db-model/get-redirect-page-name page-name)
whiteboard? (db-model/whiteboard-page? db-page-name)]
;; No error handling required, as a page name is always valid
;; Open new page if the page does not exist
(if whiteboard?
(route-handler/redirect-to-whiteboard! page-name {:block-id block-id})
(editor-handler/insert-first-page-block-if-not-exists! db-page-name)))
(safe-api-call "redirectWhenExists"
;; Redirect to the given page or block when the provided page or block exists.
;; Either :page-name or :block-id is required.
;; :page-name : the original-name of the page.
;; :block-id : uuid.
(fn [data]
(let [{:keys [page-name block-id file]} (bean/->clj data)]
(cond
page-name
(let [db-page-name (db-model/get-redirect-page-name page-name)
whiteboard? (db-model/whiteboard-page? db-page-name)]
;; No error handling required, as a page name is always valid
;; Open new page if the page does not exist
(if whiteboard?
(route-handler/redirect-to-whiteboard! page-name {:block-id block-id})
(editor-handler/insert-first-page-block-if-not-exists! db-page-name)))
block-id
(if (db-model/get-block-by-uuid block-id)
(route-handler/redirect-to-page! block-id)
(notification/show! (str "Open link failed. Block-id `" block-id "` doesn't exist in the graph.") :error false))
block-id
(if (db-model/get-block-by-uuid block-id)
(route-handler/redirect-to-page! block-id)
(notification/show! (str "Open link failed. Block-id `" block-id "` doesn't exist in the graph.") :error false))
file
(if-let [db-page-name (db-model/get-file-page file false)]
(route-handler/redirect-to-page! db-page-name)
(notification/show! (str "Open link failed. File `" file "` doesn't exist in the graph.") :error false))))))
file
(if-let [db-page-name (db-model/get-file-page file false)]
(route-handler/redirect-to-page! db-page-name)
(notification/show! (str "Open link failed. File `" file "` doesn't exist in the graph.") :error false))))))
(js/window.apis.on "dbsync"
(fn [data]
(let [{:keys [graph tx-data]} (bean/->clj data)
tx-data (db/string->db (:data tx-data))]
(when-let [conn (db/get-db graph false)]
(d/transact! conn tx-data {:dbsync? true}))
(ui-handler/re-render-root!))))
(safe-api-call "dbsync"
(fn [data]
(let [{:keys [graph tx-data]} (bean/->clj data)
tx-data (db/string->db (:data tx-data))]
(when-let [conn (db/get-db graph false)]
(d/transact! conn tx-data {:dbsync? true}))
(ui-handler/re-render-root!))))
(js/window.apis.on "persistGraph"
;; electron is requesting window for persisting a graph in it's db
;; fire back "broadcastPersistGraphDone" on done
(fn [data]
(let [repo (bean/->clj data)
before-f #(notification/show!
(ui/loading (t :graph/persist))
:warning)
after-f #(ipc/ipc "broadcastPersistGraphDone")
error-f (fn []
(after-f)
(notification/show!
(t :graph/persist-error)
:error))
handlers {:before before-f
:on-success after-f
:on-error error-f}]
(repo-handler/persist-db! repo handlers))))
(safe-api-call "persistGraph"
;; electron is requesting window for persisting a graph in it's db
;; fire back "broadcastPersistGraphDone" on done
(fn [data]
(let [repo (bean/->clj data)
before-f #(notification/show!
(ui/loading (t :graph/persist))
:warning)
after-f #(ipc/ipc "broadcastPersistGraphDone")
error-f (fn []
(after-f)
(notification/show!
(t :graph/persist-error)
:error))
handlers {:before before-f
:on-success after-f
:on-error error-f}]
(repo-handler/persist-db! repo handlers))))
(js/window.apis.on "foundInPage"
(fn [data]
(let [data' (bean/->clj data)]
(state/set-state! [:ui/find-in-page :matches] data')
(dom/remove-style! (dom/by-id "search-in-page-input") :visibility)
(dom/set-text! (dom/by-id "search-in-page-placeholder") "")
(ui/focus-element "search-in-page-input")
true)))
(safe-api-call "foundInPage"
(fn [data]
(let [data' (bean/->clj data)]
(state/set-state! [:ui/find-in-page :matches] data')
(dom/remove-style! (dom/by-id "search-in-page-input") :visibility)
(dom/set-text! (dom/by-id "search-in-page-placeholder") "")
(ui/focus-element "search-in-page-input"))))
(js/window.apis.on "loginCallback"
(fn [code]
(user/login-callback code)))
(safe-api-call "loginCallback"
(fn [code]
(user/login-callback code)))
(js/window.apis.on "quickCapture"
(fn [args]
(state/pub-event! [:editor/quick-capture args])))
(safe-api-call "quickCapture"
(fn [args]
(state/pub-event! [:editor/quick-capture args])))
(js/window.apis.on "openNewWindowOfGraph"
;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage
;; No db cache persisting ensured. Should be handled by the caller
(fn [repo]
(ui-handler/open-new-window! repo)))
(safe-api-call "openNewWindowOfGraph"
;; Handle open new window in renderer, until the destination graph doesn't rely on setting local storage
;; No db cache persisting ensured. Should be handled by the caller
(fn [repo]
(ui-handler/open-new-window! repo)))
(js/window.apis.on "invokeLogseqAPI"
(fn [^js data]
(let [sync-id (.-syncId data)
method (.-method data)
args (.-args data)
ret-fn! #(ipc/invoke (str :electron.server/sync! sync-id) %)]
(safe-api-call "invokeLogseqAPI"
(fn [^js data]
(let [sync-id (.-syncId data)
method (.-method data)
args (.-args data)
ret-fn! #(ipc/invoke (str :electron.server/sync! sync-id) %)]
(try
(println "invokeLogseqAPI:" method)
(let [^js apis (aget js/window.logseq "api")]
(when-not (aget apis method)
(throw (js/Error. (str "MethodNotExist: " method))))
(-> (p/promise (apply js-invoke apis method args))
(p/then #(ret-fn! %))
(p/catch #(ret-fn! {:error %}))))
(catch js/Error e
(ret-fn! {:error (.-message e)}))))))
(try
(println "invokeLogseqAPI:" method)
(let [^js apis (aget js/window.logseq "api")]
(when-not (aget apis method)
(throw (js/Error. (str "MethodNotExist: " method))))
(-> (p/promise (apply js-invoke apis method args))
(p/then #(ret-fn! %))
(p/catch #(ret-fn! {:error %}))))
(catch js/Error e
(ret-fn! {:error (.-message e)}))))))
(js/window.apis.on "syncAPIServerState"
(fn [^js data]
(state/set-state! :electron/server (bean/->clj data)))))
(safe-api-call "syncAPIServerState"
(fn [^js data]
(state/set-state! :electron/server (bean/->clj data)))))
(defn listen!
[]

View File

@ -92,11 +92,13 @@
(re-render-root! {}))
([{:keys [clear-all-query-state?]
:or {clear-all-query-state? false}}]
{:post [(nil? %)]}
(when-let [component (state/get-root-component)]
(if clear-all-query-state?
(db/clear-query-state!)
(db/clear-query-state-without-refs-and-embeds!))
(rum/request-render component))))
(rum/request-render component))
nil))
(defn highlight-element!
[fragment]