handler.cljs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. (ns frontend.handler
  2. (:require [cljs-bean.core :as bean]
  3. [electron.ipc :as ipc]
  4. [electron.listener :as el]
  5. [frontend.components.editor :as editor]
  6. [frontend.components.page :as page]
  7. [frontend.config :as config]
  8. [frontend.db :as db]
  9. [frontend.db-schema :as db-schema]
  10. [frontend.db.conn :as conn]
  11. [frontend.error :as error]
  12. [frontend.handler.command-palette :as command-palette]
  13. [frontend.handler.common :as common-handler]
  14. [frontend.handler.events :as events]
  15. [frontend.handler.file :as file-handler]
  16. [frontend.handler.notification :as notification]
  17. [frontend.handler.page :as page-handler]
  18. [frontend.handler.repo :as repo-handler]
  19. [frontend.handler.ui :as ui-handler]
  20. [frontend.extensions.srs :as srs]
  21. [frontend.mobile.core :as mobile]
  22. [frontend.mobile.util :as mobile-util]
  23. [frontend.idb :as idb]
  24. [frontend.modules.instrumentation.core :as instrument]
  25. [frontend.modules.shortcut.core :as shortcut]
  26. [frontend.search :as search]
  27. [frontend.state :as state]
  28. [frontend.storage :as storage]
  29. [frontend.util :as util]
  30. [frontend.util.pool :as pool]
  31. [cljs.reader :refer [read-string]]
  32. [goog.object :as gobj]
  33. [lambdaisland.glogi :as log]
  34. [promesa.core :as p]
  35. [frontend.db.persist :as db-persist]))
  36. (defn set-global-error-notification!
  37. []
  38. (set! js/window.onerror
  39. (fn [message, source, lineno, colno, error]
  40. (when-not (error/ignored? message)
  41. (js/console.error error)
  42. ;; (notification/show!
  43. ;; (str "message=" message "\nsource=" source "\nlineno=" lineno "\ncolno=" colno "\nerror=" error)
  44. ;; :error
  45. ;; ;; Don't auto-hide
  46. ;; false)
  47. ))))
  48. (defn- watch-for-date!
  49. []
  50. (let [cards-last-check-time (atom (util/time-ms))
  51. f (fn []
  52. (let [repo (state/get-current-repo)]
  53. (when-not (state/nfs-refreshing?)
  54. ;; Don't create the journal file until user writes something
  55. (page-handler/create-today-journal!))))]
  56. (f)
  57. (js/setInterval f 5000)))
  58. (defn- instrument!
  59. []
  60. (let [total (srs/get-srs-cards-total)]
  61. (state/set-state! :srs/cards-due-count total)
  62. (state/pub-event! [:instrument {:type :flashcards/count
  63. :payload {:total (or total 0)}}])
  64. (state/pub-event! [:instrument {:type :blocks/count
  65. :payload {:total (db/blocks-count)}}])))
  66. (defn store-schema!
  67. []
  68. (storage/set :db-schema (assoc db-schema/schema
  69. :db/version db-schema/version)))
  70. (defn- get-me-and-repos
  71. []
  72. (let [me (and js/window.user (bean/->clj js/window.user))
  73. logged? (:name me)
  74. repos (if logged?
  75. (:repos me)
  76. [{:url config/local-repo}])]
  77. {:me me
  78. :logged? logged?
  79. :repos repos}))
  80. (defn restore-and-setup!
  81. [me repos logged? old-db-schema]
  82. (let [interval (atom nil)
  83. inner-fn (fn []
  84. (when (and @interval js/window.pfs)
  85. (js/clearInterval @interval)
  86. (reset! interval nil)
  87. (-> (p/all (db/restore!
  88. (assoc me :repos repos)
  89. old-db-schema
  90. (fn [repo]
  91. (file-handler/restore-config! repo false))))
  92. (p/then
  93. (fn []
  94. ;; try to load custom css only for current repo
  95. (ui-handler/add-style-if-exists!)
  96. ;; install after config is restored
  97. (shortcut/unlisten-all)
  98. (shortcut/refresh!)
  99. (cond
  100. (and (not logged?)
  101. (not (seq (db/get-files config/local-repo)))
  102. ;; Not native local directory
  103. (not (some config/local-db? (map :url repos)))
  104. (not (mobile-util/is-native-platform?)))
  105. (repo-handler/setup-local-repo-if-not-exists!)
  106. :else
  107. (state/set-db-restoring! false))
  108. (store-schema!)
  109. (state/pub-event! [:modal/nfs-ask-permission])
  110. (page-handler/init-commands!)
  111. (when (seq (:repos me))
  112. ;; FIXME: handle error
  113. (common-handler/request-app-tokens!
  114. (fn []
  115. (repo-handler/clone-and-pull-repos me))
  116. (fn []
  117. (js/console.error "Failed to request GitHub app tokens."))))
  118. (watch-for-date!)
  119. (file-handler/watch-for-current-graph-dir!)
  120. ;; (when-not (state/logged?)
  121. ;; (state/pub-event! [:after-db-restore repos]))
  122. ))
  123. (p/catch (fn [error]
  124. (log/error :db/restore-failed error))))))]
  125. ;; clear this interval
  126. (let [interval-id (js/setInterval inner-fn 50)]
  127. (reset! interval interval-id))))
  128. (defn- handle-connection-change
  129. [e]
  130. (let [online? (= (gobj/get e "type") "online")]
  131. (state/set-online! online?)))
  132. (defn set-network-watcher!
  133. []
  134. (js/window.addEventListener "online" handle-connection-change)
  135. (js/window.addEventListener "offline" handle-connection-change))
  136. (defn enable-datalog-console
  137. "Enables datalog console in browser provided by https://github.com/homebaseio/datalog-console"
  138. []
  139. (js/document.documentElement.setAttribute "__datalog-console-remote-installed__" true)
  140. (.addEventListener js/window "message"
  141. (fn [event]
  142. (let [conn (conn/get-conn)]
  143. (when-let [devtool-message (gobj/getValueByKeys event "data" ":datalog-console.client/devtool-message")]
  144. (let [msg-type (:type (read-string devtool-message))]
  145. (case msg-type
  146. :datalog-console.client/request-whole-database-as-string
  147. (.postMessage js/window #js {":datalog-console.remote/remote-message" (pr-str conn)} "*")
  148. nil)))))))
  149. (defn- get-repos
  150. []
  151. (let [logged? (state/logged?)
  152. me (state/get-me)]
  153. (p/let [nfs-dbs (db-persist/get-all-graphs)
  154. nfs-dbs (map (fn [db]
  155. {:url db :nfs? true}) nfs-dbs)]
  156. (cond
  157. logged?
  158. (concat
  159. nfs-dbs
  160. (:repos me))
  161. (seq nfs-dbs)
  162. nfs-dbs
  163. :else
  164. [{:url config/local-repo
  165. :example? true}]))))
  166. (defn on-load-events
  167. []
  168. (set! js/window.onload
  169. (fn []
  170. (instrument/init))))
  171. (defn clear-cache!
  172. []
  173. (notification/show! "Clearing..." :warning false)
  174. (p/let [_ (when (util/electron?)
  175. (ipc/ipc "clearCache"))
  176. _ (idb/clear-local-storage-and-idb!)]
  177. (js/setTimeout
  178. (fn [] (if (util/electron?)
  179. (ipc/ipc :reloadWindowPage)
  180. (js/window.location.reload)))
  181. 2000)))
  182. (defn- register-components-fns!
  183. []
  184. (state/set-page-blocks-cp! page/page-blocks-cp)
  185. (state/set-editor-cp! editor/box)
  186. (command-palette/register-global-shortcut-commands))
  187. (defn start!
  188. [render]
  189. (set-global-error-notification!)
  190. (let [db-schema (storage/get :db-schema)
  191. {:keys [me logged? repos]} (get-me-and-repos)]
  192. (when me (state/set-state! :me me))
  193. (register-components-fns!)
  194. (state/set-db-restoring! true)
  195. (render)
  196. (on-load-events)
  197. (set-network-watcher!)
  198. (mobile/init!)
  199. (util/indexeddb-check?
  200. (fn [_error]
  201. (notification/show! "Sorry, it seems that your browser doesn't support IndexedDB, we recommend to use latest Chrome(Chromium) or Firefox(Non-private mode)." :error false)
  202. (state/set-indexedb-support! false)))
  203. (events/run!)
  204. (p/let [repos (get-repos)]
  205. (state/set-repos! repos)
  206. (restore-and-setup! me repos logged? db-schema)
  207. (when (mobile-util/is-native-platform?)
  208. (p/do! (mobile-util/hide-splash))))
  209. (reset! db/*sync-search-indice-f search/sync-search-indice!)
  210. (db/run-batch-txs!)
  211. (file-handler/run-writes-chan!)
  212. (pool/init-parser-pool!)
  213. (when config/dev?
  214. (enable-datalog-console))
  215. (when (util/electron?)
  216. (el/listen!))
  217. (js/setTimeout instrument! (* 60 1000))))
  218. (defn stop! []
  219. (prn "stop!"))
  220. (defn quit-and-install-new-version!
  221. []
  222. (p/let [_ (el/persist-dbs!)
  223. _ (ipc/invoke "set-quit-dirty-state" false)]
  224. (ipc/ipc :quitAndInstall)))