From af6c784ab4b5f0c92c3a3e1ccc32e9dd82ffa645 Mon Sep 17 00:00:00 2001 From: Igor Mandrigin Date: Wed, 29 May 2019 15:05:56 +0200 Subject: [PATCH] Prepare to use status-go based protocol: 1-1 and public chat management APIs. Connect to stubs of status-go protocol API, behind the flag. Since status-go isn't updated yet, setting this flag will break the app. What needs to be tested is no regressions in a normal mode. Signed-off-by: Igor Mandrigin --- .env | 1 + src/status_im/chat/models.cljs | 106 +++++++++++++--------- src/status_im/chat/models/loading.cljs | 56 ++++++++++-- src/status_im/ethereum/json_rpc.cljs | 13 ++- src/status_im/signals/core.cljs | 2 + src/status_im/utils/config.cljs | 2 + src/status_im/utils/fx.cljs | 2 +- test/cljs/status_im/test/chat/models.cljs | 23 ----- 8 files changed, 127 insertions(+), 78 deletions(-) diff --git a/.env b/.env index cc98c56ee8..cfa3bf45f2 100644 --- a/.env +++ b/.env @@ -21,3 +21,4 @@ STICKERS_ENABLED=1 PARTITIONED_TOPIC=0 CONTRACT_NODES=1 MOBILE_UI_FOR_DESKTOP=0 +STATUS_GO_PROTOCOL=0 diff --git a/src/status_im/chat/models.cljs b/src/status_im/chat/models.cljs index ff4fc1c3bd..5b7e50e8ed 100644 --- a/src/status_im/chat/models.cljs +++ b/src/status_im/chat/models.cljs @@ -5,6 +5,7 @@ [status-im.data-store.messages :as messages-store] [status-im.data-store.user-statuses :as user-statuses-store] [status-im.contact-code.core :as contact-code] + [taoensso.timbre :as log] [status-im.i18n :as i18n] [status-im.transport.chat.core :as transport.chat] [status-im.transport.utils :as transport.utils] @@ -20,6 +21,7 @@ [status-im.utils.platform :as platform] [status-im.utils.priority-map :refer [empty-message-map]] [status-im.utils.utils :as utils] + [status-im.utils.config :as config] [status-im.mailserver.core :as mailserver] [status-im.transport.partitioned-topic :as transport.topic])) @@ -101,34 +103,30 @@ (or (get (:chats db) chat-id) (create-new-chat chat-id cofx)) chat-props)] - {:db (update-in db [:chats chat-id] merge chat) :data-store/tx [(chats-store/save-chat-tx chat)]})) (fx/defn add-public-chat "Adds new public group chat to db & realm" [cofx topic] - (upsert-chat cofx - {:chat-id topic - :is-active true - :name topic - :group-chat true - :contacts #{} - :public? true - :might-have-join-time-messages? true - :unviewed-messages-count 0 - :loaded-unviewed-messages-ids #{}})) - -(fx/defn add-group-chat - "Adds new private group chat to db & realm" - [cofx chat-id chat-name admin participants] - (upsert-chat cofx - {:chat-id chat-id - :name chat-name - :is-active true - :group-chat true - :group-admin admin - :contacts participants})) + (if config/use-status-go-protocol? + {:json-rpc/call [{:method "status_joinPublicChat" + :params [topic] + :on-success + #(log/debug "successfully joined a public chat:" topic) + :on-error + (fn [error] + (log/error "can't join a public chat:" error))}]} + (upsert-chat cofx + {:chat-id topic + :is-active true + :name topic + :group-chat true + :contacts #{} + :public? true + :might-have-join-time-messages? true + :unviewed-messages-count 0 + :loaded-unviewed-messages-ids #{}}))) (fx/defn clear-history "Clears history of the particular chat" @@ -159,27 +157,37 @@ (assoc-in [:current-chat-id] nil)) :data-store/tx [(chats-store/deactivate-chat-tx chat-id now)]}) -;; TODO: There's a race condition here, as the removal of the filter (async) -;; is done at the same time as the removal of the chat, so a message -;; might come between and restore the chat. Multiple way to handle this -;; (remove chat only after the filter has been removed, probably the safest, -;; flag the chat to ignore new messages, change receive method for public/group chats) -;; For now to keep the code simplier and avoid significant changes, best to leave as it is. (fx/defn remove-chat "Removes chat completely from app, producing all necessary effects for that" [{:keys [db now] :as cofx} chat-id] - (fx/merge cofx - #(when (public-chat? % chat-id) - (transport.chat/unsubscribe-from-chat % chat-id)) - #(when (group-chat? % chat-id) - (mailserver/remove-chat-from-mailserver-topic % chat-id)) - (mailserver/remove-gaps chat-id) - (mailserver/remove-range chat-id) - (deactivate-chat chat-id) - (clear-history chat-id) - #(when (one-to-one-chat? % chat-id) - (contact-code/stop-listening % chat-id)) - (navigation/navigate-to-cofx :home {}))) + (if config/use-status-go-protocol? + (fx/merge cofx + {:json-rpc/call [{:method "status_removeChat" + :params [chat-id] + :on-success + #(log/debug "successfully removed a chat:" chat-id) + :on-error + (fn [error] + (log/error "can't remove a chat:" error))}]} + (navigation/navigate-to-cofx :home {})) + (fx/merge cofx + ;; TODO: There's a race condition here, as the removal of the filter (async) + ;; is done at the same time as the removal of the chat, so a message + ;; might come between and restore the chat. Multiple way to handle this + ;; (remove chat only after the filter has been removed, probably the safest, + ;; flag the chat to ignore new messages, change receive method for public/group chats) + ;; For now to keep the code simplier and avoid significant changes, best to leave as it is. + #(when (public-chat? % chat-id) + (transport.chat/unsubscribe-from-chat % chat-id)) + #(when (group-chat? % chat-id) + (mailserver/remove-chat-from-mailserver-topic % chat-id)) + (mailserver/remove-gaps chat-id) + (mailserver/remove-range chat-id) + (deactivate-chat chat-id) + (clear-history chat-id) + #(when (one-to-one-chat? % chat-id) + (contact-code/stop-listening % chat-id)) + (navigation/navigate-to-cofx :home {})))) (fx/defn send-messages-seen [{:keys [db] :as cofx} chat-id message-ids] @@ -287,10 +295,20 @@ [{:keys [db] :as cofx} chat-id opts] ;; don't allow to open chat with yourself (when (not= (accounts.db/current-public-key cofx) chat-id) - (fx/merge cofx - (upsert-chat {:chat-id chat-id - :is-active true}) - (navigate-to-chat chat-id opts)))) + (if config/use-status-go-protocol? + (fx/merge cofx + {:json-rpc/call [{:method "status_startOneOnOneChat" + :params [chat-id] + :on-success + #(log/debug "successfully started a 1-1 chat with:" chat-id) + :on-error + (fn [error] + (log/error "can't start a 1-1 chat:" error))}]} + (navigate-to-chat chat-id opts)) + (fx/merge cofx + (upsert-chat {:chat-id chat-id + :is-active true}) + (navigate-to-chat chat-id opts))))) (fx/defn start-public-chat "Starts a new public chat" diff --git a/src/status_im/chat/models/loading.cljs b/src/status_im/chat/models/loading.cljs index a32b0a7810..8021026618 100644 --- a/src/status_im/chat/models/loading.cljs +++ b/src/status_im/chat/models/loading.cljs @@ -1,11 +1,14 @@ (ns status-im.chat.models.loading - (:require [status-im.accounts.db :as accounts.db] + (:require [re-frame.core :as re-frame] + [status-im.accounts.db :as accounts.db] [status-im.chat.commands.core :as commands] [status-im.chat.models :as chat-model] + [status-im.mailserver.core :as mailserver] + [status-im.utils.config :as config] [status-im.utils.datetime :as time] [status-im.utils.fx :as fx] [status-im.utils.priority-map :refer [empty-message-map]] - [status-im.mailserver.core :as mailserver])) + [taoensso.timbre :as log])) (def index-messages (partial into empty-message-map (map (juxt :message-id identity)))) @@ -60,10 +63,37 @@ message-id))) statuses)) -(fx/defn initialize-chats - "Initialize persisted chats on startup" +(fx/defn update-chats-in-app-db + {:events [:chats-list/load-success]} + [{:keys [db] :as cofx} chats] + (fx/merge cofx + {:db (assoc db :chats chats)} + (commands/load-commands commands/register))) + +(defn- unkeywordize-chat-names + [chats] + (reduce-kv + (fn [acc chat-keyword chat] + (assoc acc (name chat-keyword) chat)) + {} + chats)) + +(defn load-chats-from-rpc + [cofx] + (fx/merge cofx + {:json-rpc/call [{:method "status_chats" + :params [] + :on-error + #(log/error "can't retrieve chats list from status-go:" %) + :on-success + #(re-frame/dispatch + [:chats-list/load-success + (unkeywordize-chat-names (:chats %))])}]})) + +(defn initialize-chats-legacy + "Use realm + clojure to manage chats" [{:keys [db get-all-stored-chats] :as cofx} - {:keys [from to] :or {from 0 to nil}}] + from to] (let [old-chats (:chats db) chats (reduce (fn [acc {:keys [chat-id] :as chat}] (assoc acc chat-id @@ -74,9 +104,15 @@ {} (get-all-stored-chats from to)) chats (merge old-chats chats)] - (fx/merge cofx - {:db (assoc db :chats chats)} - (commands/load-commands commands/register)))) + (update-chats-in-app-db cofx chats))) + +(fx/defn initialize-chats + "Initialize persisted chats on startup" + [cofx + {:keys [from to] :or {from 0 to nil}}] + (if config/use-status-go-protocol? + (load-chats-from-rpc cofx) + (initialize-chats-legacy cofx from to))) (defn load-more-messages "Loads more messages for current chat" @@ -84,7 +120,9 @@ get-stored-messages :get-stored-messages get-stored-user-statuses :get-stored-user-statuses get-referenced-messages :get-referenced-messages :as cofx}] - (when-not (get-in db [:chats current-chat-id :all-loaded?]) + ;; TODO: re-implement functionality for status-go protocol + (when-not (or config/use-status-go-protocol? + (get-in db [:chats current-chat-id :all-loaded?])) (let [previous-pagination-info (get-in db [:chats current-chat-id :pagination-info]) {:keys [messages pagination-info diff --git a/src/status_im/ethereum/json_rpc.cljs b/src/status_im/ethereum/json_rpc.cljs index ebd10ee2ef..e24b1b9eb0 100644 --- a/src/status_im/ethereum/json_rpc.cljs +++ b/src/status_im/ethereum/json_rpc.cljs @@ -22,7 +22,11 @@ "eth_getTransactionByHash" {} "eth_getTransactionReceipt" {} "eth_newBlockFilter" {:subscription? true} - "eth_newFilter" {:subscription? true}}) + "eth_newFilter" {:subscription? true} + "status_joinPublicChat" {} + "status_chats" {} + "status_startOneOnOneChat" {} + "status_removeChat" {}}) (defn call [{:keys [method params on-success on-error]}] @@ -72,3 +76,10 @@ on-success) :on-error on-error})) + +;; effects +(re-frame/reg-fx + :json-rpc/call + (fn [params] + (doseq [param params] + (call param)))) diff --git a/src/status_im/signals/core.cljs b/src/status_im/signals/core.cljs index 548365872e..b5d2acc95e 100644 --- a/src/status_im/signals/core.cljs +++ b/src/status_im/signals/core.cljs @@ -1,6 +1,7 @@ (ns status-im.signals.core (:require [status-im.accounts.db :as accounts.db] [status-im.accounts.login.core :as accounts.login] + [status-im.chat.models.loading :as chat.loading] [status-im.contact-recovery.core :as contact-recovery] [status-im.ethereum.subscriptions :as ethereum.subscriptions] [status-im.hardwallet.core :as hardwallet] @@ -75,4 +76,5 @@ "discovery.summary" (summary cofx event) "subscriptions.data" (ethereum.subscriptions/handle-signal cofx event) "subscriptions.error" (ethereum.subscriptions/handle-error cofx event) + "status.chats.did-change" (chat.loading/load-chats-from-rpc cofx) (log/debug "Event " type " not handled")))) diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 4743645b09..77b981c0b8 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -39,6 +39,8 @@ (def contract-nodes-enabled? (enabled? (get-config :CONTRACT_NODES "0"))) (def mobile-ui-for-desktop? (enabled? (get-config :MOBILE_UI_FOR_DESKTOP "0"))) +(def use-status-go-protocol? (enabled? (get-config :STATUS_GO_PROTOCOL "0"))) + ;; CONFIG VALUES (def log-level (-> (get-config :LOG_LEVEL "error") diff --git a/src/status_im/utils/fx.cljs b/src/status_im/utils/fx.cljs index 13cb7535d7..1f7e5494ef 100644 --- a/src/status_im/utils/fx.cljs +++ b/src/status_im/utils/fx.cljs @@ -14,7 +14,7 @@ :shh/add-new-sym-keys :shh/get-new-sym-keys :shh/post :shh/send-direct-message :shh/remove-filter :shh/generate-sym-key-from-password :transport/confirm-messages-processed - :group-chats/extract-membership-signature :utils/dispatch-later}) + :group-chats/extract-membership-signature :utils/dispatch-later :json-rpc/call}) (defn- safe-merge [fx new-fx] (if (:merging-fx-with-common-keys fx) diff --git a/test/cljs/status_im/test/chat/models.cljs b/test/cljs/status_im/test/chat/models.cljs index 2f3314183d..4a7fe574e0 100644 --- a/test/cljs/status_im/test/chat/models.cljs +++ b/test/cljs/status_im/test/chat/models.cljs @@ -48,29 +48,6 @@ (testing "it adds the fx to store a chat" (is store-chat-fx))))) -(deftest add-group-chat - (let [chat-id "chat-id" - chat-name "chat-name" - admin "admin" - participants ["a"] - fx (chat/add-group-chat {:db {}} chat-id chat-name admin participants) - store-fx (:data-store/tx fx) - group-chat (get-in fx [:db :chats chat-id])] - (testing "it saves the chat in the database" - (is store-fx)) - (testing "it sets the name" - (is (= chat-name (:name group-chat)))) - (testing "it sets the admin" - (is (= admin (:group-admin group-chat)))) - (testing "it sets the participants" - (is (= participants (:contacts group-chat)))) - (testing "it sets the chat-id" - (is (= chat-id (:chat-id group-chat)))) - (testing "it sets the group-chat flag" - (is (:group-chat group-chat))) - (testing "it does not sets the public flag" - (is (not (:public? group-chat)))))) - (deftest add-public-chat (let [topic "topic" fx (chat/add-public-chat {:db {}} topic)