diff --git a/package.json b/package.json index 7890c53cb7..f63ef15e2c 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "react-native-randombytes": "^2.1.0", "react-native-vector-icons": "^1.3.4", "react-native-orientation": "^1.17.0", - "realm": "^0.11.1", + "realm": "^0.14.0", "react-native-status": "git+ssh://git@github.com/status-im/react-native-status" } } diff --git a/src/status_im/accounts/handlers.cljs b/src/status_im/accounts/handlers.cljs index 9b0e59f444..7533014d43 100644 --- a/src/status_im/accounts/handlers.cljs +++ b/src/status_im/accounts/handlers.cljs @@ -1,6 +1,6 @@ (ns status-im.accounts.handlers (:require [status-im.models.accounts :as accounts] - [re-frame.core :refer [register-handler after dispatch debug]] + [re-frame.core :refer [register-handler after dispatch dispatch-sync debug]] [status-im.utils.logging :as log] [status-im.components.react :refer [geth]] [status-im.utils.types :refer [json->clj]] @@ -9,6 +9,7 @@ [status-im.utils.identicon :refer [identicon]] [status-im.db :refer [default-view]] [status-im.utils.random :as random] + [status-im.persistence.realm.core :as realm] [status-im.i18n :refer [label]] [status-im.constants :refer [content-type-command-request]] [clojure.string :as str])) @@ -32,24 +33,31 @@ account {:public-key public-key :address address :name address - :photo-path (identicon address)}] - (log/debug "Created account: " result) + :photo-path (identicon address)} + ] + (log/debug "account-created: " account) (when (not (str/blank? public-key)) (do - (save-password password) - (dispatch [:add-account account]) - (when (not (:signed-up db)) (dispatch [:login-account address password])))))) + ;(save-password password) + (dispatch-sync [:add-account account]) + (dispatch [:login-account address password]))))) (register-handler :create-account (-> (fn [db [_ password]] (.createAccount geth password (fn [result] (account-created db result password))) db))) -(defn login [db address] +(defn logged-in [db address] (let [account (get-in db [:accounts address])] + (log/debug "Logged in: " address account) + (realm/close-account-realm) + (reset! realm/account-realm (realm/create-account-realm address)) (dispatch [:set :login {}]) - (dispatch [:set :current-account account]) - (dispatch [:initialize-protocol account]) + (dispatch [:set :is-logged-in true]) + (dispatch [:set :user-identity account]) + (dispatch [:save-console]) + + (dispatch [:initialize-account account]) (when (:signed-up db) (dispatch [:navigate-to-clean default-view])))) (register-handler :login-account @@ -60,7 +68,7 @@ success (zero? (count error))] (log/debug "Logged in account: " address result) (if success - (login db address) + (logged-in db address) (dispatch [:set-in [:login :error] error]))))) db))) diff --git a/src/status_im/accounts/screen.cljs b/src/status_im/accounts/screen.cljs index 61ab31be7c..ea9f1a361a 100644 --- a/src/status_im/accounts/screen.cljs +++ b/src/status_im/accounts/screen.cljs @@ -40,7 +40,8 @@ :key row-id}])) (defn create-account [event] - (dispatch [:console-create-account]) + ;(dispatch [:console-create-account]) + (dispatch-sync [:reset-app]) (dispatch [:navigate-to :chat "console"])) (defview accounts [] diff --git a/src/status_im/accounts/views/account.cljs b/src/status_im/accounts/views/account.cljs index af714d566e..63afee013e 100644 --- a/src/status_im/accounts/views/account.cljs +++ b/src/status_im/accounts/views/account.cljs @@ -16,7 +16,7 @@ (dispatch [:set-in [:login :address] address])) (defview account-view [{:keys [address photo-path name] :as account}] - [current-account [:get :current-account]] + [current-account [:get :user-identity]] [touchable-highlight {:onPress #(on-press address)} [view st/account-container diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 6f7eff59f2..8762730a95 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -43,7 +43,7 @@ (defn app-root [] (let [signed-up (subscribe [:get :signed-up]) view-id (subscribe [:get :view-id]) - account (subscribe [:get :current-account]) + account (subscribe [:get :user-identity]) keyboard-height (subscribe [:get :keyboard-height])] (log/debug "Current account: " @account) (r/create-class @@ -88,16 +88,13 @@ :my-profile [my-profile])))}))) (defn init [] - (dispatch-sync [:initialize-db]) + (dispatch-sync [:reset-app]) (dispatch [:initialize-crypt]) (dispatch [:initialize-geth]) - (dispatch [:load-accounts]) - (dispatch [:initialize-chats]) - ;protocol must be initialized after user enters password and we create account - ;(dispatch [:initialize-protocol]) + (dispatch [:load-user-phone-number]) - (dispatch [:load-contacts]) - (dispatch [:init-console-chat]) - (dispatch [:init-chat]) + + + ;(dispatch [:init-chat]) (init-back-button-handler!) (.registerComponent app-registry "StatusIm" #(r/reactify-component app-root))) diff --git a/src/status_im/chat/handlers.cljs b/src/status_im/chat/handlers.cljs index 97df9c4281..83bda90f99 100644 --- a/src/status_im/chat/handlers.cljs +++ b/src/status_im/chat/handlers.cljs @@ -15,7 +15,7 @@ [status-im.models.chats :as chats] [status-im.navigation.handlers :as nav] [status-im.utils.handlers :refer [register-handler] :as u] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.handlers.server :as server] [status-im.handlers.content-suggestions :refer [get-content-suggestions]] [status-im.utils.phone-number :refer [format-phone-number]] @@ -31,9 +31,10 @@ (assoc db :show-actions show-actions))) (register-handler :load-more-messages - (fn [{:keys [current-chat-id] :as db} _] - (let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?])] - (if all-loaded? + (fn [{:keys [is-logged-in current-chat-id] :as db} _] + (let [all-loaded? (get-in db [:chats current-chat-id :all-loaded?]) + account-realm-exists? (or (not= current-chat-id "console") is-logged-in)] + (if (or all-loaded? (not account-realm-exists?)) db (let [messages-path [:chats current-chat-id :messages] messages (get-in db messages-path) @@ -291,21 +292,22 @@ :content content}))))) (defn save-message-to-realm! - [{:keys [new-message current-chat-id]} _] - (when new-message + [{:keys [is-logged-in new-message current-chat-id]} _] + (when (and new-message is-logged-in) (messages/save-message current-chat-id new-message))) (defn save-commands-to-realm! - [{:keys [new-commands current-chat-id]} _] - (doseq [new-command new-commands] - (messages/save-message - current-chat-id - (dissoc new-command :rendered-preview :to-message)))) + [{:keys [is-logged-in new-commands current-chat-id]} _] + (when is-logged-in + (doseq [new-command new-commands] + (messages/save-message + current-chat-id + (dissoc new-command :rendered-preview :to-message))))) (defn dispatch-responded-requests! [{:keys [new-commands current-chat-id]} _] - (doseq [{:keys [to-message]} new-commands] - (when to-message + (doseq [{:keys [is-logged-in to-message]} new-commands] + (when (and to-message is-logged-in) (dispatch [:request-answered! current-chat-id to-message])))) (defn invoke-commands-handlers! @@ -409,6 +411,18 @@ ((enrich init-chat)) ((after load-commands!)))) + +(register-handler :save-console + (fn [db _] + (when-not (chats/chat-exists? "console") + (let [console-chat (get-in db [:chats "console"])] + (when console-chat + (do + (chats/create-chat console-chat) + (doseq [message (reverse (:messages console-chat))] + (messages/save-message "console" message)))))) + db)) + (defn initialize-chats [{:keys [loaded-chats] :as db} _] (let [chats (->> loaded-chats @@ -429,11 +443,13 @@ ((enrich initialize-chats) load-chats!)) (defn store-message! - [{:keys [new-message]} [_ {chat-id :from}]] - (messages/save-message chat-id new-message)) + [{:keys [is-logged-in new-message]} [_ {chat-id :from}]] + (if (or (not= chat-id "console") is-logged-in) + (messages/save-message chat-id new-message))) (defn dispatch-request! [{:keys [new-message]} [_ {chat-id :from}]] + (log/debug "Dispatching request: " new-message) (when (= (:content-type new-message) content-type-command-request) (dispatch [:add-request chat-id new-message]))) @@ -455,15 +471,20 @@ (messages/save-message chat-id msg)))) (defmethod nav/preload-data! :chat - [{:keys [current-chat-id] :as db} [_ _ id]] + [{:keys [is-logged-in current-chat-id] :as db} [_ _ id]] (let [chat-id (or id current-chat-id) messages (get-in db [:chats chat-id :messages]) - db' (assoc db :current-chat-id chat-id)] - (dispatch [:load-requests! chat-id]) + db' (assoc db :current-chat-id chat-id) + account-realm-exists? (or (not= chat-id "console") is-logged-in)] + (when account-realm-exists? + (dispatch [:load-requests! chat-id])) (if (seq messages) db' (-> db' - load-messages! + ((fn [db] + (if account-realm-exists? + (load-messages! db) + db))) init-chat)))) (defn prepare-chat @@ -525,17 +546,17 @@ (defn delete-messages! [{:keys [current-chat-id]} _] - (r/write + (r/write :account (fn [] - (r/delete (r/get-by-field :msgs :chat-id current-chat-id))))) + (r/delete :account (r/get-by-field :account :msgs :chat-id current-chat-id))))) (defn delete-chat! [{:keys [current-chat-id]} _] - (r/write - (fn [] - (-> (r/get-by-field :chats :chat-id current-chat-id) - (r/single) - (r/delete))))) + (r/write :account + (fn [] :account + (->> (r/get-by-field :account :chats :chat-id current-chat-id) + (r/single) + (r/delete :account))))) (register-handler :leave-group-chat ;; todo oreder of operations tbd diff --git a/src/status_im/chat/handlers/requests.cljs b/src/status_im/chat/handlers/requests.cljs index d229b0dc94..7789e5a445 100644 --- a/src/status_im/chat/handlers/requests.cljs +++ b/src/status_im/chat/handlers/requests.cljs @@ -1,14 +1,15 @@ (ns status-im.chat.handlers.requests (:require [re-frame.core :refer [after dispatch enrich]] [status-im.utils.handlers :refer [register-handler]] - [status-im.persistence.realm :as realm] + [status-im.persistence.realm.core :as realm] + [status-im.models.requests :as requests] [status-im.utils.handlers :as u])) (defn store-request! - [{:keys [new-request]}] - (realm/write - (fn [] - (realm/create :requests new-request)))) + [{:keys [is-logged-in new-request] :as db}] + (if (or (not= (:chat-id new-request) "console") is-logged-in) + (requests/save-request new-request) + db)) (defn add-request [db [_ chat-id {:keys [msg-id content]}]] @@ -24,9 +25,9 @@ (defn load-requests! [{:keys [current-chat-id] :as db} [_ chat-id]] (let [chat-id' (or chat-id current-chat-id) - requests (-> :requests - ;; todo maybe limit is needed - (realm/get-by-fields {:chat-id chat-id' + requests (-> ;; todo maybe limit is needed + (realm/get-by-fields :account :requests + {:chat-id chat-id' :status "open"}) (realm/sorted :added :desc) (realm/collection->map)) @@ -35,12 +36,11 @@ (defn mark-request-as-answered! [_ [_ chat-id message-id]] - (realm/write + (realm/write :account (fn [] - (-> :requests - (realm/get-by-fields - {:chat-id chat-id - :message-id message-id}) + (-> (realm/get-by-fields :account :requests + {:chat-id chat-id + :message-id message-id}) (realm/single) (.-status) (set! "answered"))))) diff --git a/src/status_im/chat/sign_up.cljs b/src/status_im/chat/sign_up.cljs index e4140eab16..e592ea2061 100644 --- a/src/status_im/chat/sign_up.cljs +++ b/src/status_im/chat/sign_up.cljs @@ -5,7 +5,8 @@ [status-im.protocol.state.storage :as s] [status-im.models.chats :as c] [status-im.components.styles :refer [default-chat-color]] - [status-im.utils.utils :refer [log on-error http-post toast]] + [status-im.utils.utils :refer [on-error http-post toast]] + [status-im.utils.logging :as log] [status-im.utils.random :as random] [status-im.utils.sms-listener :refer [add-sms-listener remove-sms-listener]] @@ -198,14 +199,15 @@ (defn create-chat [handler] (fn [db] (let [{:keys [new-chat] :as db'} (handler db)] - (when new-chat + (log/debug new-chat) + (when (and new-chat (not= (:chat-id new-chat) "console")) (c/create-chat new-chat)) (dissoc db' :new-chat)))) (def init (create-chat - (fn [{:keys [chats] :as db}] - (if (chats "console") + (fn [{:keys [is-logged-in chats] :as db}] + (if is-logged-in db (-> db (assoc-in [:chats "console"] console-chat) diff --git a/src/status_im/commands/handlers/loading.cljs b/src/status_im/commands/handlers/loading.cljs index ccecdc86e5..eee3ddc22a 100644 --- a/src/status_im/commands/handlers/loading.cljs +++ b/src/status_im/commands/handlers/loading.cljs @@ -4,7 +4,7 @@ [status-im.utils.handlers :as u] [status-im.utils.utils :refer [http-get toast]] [clojure.string :as s] - [status-im.persistence.realm :as realm] + [status-im.persistence.realm.core :as realm] [status-im.components.jail :as j] [status-im.utils.types :refer [json->clj]] [status-im.commands.utils :refer [reg-handler]])) @@ -13,12 +13,16 @@ (defn load-commands! [_ [identity]] + (let [is-console? (= identity "console") + schema (if is-console? + :base + :account)] (dispatch [::fetch-commands! identity]) ;; todo uncomment - #_(if-let [{:keys [file]} (realm/get-one-by-field :commands :chat-id - identity)] + #_(if-let [{:keys [file]} (realm/get-one-by-field schema :commands + :chat-id identity)] (dispatch [::parse-commands! identity file]) - (dispatch [::fetch-commands! identity]))) + (dispatch [::fetch-commands! identity])))) (defn fetch-commands! [db [identity]] @@ -73,7 +77,11 @@ (defn save-commands-js! [_ [id file]] - (realm/create-object :commands {:chat-id id :file file})) + (let [is-console? (= id "console") + schema (if is-console? + :base + :account)] + (realm/create-object schema :commands {:chat-id id :file file}))) (defn loading-failed! [db [id reason details]] diff --git a/src/status_im/contacts/validations.cljs b/src/status_im/contacts/validations.cljs index f2aa252434..dc8f7b7938 100644 --- a/src/status_im/contacts/validations.cljs +++ b/src/status_im/contacts/validations.cljs @@ -1,14 +1,14 @@ (ns status-im.contacts.validations (:require [cljs.spec :as s] [cljsjs.web3] - [status-im.persistence.realm :as realm])) + [status-im.persistence.realm.core :as realm])) (defn is-address? [s] (.isAddress js/Web3.prototype s)) (defn unique-identity? [identity] (println identity) - (not (realm/exists? :contacts :whisper-identity identity))) + (not (realm/exists? :account :contacts :whisper-identity identity))) (defn valid-length? [identity] (let [length (count identity)] diff --git a/src/status_im/db.cljs b/src/status_im/db.cljs index 8eefb216ad..0f1887ea9e 100644 --- a/src/status_im/db.cljs +++ b/src/status_im/db.cljs @@ -11,8 +11,9 @@ ;; initial state of app-db (def app-db {:identity-password "replace-me-with-user-entered-password" :identity "me" + :is-logged-in false :accounts {} - :current-account false + :user-identity nil :contacts [] :contacts-ids #{} :selected-contacts #{} @@ -23,7 +24,7 @@ :chats-updated-signal 0 :show-actions false :selected-participants #{} - :signed-up true + :signed-up false :view-id default-view :navigation-stack (list default-view) ;; TODO fix hardcoded values diff --git a/src/status_im/discovery/model.cljs b/src/status_im/discovery/model.cljs index 6547321ff7..7b8a72b3a8 100644 --- a/src/status_im/discovery/model.cljs +++ b/src/status_im/discovery/model.cljs @@ -1,12 +1,11 @@ (ns status-im.discovery.model ;status-im.models.discoveries (:require [status-im.utils.logging :as log] - [status-im.persistence.realm :as realm] - [status-im.persistence.realm :as r])) + [status-im.persistence.realm.core :as r])) (defn get-tag [tag] (log/debug "Getting tag: " tag) - (-> (r/get-by-field :tag :name tag) + (-> (r/get-by-field :base :tag :name tag) (r/single-cljs))) (defn decrease-tag-counter [tag] @@ -15,18 +14,20 @@ (if tag-object (let [counter (dec (:count tag-object))] (if (zero? counter) - (realm/delete tag-object) - (realm/create :tag {:name tag - :count counter} - true)))))) + (r/delete :base tag-object) + (r/create :base :tag + {:name tag + :count counter} + true)))))) (defn increase-tag-counter [tag] (let [tag (:name tag) tag-object (get-tag tag)] (if tag-object - (realm/create :tag {:name tag - :count (inc (:count tag-object))} - true)))) + (r/create :base :tag + {:name tag + :count (inc (:count tag-object))} + true)))) (defn decrease-tags-counter [tags] (doseq [tag tags] @@ -37,45 +38,46 @@ (increase-tag-counter tag))) (defn get-tags [whisper-id] - (:tags (-> (r/get-by-field :discoveries :whisper-id whisper-id) + (:tags (-> (r/get-by-field :base :discoveries :whisper-id whisper-id) (r/single-cljs)))) (defn- create-discovery [{:keys [tags] :as discovery}] (log/debug "Creating discovery: " discovery tags) - (realm/create :discoveries discovery true) + (r/create :base :discoveries discovery true) (increase-tags-counter tags)) (defn- update-discovery [{:keys [whisper-id tags] :as discovery}] (let [old-tags (get-tags whisper-id) tags (map :name tags)] (decrease-tags-counter old-tags) - (realm/create :discoveries discovery true) + (r/create :base :discoveries discovery true) (increase-tags-counter tags))) (defn- discovery-exist? [discoveries discovery] (some #(= (:whisper-id discovery) (:whisper-id %)) discoveries)) (defn discovery-list [] - (->> (-> (r/get-all :discoveries) + (->> (-> (r/get-all :base :discoveries) (r/sorted :last-updated :desc) r/collection->map) (map #(update % :tags vals)))) (defn- add-discoveries [discoveries] - (realm/write (fn [] - (let [db-discoveries (discovery-list)] - (mapv (fn [discovery] - (if-not (discovery-exist? db-discoveries - discovery) - (create-discovery discovery) - (update-discovery discovery))) - discoveries))))) + (r/write :base + (fn [] + (let [db-discoveries (discovery-list)] + (mapv (fn [discovery] + (if-not (discovery-exist? db-discoveries + discovery) + (create-discovery discovery) + (update-discovery discovery))) + discoveries))))) (defn save-discoveries [discoveries] (add-discoveries discoveries)) (defn discoveries-by-tag [tag limit] - (let [discoveries (-> (r/get-by-filter :discoveries (str "tags.name = '" tag "'")) + (let [discoveries (-> (r/get-by-filter :base :discoveries (str "tags.name = '" tag "'")) (r/sorted :last-updated :desc))] (log/debug "Discoveries by tag: " tag) (if (pos? limit) @@ -83,7 +85,7 @@ discoveries))) (defn all-tags [] - (-> (r/get-all :tag) + (-> (r/get-all :base :tag) (r/sorted :count :desc) r/collection->map)) diff --git a/src/status_im/group_settings/handlers.cljs b/src/status_im/group_settings/handlers.cljs index 6f5e94d558..0c0521bcfd 100644 --- a/src/status_im/group_settings/handlers.cljs +++ b/src/status_im/group_settings/handlers.cljs @@ -1,7 +1,7 @@ (ns status-im.group-settings.handlers (:require [re-frame.core :refer [debug dispatch after enrich]] [status-im.utils.handlers :refer [register-handler]] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.chat.handlers :refer [delete-messages!]] [status-im.protocol.api :as api] [status-im.utils.random :as random] @@ -20,8 +20,9 @@ [db-name property-name] (fn [{:keys [current-chat-id] :as db} _] (let [property (db-name db)] - (r/write (fn [] - (-> (r/get-by-field :chats :chat-id current-chat-id) + (r/write :account + (fn [] + (-> (r/get-by-field :account :chats :chat-id current-chat-id) (r/single) (aset (name property-name) property))))))) @@ -76,9 +77,9 @@ (defn remove-members-from-realm! [{:keys [current-chat-id selected-participants] :as db} _] (let [chat (get-in db [:chats current-chat-id])] - (r/write + (r/write :account (fn [] - (r/create + (r/create :account :chats (update chat :contacts remove-identities selected-participants) true))))) diff --git a/src/status_im/handlers.cljs b/src/status_im/handlers.cljs index 0a6f9b2dda..fb60e6e368 100644 --- a/src/status_im/handlers.cljs +++ b/src/status_im/handlers.cljs @@ -1,6 +1,6 @@ (ns status-im.handlers (:require - [re-frame.core :refer [after dispatch debug]] + [re-frame.core :refer [after dispatch dispatch-sync debug]] [schema.core :as s :include-macros true] [status-im.db :refer [app-db schema]] [status-im.persistence.simple-kv-store :as kv] @@ -56,12 +56,34 @@ (assoc-in db [:animations k] v))) (register-handler :initialize-db + (fn [_ _] + (assoc app-db + :user-identity nil))) + +(register-handler :initialize-account-db (fn [_ _] (assoc app-db :signed-up (storage/get kv/kv-store :signed-up) :user-identity (protocol/stored-identity nil) :password (storage/get kv/kv-store :password)))) +(register-handler :initialize-account + (u/side-effect! + (fn [_ [_ account]] + (dispatch [:initialize-protocol account]) + (dispatch [:initialize-chats]) + (dispatch [:load-contacts]) + ; TODO: initialize protocol here + (dispatch [:init-chat])))) + +(register-handler :reset-app + (u/side-effect! + (fn [_ _] + (dispatch [:initialize-db]) + (dispatch [:load-accounts]) + (dispatch [:init-console-chat]) + (dispatch [:load-commands! "console"])))) + (register-handler :initialize-crypt (u/side-effect! (fn [_ _] diff --git a/src/status_im/models/accounts.cljs b/src/status_im/models/accounts.cljs index a9f333c3c7..834db43e94 100644 --- a/src/status_im/models/accounts.cljs +++ b/src/status_im/models/accounts.cljs @@ -1,22 +1,22 @@ (ns status-im.models.accounts - (:require [status-im.persistence.realm :as r])) + (:require [status-im.persistence.realm.core :as r])) (defn get-accounts [] - (-> (r/get-all :accounts) + (-> (r/get-all :base :accounts) r/collection->map)) (defn create-account [{:keys [address public-key] :as account}] (->> account - (r/create :accounts))) + (r/create :base :accounts))) (defn save-accounts [accounts] - (r/write #(mapv create-account accounts))) + (r/write :base #(mapv create-account accounts))) ;;;;;;;;;;;;;;;;;;;;---------------------------------------------- (defn accounts-list [] - (r/get-all :accounts)) + (r/get-all :base :accounts)) (defn account-by-address [address] - (r/single-cljs (r/get-by-field :accounts :address address))) + (r/single-cljs (r/get-by-field :base :accounts :address address))) diff --git a/src/status_im/models/chats.cljs b/src/status_im/models/chats.cljs index 33e003a10d..9e86014fe4 100644 --- a/src/status_im/models/chats.cljs +++ b/src/status_im/models/chats.cljs @@ -1,7 +1,7 @@ (ns status-im.models.chats (:require [clojure.set :refer [difference]] [re-frame.core :refer [dispatch]] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.utils.random :as random :refer [timestamp]] [clojure.string :refer [join blank?]] [status-im.utils.logging :as log] @@ -12,7 +12,7 @@ (defn chat-name-from-contacts [identities] (let [chat-name (->> identities (map (fn [identity] - (-> (r/get-by-field :contacts :whisper-identity identity) + (-> (r/get-by-field :account :contacts :whisper-identity identity) (r/single-cljs) :name))) (filter identity) @@ -25,7 +25,7 @@ chat-id)) (defn chat-exists? [chat-id] - (r/exists? :chats :chat-id chat-id)) + (r/exists? :account :chats :chat-id chat-id)) (defn add-status-message [chat-id] ;; TODO Get real status @@ -42,32 +42,35 @@ (defn create-chat ([{:keys [last-msg-id] :as chat}] (let [chat (assoc chat :last-msg-id (or last-msg-id ""))] - (r/write #(r/create :chats chat)))) + (log/debug "Creating chat" chat) + (r/write :account #(r/create :account :chats chat)))) ([db chat-id identities group-chat? chat-name] + (log/debug "Creating chat" chat-id) (when-not (chat-exists? chat-id) (let [chat-name (or chat-name (get-chat-name chat-id identities)) _ (log/debug "creating chat" chat-name)] - (r/write + (r/write :account (fn [] (let [contacts (mapv (fn [ident] {:identity ident}) identities)] - (r/create :chats {:chat-id chat-id - :is-active true - :name chat-name - :group-chat group-chat? - :timestamp (timestamp) - :contacts contacts - :last-msg-id ""})))) + (r/create :account :chats + {:chat-id chat-id + :is-active true + :name chat-name + :group-chat group-chat? + :timestamp (timestamp) + :contacts contacts + :last-msg-id ""})))) (add-status-message chat-id))))) (defn chat-contacts [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single) (aget "contacts"))) (defn re-join-group-chat [db group-id identities group-name] - (r/write + (r/write :account (fn [] (let [new-identities (set identities) only-old-contacts (->> (chat-contacts group-id) @@ -78,10 +81,11 @@ (mapv (fn [ident] {:identity ident})) (concat only-old-contacts))] - (r/create :chats {:chat-id group-id - :is-active true - :name group-name - :contacts contacts} true)))) + (r/create :account :chats + {:chat-id group-id + :is-active true + :name group-name + :contacts contacts} true)))) db) (defn normalize-contacts @@ -89,23 +93,23 @@ (map #(update % :contacts vals) chats)) (defn chats-list [] - (-> (r/get-all :chats) + (-> (r/get-all :account :chats) (r/sorted :timestamp :desc) r/collection->map normalize-contacts)) (defn chat-by-id [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single-cljs) (r/list-to-array :contacts))) (defn chat-by-id2 [chat-id] - (-> (r/get-by-field :chats :chat-id chat-id) + (-> (r/get-by-field :account :chats :chat-id chat-id) r/collection->map first)) (defn chat-add-participants [chat-id identities] - (r/write + (r/write :account (fn [] (let [contacts (chat-contacts chat-id)] (doseq [contact-identity identities] @@ -118,23 +122,24 @@ ;; TODO deprecated? (is there need to remove multiple member at once?) (defn chat-remove-participants [chat-id identities] - (r/write + (r/write :account (fn [] (let [query (include-query :identity identities) - chat (r/single (r/get-by-field :chats :chat-id chat-id))] + chat (r/single (r/get-by-field :account :chats :chat-id chat-id))] (-> (aget chat "contacts") (r/filtered query) (.forEach (fn [object _ _] (aset object "is-in-chat" false)))))))) (defn active-group-chats [] - (let [results (r/filtered (r/get-all :chats) + (let [results (r/filtered (r/get-all :account :chats) "group-chat = true && is-active = true")] (js->clj (.map results (fn [object _ _] (aget object "chat-id")))))) (defn set-chat-active [chat-id active?] - (r/write (fn [] - (-> (r/get-by-field :chats :chat-id chat-id) + (r/write :account + (fn [] + (-> (r/get-by-field :account :chats :chat-id chat-id) (r/single) (aset "is-active" active?))))) diff --git a/src/status_im/models/contacts.cljs b/src/status_im/models/contacts.cljs index 6c3ea62a7a..d10904e789 100644 --- a/src/status_im/models/contacts.cljs +++ b/src/status_im/models/contacts.cljs @@ -1,11 +1,11 @@ (ns status-im.models.contacts - (:require [status-im.persistence.realm :as r] + (:require [status-im.persistence.realm.core :as r] [status-im.utils.identicon :refer [identicon]] [status-im.persistence.realm-queries :refer [include-query exclude-query]])) (defn get-contacts [] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/sorted :name :asc) r/collection->map)) @@ -13,22 +13,22 @@ (->> {:name (or name "") :photo-path (or photo-path (identicon whisper-identity))} (merge contact) - (r/create :contacts))) + (r/create :account :contacts))) (defn save-contacts [contacts] - (r/write #(mapv create-contact contacts))) + (r/write :account #(mapv create-contact contacts))) ;;;;;;;;;;;;;;;;;;;;---------------------------------------------- (defn contacts-list [] - (r/sorted (r/get-all :contacts) :name :asc)) + (r/sorted (r/get-all :account :contacts) :name :asc)) (defn contacts-list-exclude [exclude-idents] (if (empty? exclude-idents) (contacts-list) (let [query (exclude-query :whisper-identity exclude-idents)] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/filtered query) (r/sorted :name :asc))))) @@ -36,9 +36,9 @@ (if (empty? include-indents) () (let [query (include-query :whisper-identity include-indents)] - (-> (r/get-all :contacts) + (-> (r/get-all :account :contacts) (r/filtered query) (r/sorted :name :asc))))) (defn contact-by-identity [identity] - (r/single-cljs (r/get-by-field :contacts :whisper-identity identity))) + (r/single-cljs (r/get-by-field :account :contacts :whisper-identity identity))) diff --git a/src/status_im/models/messages.cljs b/src/status_im/models/messages.cljs index 38d7342ae3..122ba94c64 100644 --- a/src/status_im/models/messages.cljs +++ b/src/status_im/models/messages.cljs @@ -1,5 +1,5 @@ (ns status-im.models.messages - (:require [status-im.persistence.realm :as r] + (:require [status-im.persistence.realm.core :as r] [re-frame.core :refer [dispatch]] [cljs.reader :refer [read-string]] [status-im.utils.random :refer [timestamp]] @@ -28,8 +28,8 @@ ;; todo remove chat-id parameter [chat-id {:keys [msg-id content] :as message}] - (when-not (r/exists? :msgs :msg-id msg-id) - (r/write + (when-not (r/exists? :account :msgs :msg-id msg-id) + (r/write :account (fn [] (let [content' (if (string? content) content @@ -40,7 +40,7 @@ :content content' :timestamp (timestamp) :delivery-status nil})] - (r/create :msgs message' true)))))) + (r/create :account :msgs message' true)))))) (defn command-type? [type] (contains? @@ -50,7 +50,7 @@ (defn get-messages ([chat-id] (get-messages chat-id 0)) ([chat-id from] - (->> (-> (r/get-by-field :msgs :chat-id chat-id) + (->> (-> (r/get-by-field :account :msgs :chat-id chat-id) (r/sorted :timestamp :desc) (r/page from (+ from c/default-number-of-messages)) (r/collection->map)) @@ -63,7 +63,7 @@ (defn update-message! [{:keys [msg-id] :as msg}] (log/debug "update-message!" msg) - (r/write + (r/write :account (fn [] - (when (r/exists? :msgs :msg-id msg-id) - (r/create :msgs msg true))))) + (when (r/exists? :account :msgs :msg-id msg-id) + (r/create :account :msgs msg true))))) diff --git a/src/status_im/models/requests.cljs b/src/status_im/models/requests.cljs new file mode 100644 index 0000000000..c29f3ee8a1 --- /dev/null +++ b/src/status_im/models/requests.cljs @@ -0,0 +1,21 @@ +(ns status-im.models.requests + (:require [status-im.persistence.realm.core :as r])) + +(defn get-requests [] + (-> (r/get-all :account :requests) + r/collection->map)) + +(defn create-request [request] + (r/create :account :requests request true)) + +(defn save-request [request}] + (r/write :account + (fn [] + (create-request request)))) + +(defn save-requests [requests] + (r/write :account #(mapv create-request requests))) + +(defn requests-list [] + (r/get-all :account :requests)) + diff --git a/src/status_im/persistence/realm.cljs b/src/status_im/persistence/realm.cljs deleted file mode 100644 index 08e7ae84f4..0000000000 --- a/src/status_im/persistence/realm.cljs +++ /dev/null @@ -1,200 +0,0 @@ -(ns status-im.persistence.realm - (:require [cljs.reader :refer [read-string]] - [status-im.components.styles :refer [default-chat-color]] - [status-im.utils.types :refer [to-string]] - [status-im.utils.utils :as u] - [clojure.string :as str]) - (:refer-clojure :exclude [exists?])) - -(def opts {:schema [{:name :contacts - :primaryKey :whisper-identity - :properties {:phone-number {:type "string" - :optional true} - :whisper-identity "string" - :name {:type "string" - :optional true} - :photo-path {:type "string" - :optinal true}}} - {:name :accounts - :primaryKey :address - :properties {:address "string" - :public-key "string" - :name "string" - :photo-path "string"}} - {:name :requests - :properties {:message-id :string - :chat-id :string - :type :string - :status {:type :string - :default "open"} - :added :date}} - {:name :kv-store - :primaryKey :key - :properties {:key "string" - :value "string"}} - {:name :msgs - :primaryKey :msg-id - :properties {:msg-id "string" - :from "string" - :to {:type "string" - :optional true} - :content "string" ;; TODO make it ArrayBuffer - :content-type "string" - :timestamp "int" - :chat-id {:type "string" - :indexed true} - :outgoing "bool" - :delivery-status {:type "string" - :optional true} - :same-author "bool" - :same-direction "bool" - :preview {:type :string - :optional true}}} - {:name :chat-contact - :properties {:identity "string" - :is-in-chat {:type "bool" - :default true}}} - {:name :chats - :primaryKey :chat-id - :properties {:chat-id "string" - :name "string" - :color {:type "string" - :default default-chat-color} - :group-chat {:type "bool" - :indexed true} - :is-active "bool" - :timestamp "int" - :contacts {:type "list" - :objectType "chat-contact"} - :dapp-url {:type :string - :optional true} - :dapp-hash {:type :int - :optional true} - :last-msg-id "string"}} - {:name :commands - :primaryKey :chat-id - :properties {:chat-id "string" - :file "string"}} - {:name :tag - :primaryKey :name - :properties {:name "string" - :count {:type "int" - :optional true - :default 0}}} - {:name :discoveries - :primaryKey :whisper-id - :properties {:name "string" - :status "string" - :whisper-id "string" - :photo "string" - :location "string" - :tags {:type "list" - :objectType "tag"} - :last-updated "date"}}]}) - -(def realm-class (u/require "realm")) - -(def realm (when (cljs.core/exists? js/window) - (realm-class. (clj->js opts)))) - -(def schema-by-name (->> (:schema opts) - (mapv (fn [{:keys [name] :as schema}] - [name schema])) - (into {}))) - -(defn field-type [schema-name field] - (let [field-def (get-in schema-by-name [schema-name :properties field])] - (if (map? field-def) - (:type field-def) - field-def))) - -(defn write [f] - (.write realm f)) - -(defn create - ([schema-name obj] - (create schema-name obj false)) - ([schema-name obj update?] - (.create realm (to-string schema-name) (clj->js obj) update?))) - -(defn create-object - [schema-name obj] - (write (fn [] (create schema-name obj true)))) - -(defn and-q [queries] - (str/join " and " queries)) - -(defmulti to-query (fn [schema-name operator field value] - operator)) - -(defmethod to-query :eq [schema-name operator field value] - (let [value (to-string value) - query (str (name field) "=" (if (= "string" (name (field-type - schema-name field))) - (str "\"" value "\"") - value))] - query)) - -(defn get-by-filter [schema-name filter] - (-> (.objects realm (name schema-name)) - (.filtered filter))) - -(defn get-by-field [schema-name field value] - (let [q (to-query schema-name :eq field value)] - (.filtered (.objects realm (name schema-name)) q))) - -(defn get-by-fields [schema-name fields] - (let [queries (map (fn [[k v]] - (to-query schema-name :eq k v)) - fields)] - (.filtered (.objects realm (name schema-name)) (and-q queries)))) - -(defn get-all [schema-name] - (.objects realm (to-string schema-name))) - -(defn sorted [results field-name order] - (.sorted results (to-string field-name) (if (= order :asc) - false - true))) - -(defn filtered [results filter-query] - (.filtered results filter-query)) - -(defn page [results from to] - (js/Array.prototype.slice.call results from to)) - -(defn single [result] - (-> (aget result 0))) - -(defn single-cljs [result] - (some-> (aget result 0) - (js->clj :keywordize-keys true))) - -(defn cljs-list [results] - (-> (js->clj results :keywordize-keys true) - (vals))) - -(defn list-to-array [record list-field] - (update-in record [list-field] (comp vec vals))) - -(defn decode-value [{:keys [key value]}] - (read-string value)) - -(defn delete [obj] - (.delete realm obj)) - -(defn exists? [schema-name field value] - (pos? (.-length (get-by-field schema-name field value)))) - -(defn get-count [objs] - (.-length objs)) - -(defn get-list [schema-name] - (vals (js->clj (.objects realm (to-string schema-name)) :keywordize-keys true))) - -(defn collection->map [collection] - (-> (.map collection (fn [object _ _] object)) - (js->clj :keywordize-keys true))) - -(defn get-one-by-field [schema-name field value] - (single-cljs (get-by-field schema-name field value))) diff --git a/src/status_im/persistence/realm/core.cljs b/src/status_im/persistence/realm/core.cljs new file mode 100644 index 0000000000..e7a85996d9 --- /dev/null +++ b/src/status_im/persistence/realm/core.cljs @@ -0,0 +1,151 @@ +(ns status-im.persistence.realm.core + (:require [cljs.reader :refer [read-string]] + [status-im.components.styles :refer [default-chat-color]] + [status-im.utils.types :refer [to-string]] + [status-im.utils.utils :as u] + [status-im.utils.logging :as log] + [status-im.persistence.realm.schemas :refer [base account]] + [clojure.string :as str]) + (:refer-clojure :exclude [exists?])) + + +(def realm-class (u/require "realm")) + +(def base-realm + (when (cljs.core/exists? js/window) + (realm-class. (clj->js base)))) + +(def account-realm (atom nil)) + +(defn create-account-realm [address] + (let [opts (merge account {:path (str address ".realm")})] + (when (cljs.core/exists? js/window) + (realm-class. (clj->js opts))))) + +(defn realm [schema] + (log/debug "Schema: " schema) + (case schema + :base base-realm + :account @account-realm)) + +(defn close [schema] + (let [realm-db (realm schema)] + (when realm-db + (.close realm-db)))) + +(defn close-account-realm [] + (close :account) + (reset! account-realm nil)) + +(defn get-schema-by-name [opts] + (->> (:schema opts) + (mapv (fn [{:keys [name] :as schema}] + [name schema])) + (into {}))) + +(def schema-by-name + {:base (get-schema-by-name base) + :account (get-schema-by-name account)}) + +(defn field-type [schema schema-name field] + (let [schema-by-name (get schema-by-name schema) + field-def (get-in schema-by-name [schema-name :properties field])] + (if (map? field-def) + (:type field-def) + field-def))) + +(defn write [schema f] + (.write (realm schema) f)) + +(defn create + ([schema schema-name obj] + (create schema schema-name obj false)) + ([schema schema-name obj update?] + (.create (realm schema) (to-string schema-name) (clj->js obj) update?))) + +(defn create-object + [schema schema-name obj] + (write schema (fn [] (create schema schema-name obj true)))) + +(defn and-q [queries] + (str/join " and " queries)) + +(defmulti to-query (fn [schema schema-name operator field value] + operator)) + +(defmethod to-query :eq [schema schema-name operator field value] + (let [value (to-string value) + field-type (field-type schema schema-name field) + query (str (name field) "=" (if (= "string" (name field-type)) + (str "\"" value "\"") + value))] + query)) + +(defn get-by-filter [schema schema-name filter] + (log/debug "Get by filter: " schema schema-name field) + (-> (.objects (realm schema) (name schema-name)) + (.filtered filter))) + +(defn get-by-field [schema schema-name field value] + (log/debug "Get by field: " schema schema-name field value) + (let [q (to-query schema schema-name :eq field value)] + (.filtered (.objects (realm schema) (name schema-name)) q))) + +(defn get-by-fields [schema schema-name fields] + (log/debug "Get by fields: " schema schema-name fields) + (let [queries (map (fn [[k v]] + (to-query schema schema-name :eq k v)) + fields)] + (.filtered (.objects (realm schema) (name schema-name)) (and-q queries)))) + +(defn get-all [schema schema-name] + (log/debug "Get all: " schema schema-name) + (.objects (realm schema) (to-string schema-name))) + +(defn sorted [results field-name order] + (.sorted results (to-string field-name) (if (= order :asc) + false + true))) + +(defn filtered [results filter-query] + (.filtered results filter-query)) + +(defn page [results from to] + (js/Array.prototype.slice.call results from to)) + +(defn single [result] + (-> (aget result 0))) + +(defn single-cljs [result] + (some-> (aget result 0) + (js->clj :keywordize-keys true))) + +(defn cljs-list [results] + (-> (js->clj results :keywordize-keys true) + (vals))) + +(defn list-to-array [record list-field] + (update-in record [list-field] (comp vec vals))) + +(defn decode-value [{:keys [key value]}] + (read-string value)) + +(defn delete [schema obj] + (.delete (realm schema) obj)) + +(defn exists? [schema schema-name field value] + (pos? (.-length (get-by-field schema schema-name field value)))) + +(defn get-count [objs] + (.-length objs)) + +(defn get-list [schema schema-name] + (log/debug "Get list: " schema schema-name) + (vals (js->clj (.objects (realm schema) (to-string schema-name)) :keywordize-keys true))) + +(defn collection->map [collection] + (-> (.map collection (fn [object _ _] object)) + (js->clj :keywordize-keys true))) + +(defn get-one-by-field [schema schema-name field value] + (single-cljs (get-by-field schema schema-name field value))) \ No newline at end of file diff --git a/src/status_im/persistence/realm/schemas.cljs b/src/status_im/persistence/realm/schemas.cljs new file mode 100644 index 0000000000..4625b8b2c8 --- /dev/null +++ b/src/status_im/persistence/realm/schemas.cljs @@ -0,0 +1,100 @@ +(ns status-im.persistence.realm.schemas + (:require [status-im.components.styles :refer [default-chat-color]])) + +(def base {:schema [{:name :accounts + :primaryKey :address + :properties {:address "string" + :public-key "string" + :name "string" + :photo-path "string"}} + {:name :tag + :primaryKey :name + :properties {:name "string" + :count {:type "int" + :optional true + :default 0}}} + {:name :discoveries + :primaryKey :whisper-id + :properties {:name "string" + :status "string" + :whisper-id "string" + :photo "string" + :location "string" + :tags {:type "list" + :objectType "tag"} + :last-updated "date"}} + {:name :kv-store + :primaryKey :key + :properties {:key "string" + :value "string"}} + {:name :commands + :primaryKey :chat-id + :properties {:chat-id "string" + :file "string"}}] + :schemaVersion 0}) + +(def account {:schema [{:name :contacts + :primaryKey :whisper-identity + :properties {:phone-number {:type "string" + :optional true} + :whisper-identity "string" + :name {:type "string" + :optional true} + :photo-path {:type "string" + :optinal true}}} + {:name :requests + :properties {:message-id :string + :chat-id :string + :type :string + :status {:type :string + :default "open"} + :added :date}} + {:name :kv-store + :primaryKey :key + :properties {:key "string" + :value "string"}} + {:name :msgs + :primaryKey :msg-id + :properties {:msg-id "string" + :from "string" + :to {:type "string" + :optional true} + :content "string" ;; TODO make it ArrayBuffer + :content-type "string" + :timestamp "int" + :chat-id {:type "string" + :indexed true} + :outgoing "bool" + :delivery-status {:type "string" + :optional true} + :same-author "bool" + :same-direction "bool" + :preview {:type :string + :optional true}}} + {:name :chat-contact + :properties {:identity "string" + :is-in-chat {:type "bool" + :default true}}} + {:name :chats + :primaryKey :chat-id + :properties {:chat-id "string" + :name "string" + :color {:type "string" + :default default-chat-color} + :group-chat {:type "bool" + :indexed true} + :is-active "bool" + :timestamp "int" + :contacts {:type "list" + :objectType "chat-contact"} + :dapp-url {:type :string + :optional true} + :dapp-hash {:type :int + :optional true} + :last-msg-id "string"}} + {:name :commands + :primaryKey :chat-id + :properties {:chat-id "string" + :file "string"}}] + :schemaVersion 0}) + diff --git a/src/status_im/persistence/simple_kv_store.cljs b/src/status_im/persistence/simple_kv_store.cljs index 84dd85bff3..84151ef522 100644 --- a/src/status_im/persistence/simple_kv_store.cljs +++ b/src/status_im/persistence/simple_kv_store.cljs @@ -1,25 +1,29 @@ (ns status-im.persistence.simple-kv-store (:require [status-im.protocol.state.storage :as st] - [status-im.persistence.realm :as r] + [status-im.persistence.realm.core :as r] [status-im.utils.types :refer [to-edn-string]])) -(defrecord SimpleKvStore [] +(defrecord SimpleKvStore [schema] st/Storage (put [_ key value] - (r/write + (r/write schema (fn [] - (r/create :kv-store {:key key - :value (to-edn-string value)} true)))) + (r/create schema :kv-store + {:key key + :value (to-edn-string value)} true)))) (get [_ key] - (some-> (r/get-by-field :kv-store :key key) + (some-> (r/get-by-field schema :kv-store :key key) (r/single-cljs) (r/decode-value))) (contains-key? [_ key] - (r/exists? :kv-store :key key)) + (r/exists? schema :kv-store :key key)) (delete [_ key] - (r/write (fn [] - (-> (r/get-by-field :kv-store :key key) - (r/single) - (r/delete)))))) + (r/write schema + (fn [] + (->> (r/get-by-field schema :kv-store :key key) + (r/single) + (r/delete schema)))))) -(def kv-store (->SimpleKvStore)) +(def kv-store (->SimpleKvStore :account)) + +(def base-kv-store (->SimpleKvStore :base))