From 50072ffe3fd283abdfdf5585c6b2f73e61a462fb Mon Sep 17 00:00:00 2001 From: Eric Dvorsak Date: Fri, 18 May 2018 02:30:33 +0200 Subject: [PATCH] [fix 4177] handle discovery signals Signed-off-by: Julien Eluard --- deps.edn | 3 +- project.clj | 3 +- src/status_im/network/events.cljs | 13 +- src/status_im/translations/en.cljs | 2 + src/status_im/transport/core.cljs | 2 +- src/status_im/transport/handlers.cljs | 2 +- src/status_im/transport/inbox.cljs | 282 +++++++++--------- .../transport/message/v1/public_chat.cljs | 5 +- .../ui/components/connectivity/view.cljs | 55 ++-- src/status_im/ui/screens/db.cljs | 11 +- src/status_im/ui/screens/events.cljs | 39 ++- src/status_im/ui/screens/subs.cljs | 17 +- src/status_im/utils/config.cljs | 2 +- src/status_im/utils/utils.cljs | 11 +- test/cljs/status_im/test/runner.cljs | 2 + test/cljs/status_im/test/transport/inbox.cljs | 80 +++++ 16 files changed, 310 insertions(+), 219 deletions(-) create mode 100644 test/cljs/status_im/test/transport/inbox.cljs diff --git a/deps.edn b/deps.edn index d68c59a7d4..f235c18653 100644 --- a/deps.edn +++ b/deps.edn @@ -10,8 +10,7 @@ com.andrewmcveigh/cljs-time {:mvn/version "0.5.2"} com.taoensso/timbre {:mvn/version "4.10.0"} hickory {:mvn/version "0.7.1"} - com.cognitect/transit-cljs {:mvn/version "0.8.248"} - day8.re-frame/async-flow-fx {:mvn/version "0.0.10"}} + com.cognitect/transit-cljs {:mvn/version "0.8.248"}} :aliases {:repl {:extra-deps diff --git a/project.clj b/project.clj index 312ae831a9..ff0ace80ab 100644 --- a/project.clj +++ b/project.clj @@ -10,8 +10,7 @@ [com.andrewmcveigh/cljs-time "0.5.2"] [com.taoensso/timbre "4.10.0"] [hickory "0.7.1"] - [com.cognitect/transit-cljs "0.8.248"] - [day8.re-frame/async-flow-fx "0.0.10"]] + [com.cognitect/transit-cljs "0.8.248"]] :plugins [[lein-cljsbuild "1.1.7"] [lein-re-frisk "0.5.8"] [lein-cljfmt "0.5.7"] diff --git a/src/status_im/network/events.cljs b/src/status_im/network/events.cljs index 511fd41a8d..b707e9487f 100644 --- a/src/status_im/network/events.cljs +++ b/src/status_im/network/events.cljs @@ -29,14 +29,11 @@ ::update-connection-status [re-frame/trim-v] (fn [{{:keys [network-status mailserver-status] :as db} :db :as cofx} [is-connected?]] - (let [should-recover? (and (= network-status :offline) - is-connected? - (not= mailserver-status :connecting))] - (cond-> (handlers-macro/merge-fx cofx - {:db (assoc db :network-status (if is-connected? :online :offline))} - (inbox/recover-offline-inbox should-recover?)) - is-connected? - (assoc :drain-mixpanel-events nil))))) + (cond-> (handlers-macro/merge-fx cofx + {:db (assoc db :network-status (if is-connected? :online :offline))} + (inbox/request-messages {:discover? true})) + is-connected? + (assoc :drain-mixpanel-events nil)))) (handlers/register-handler-fx ::update-network-status diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index 79059a509c..0a0ef6e1a1 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -7,8 +7,10 @@ :chat-name "Chat name" :notifications-title "Notifications and sounds" :offline "Offline" + :disconnected "Connecting to peers..." :connection-problem "Messages connection problem" :mailserver-reconnect "Could not connect to mailserver. Tap to reconnect" + :fetching-messages "Fetching messages..." :search-for "Search for..." :cancel "Cancel" :next "Next" diff --git a/src/status_im/transport/core.cljs b/src/status_im/transport/core.cljs index 445f1b9851..298eb36004 100644 --- a/src/status_im/transport/core.cljs +++ b/src/status_im/transport/core.cljs @@ -34,7 +34,7 @@ :shh/restore-sym-keys {:web3 web3 :transport (:transport/chats db) :on-success sym-key-added-callback}} - (inbox/initialize-offline-inbox))))) + (inbox/peers-summary-change-fx))))) ;;TODO (yenda) remove once go implements persistence ;;Since symkeys are not persisted, we restore them via add sym-keys, diff --git a/src/status_im/transport/handlers.cljs b/src/status_im/transport/handlers.cljs index 154bda15ff..96bd713124 100644 --- a/src/status_im/transport/handlers.cljs +++ b/src/status_im/transport/handlers.cljs @@ -86,7 +86,7 @@ {:db (assoc-in db [:transport/chats chat-id :sym-key-id] sym-key-id) - :dispatch [:inbox/request-messages {:topics [topic]}] + :dispatch [:inbox/request-messages {:topics [topic] :discover? false}] :shh/add-filter {:web3 web3 :sym-key-id sym-key-id :topic topic diff --git a/src/status_im/transport/inbox.cljs b/src/status_im/transport/inbox.cljs index 5c4f566c92..89a25c0aae 100644 --- a/src/status_im/transport/inbox.cljs +++ b/src/status_im/transport/inbox.cljs @@ -11,8 +11,17 @@ [status-im.utils.ethereum.core :as ethereum] [status-im.utils.utils :as utils] [status-im.i18n :as i18n] - [day8.re-frame.async-flow-fx] - [status-im.constants :as constants])) + [status-im.constants :as constants] + [status-im.utils.handlers-macro :as handlers-macro])) + +(def connection-timeout + "Time after which mailserver connection is considered to have failed" + 60000) + +(def fetching-messages-notification-timeout + "Time after which we consider mailserver is done fetching messages and we can + stop showing notification to user" + 5000) (defn- parse-json ;; NOTE(dmitryn) Expects JSON response like: @@ -48,61 +57,14 @@ wnode-id (get-in db [:account/account :settings :wnode chain])] (get-in db [:inbox/wnodes chain wnode-id :address]))) -(defn initialize-offline-inbox-flow [] - {:first-dispatch [:inbox/get-sym-key] - :rules [{:when :seen-both? - :events [:inbox/get-sym-key-success :inbox/connection-success] - :dispatch [:inbox/request-messages {:discover? true}]}]}) - -(defn recover-offline-inbox-flow [] - {:first-dispatch [:inbox/fetch-peers] - :rules [{:when :seen? - :events :inbox/connection-success - :dispatch [:inbox/request-messages {:discover? true}]}]}) - -(defn initialize-offline-inbox - "Initialises offline inbox if inboxing enabled in config" - [{:keys [db]}] - (when config/offline-inbox-enabled? - (let [wnode (get-current-wnode-address db)] - (log/info "offline inbox: initialize " wnode) - (when wnode - {:async-flow (initialize-offline-inbox-flow) - :db (assoc db :mailserver-status :connecting) - ::add-peer {:wnode wnode}})))) - -(defn recover-offline-inbox - "Recover offline inbox connection after being offline because of connectivity loss" - [should-recover? {:keys [db]}] - (when (and config/offline-inbox-enabled? - should-recover?) - (let [wnode (get-current-wnode-address db)] - (when (and wnode - (:account/account db)) - (log/info "offline inbox: recover" wnode) - {:db (assoc db :mailserver-status :connecting) - :async-flow (recover-offline-inbox-flow)})))) - -(defn add-peer [enode success-fn error-fn] - (status/add-peer enode (response-handler error-fn success-fn))) - -(defn fetch-peers - ;; https://github.com/ethereum/go-ethereum/wiki/Management-APIs#admin_peers - ;; retrieves all the information known about the connected remote nodes - ;; TODO(dmitryn): use web3 instead of rpc call - [success-fn error-fn] - (let [args {:jsonrpc "2.0" - :id 2 - :method "admin_peers" - :params []} - payload (.stringify js/JSON (clj->js args))] - (status/call-web3-private payload (response-handler error-fn success-fn)))) - (defn registered-peer? [peers enode] (let [peer-ids (into #{} (map :id) peers) enode-id (transport.utils/extract-enode-id enode)] (contains? peer-ids enode-id))) +(defn add-peer [enode success-fn error-fn] + (status/add-peer enode (response-handler error-fn success-fn))) + (defn mark-trusted-peer [web3 enode success-fn error-fn] (.markTrustedPeer (transport.utils/shh web3) enode @@ -111,7 +73,7 @@ (success-fn resp) (error-fn err))))) -(defn request-messages [web3 wnode topics to from sym-key-id success-fn error-fn] +(defn request-inbox-messages [web3 wnode topics to from sym-key-id success-fn error-fn] (let [opts (merge {:mailServerPeer wnode :symKeyID sym-key-id} (when from {:from from}) @@ -119,7 +81,6 @@ (log/info "offline inbox: request-messages request for topics " topics) (doseq [topic topics] (let [opts (assoc opts :topic topic)] - (log/info "offline inbox: request-messages args" (pr-str opts)) (.requestMessages (transport.utils/shh web3) (clj->js opts) (fn [err resp] @@ -131,54 +92,122 @@ ::add-peer (fn [{:keys [wnode]}] (add-peer wnode - #(re-frame/dispatch [:inbox/fetch-peers]) + #(log/debug "offline inbox: add-peer success" %) #(log/error "offline inbox: add-peer error" %)))) -(re-frame/reg-fx - ::fetch-peers - (fn [retries] - (fetch-peers #(re-frame/dispatch [:inbox/check-peer-added % retries]) - #(log/error "offline inbox: fetch-peers error" %)))) - (re-frame/reg-fx ::mark-trusted-peer (fn [{:keys [wnode web3]}] (mark-trusted-peer web3 wnode - #(re-frame/dispatch [:inbox/connection-success %]) - #(log/error "offline inbox: mark-trusted-peer error" % wnode)))) + #(re-frame/dispatch [:inbox/mailserver-trusted %]) + #(re-frame/dispatch [:inbox/connection-check])))) (re-frame/reg-fx ::request-messages (fn [{:keys [wnode topics to from sym-key-id web3]}] - (request-messages web3 - wnode - topics - to - from - sym-key-id - #(log/info "offline inbox: request-messages response" %) - #(log/error "offline inbox: request-messages error" %1 %2 to from)))) + (request-inbox-messages web3 + wnode + topics + to + from + sym-key-id + #(log/info "offline inbox: request-messages response" %) + #(log/error "offline inbox: request-messages error" %1 %2 to from)))) + +(defn update-mailserver-status [transition {:keys [db]}] + (let [state transition] + {:db (assoc db :mailserver-status state)})) + +(defn generate-mailserver-symkey [{:keys [db] :as cofx}] + (when-not (:inbox/sym-key-id db) + {:shh/generate-sym-key-from-password + {:password (:inbox/password db) + :web3 (:web3 db) + :on-success (fn [_ sym-key-id] + (re-frame/dispatch [:inbox/get-sym-key-success sym-key-id])) + :on-error #(log/error "offline inbox: get-sym-key error" %)}})) + +(defn connect-to-mailserver + "Add mailserver as a peer using ::add-peer cofx and generate sym-key when + it doesn't exists + Peer summary will change and we will receive a signal from status go when + this is successful + A connection-check is made after `connection timeout` is reached and + mailserver-status is changed to error if it is not connected by then" + [{:keys [db] :as cofx}] + (let [web3 (:web3 db) + wnode (get-current-wnode-address db)] + (when config/offline-inbox-enabled? + (handlers-macro/merge-fx cofx + {::add-peer {:wnode wnode} + :utils/dispatch-later [{:ms connection-timeout + :dispatch [:inbox/connection-check]}]} + (update-mailserver-status :connecting) + (generate-mailserver-symkey))))) + +(defn peers-summary-change-fx + "Called when a peer summary signal is received or we want to try to connect + to mailserver ie. after login. + Marks the mailserver as trusted peer if it is already added to the list of + peers or connects to it if it's not the case" + [{:keys [db] :as cofx}] + (when (and (:account/account db) + config/offline-inbox-enabled?) + (let [{:keys [peers-summary peers-count]} db] + (if (zero? peers-count) + (update-mailserver-status :disconnected cofx) + (let [wnode (get-current-wnode-address db)] + (if (registered-peer? peers-summary wnode) + (handlers-macro/merge-fx cofx + {::mark-trusted-peer {:web3 (:web3 db) + :wnode wnode}} + (generate-mailserver-symkey)) + (connect-to-mailserver cofx))))))) + +(defn get-topics + [db topics discover?] + (let [inbox-topics (:inbox/topics db) + discovery-topic (transport.utils/get-topic constants/contact-discovery) + topics (or topics + (map #(:topic %) (vals (:transport/chats db))))] + (cond-> (apply conj inbox-topics topics) + discover? (conj discovery-topic)))) + +(defn request-messages + ([cofx] + (request-messages {} cofx)) + ([{:keys [topics discover? should-recover?] + :or {should-recover? true + discover? true}} + {:keys [db] :as cofx}] + (let [mailserver-status (:mailserver-status db) + sym-key-id (:inbox/sym-key-id db) + wnode (get-current-wnode-address db) + inbox-topics (get-topics db topics discover?) + inbox-ready? (and (= :connected mailserver-status) + sym-key-id)] + (when should-recover? + (if inbox-ready? + {::request-messages {:wnode wnode + :topics (into [] inbox-topics) + :sym-key-id sym-key-id + :web3 (:web3 db)} + :db (assoc db + :inbox/fetching? true + :inbox/topics #{}) + :dispatch-later [{:ms fetching-messages-notification-timeout + :dispatch [:inbox/remove-fetching-notification]}]} + {:db (assoc db :inbox/topics (into #{} inbox-topics))}))))) ;;;; Handlers (handlers/register-handler-fx - :inbox/add-peer - ;; This event adds a wnode to the list of peers - (fn [_ [_ wnode]] - {::add-peer {:wnode wnode}})) - -(handlers/register-handler-fx - :inbox/fetch-peers - ;; This event fetches the list of peers - ;; We want it to check if the node has been added - (fn [_ [_ retries]] - {::fetch-peers (or retries 0)})) - -(def ^:private ^:const short-retry-delay-ms 300) -(def ^:private ^:const long-retry-delay-ms 5000) -(def ^:private ^:const max-retries 10) -(def ^:private ^:const retries-interval-change-threshold 3) + :inbox/mailserver-trusted + (fn [{:keys [db] :as cofx} _] + (handlers-macro/merge-fx cofx + (update-mailserver-status :connected) + (request-messages)))) (defn add-custom-mailservers [mailservers {:keys [db]}] {:db (reduce (fn [db {:keys [id chain] :as mailserver}] @@ -189,71 +218,30 @@ db mailservers)}) -(handlers/register-handler-fx - :inbox/check-peer-added - ;; We check if the wnode is part of the peers list - ;; if not we dispatch a new fetch-peer event for later - (fn [{{:keys [web3 network-status] :as db} :db} [_ peers retries]] - (let [wnode (get-current-wnode-address db)] - (log/info "offline inbox: fetch-peers response" peers) - (if (registered-peer? peers wnode) - {::mark-trusted-peer {:web3 web3 - :wnode wnode}} - (do - (log/info "Peer" wnode "is not registered. Retrying fetch peers.") - (let [delay-ms (if (< retries retries-interval-change-threshold) - short-retry-delay-ms - long-retry-delay-ms)] - (if (or (= network-status :offline) - (> retries max-retries)) - (do (log/info :mailserver-connection-error) - {:db (assoc db :mailserver-status :disconnected)}) - {:dispatch-later [{:ms delay-ms :dispatch [:inbox/fetch-peers (inc retries)]}]}))))))) - -(handlers/register-handler-fx - :inbox/get-sym-key - (fn [{:keys [db]} _] - (let [web3 (:web3 db) - wnode (get-current-wnode-address db) - password (or (:password wnode) - (:inbox/password db))] - {:shh/generate-sym-key-from-password {:password password - :web3 web3 - :on-success (fn [_ sym-key-id] - (re-frame/dispatch [:inbox/get-sym-key-success sym-key-id])) - :on-error #(log/error "offline inbox: get-sym-key error" %)}}))) - (handlers/register-handler-fx :inbox/get-sym-key-success - (fn [{:keys [db]} [_ sym-key-id]] - {:db (assoc db :inbox/sym-key-id sym-key-id)})) - -(handlers/register-handler-fx - :inbox/connection-success - (fn [{:keys [db]} _] - {:db (assoc db :mailserver-status :connected)})) + (fn [{:keys [db] :as cofx} [_ sym-key-id]] + (handlers-macro/merge-fx cofx + {:db (assoc db :inbox/sym-key-id sym-key-id)} + (request-messages)))) (handlers/register-handler-fx :inbox/request-messages - (fn [{:keys [db now]} [_ {:keys [from topics discover?]}]] - (let [web3 (:web3 db) - wnode (get-current-wnode-address db) - topics (or topics - (map #(:topic %) (vals (:transport/chats db)))) - from (or from (:inbox/last-request db) nil) - sym-key-id (:inbox/sym-key-id db)] - {::request-messages {:wnode wnode - :topics (if discover? - (conj topics (transport.utils/get-topic constants/contact-discovery)) - topics) - ;;TODO (yenda) fix from, right now mailserver is dropping us - ;;when we send a requestMessage with a from field - ;;:from from - :sym-key-id sym-key-id - :web3 web3} - :db (assoc db :inbox/last-request (quot now 1000))}))) + (fn [cofx [_ args]] + (request-messages args cofx))) + +(handlers/register-handler-fx + :inbox/connection-check + (fn [{:keys [db] :as cofx} [_ _]] + (when (= :connecting (:mailserver-status db)) + (update-mailserver-status :error cofx)))) + +(handlers/register-handler-fx + :inbox/remove-fetching-notification + (fn [{:keys [db] :as cofx} [_ _]] + {:db (dissoc db :inbox/fetching?)})) (handlers/register-handler-fx :inbox/reconnect - (fn [cofx _] - (recover-offline-inbox true cofx))) + (fn [cofx [_ args]] + (connect-to-mailserver cofx))) diff --git a/src/status_im/transport/message/v1/public_chat.cljs b/src/status_im/transport/message/v1/public_chat.cljs index c45fd018ed..3e525ff4c9 100644 --- a/src/status_im/transport/message/v1/public_chat.cljs +++ b/src/status_im/transport/message/v1/public_chat.cljs @@ -41,5 +41,6 @@ (assoc :sym-key-id sym-key-id) ;;TODO (yenda) remove once go implements persistence (assoc :sym-key sym-key))})] - :dispatch [:inbox/request-messages {:topics [topic] - :from 0}]}))) + :dispatch [:inbox/request-messages {:topics [topic] + :discover? false + :from 0}]}))) diff --git a/src/status_im/ui/components/connectivity/view.cljs b/src/status_im/ui/components/connectivity/view.cljs index 75d8a0015a..1b5a04a987 100644 --- a/src/status_im/ui/components/connectivity/view.cljs +++ b/src/status_im/ui/components/connectivity/view.cljs @@ -1,44 +1,29 @@ (ns status-im.ui.components.connectivity.view + (:require-macros [status-im.utils.views :refer [defview letsubs] :as views]) (:require [re-frame.core :as re-frame] [reagent.core :as reagent] [status-im.ui.components.react :as react] [status-im.ui.components.connectivity.styles :as styles] - [status-im.ui.components.animation :as animation] [status-im.i18n :as i18n])) (def window-width (:width (react/get-dimensions "window"))) -(defn start-error-animation [offline-opacity] - (animation/start - (animation/timing offline-opacity {:toValue 1.0 - :duration 250}))) - -(defn error-view [_] - (let [offline? (re-frame/subscribe [:offline?]) - connection-problem? (re-frame/subscribe [:connection-problem?]) - offline-opacity (animation/create-value 0.0) - on-update (fn [_ _] - (animation/set-value offline-opacity 0) - (when (or @offline? @connection-problem?) - (start-error-animation offline-opacity))) - current-chat-contact (re-frame/subscribe [:get-current-chat-contact]) - view-id (re-frame/subscribe [:get :view-id])] - (reagent/create-class - {:component-did-mount - on-update - :component-did-update - on-update - :display-name "connectivity-error-view" - :reagent-render - (fn [{:keys [top]}] - (when-let [label (cond - @offline? :t/offline - @connection-problem? :t/mailserver-reconnect - :else nil)] - (let [pending? (and (:pending @current-chat-contact) (= :chat @view-id))] - [react/animated-view {:style (styles/text-wrapper top offline-opacity window-width pending?)} - [react/view - [react/text {:style styles/text - :on-press (when @connection-problem? - #(re-frame/dispatch [:inbox/reconnect]))} - (i18n/label label)]]])))}))) +(defview error-view [{:keys [top]}] + (letsubs [offline? [:offline?] + disconnected? [:disconnected?] + mailserver-error? [:mailserver-error?] + fetching? [:fetching?] + current-chat-contact [:get-current-chat-contact] + view-id [:get :view-id]] + (when-let [label (cond + offline? :t/offline + disconnected? :t/disconnected + mailserver-error? :t/mailserver-reconnect + fetching? :t/fetching-messages + :else nil)] + (let [pending? (and (:pending current-chat-contact) (= :chat view-id))] + [react/view {:style (styles/text-wrapper top 1.0 window-width pending?)} + [react/text {:style styles/text + :on-press (when mailserver-error? + #(re-frame/dispatch [:inbox/reconnect]))} + (i18n/label label)]])))) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 27e241286e..ff25a29cbb 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -37,9 +37,12 @@ :wallet.transactions constants/default-wallet-transactions :wallet-selected-asset {} :prices {} + :peers-count 0 + :peers-summary [] :notifications {} :network constants/default-network :networks/networks constants/default-networks + :inbox/topics #{} :inbox/wnodes constants/default-wnodes :inbox/password constants/inbox-password :my-profile/editing? false @@ -69,7 +72,7 @@ (spec/def ::network-status (spec/nilable keyword?)) (spec/def ::mailserver-status (spec/nilable keyword?)) -(spec/def ::peers-count (spec/nilable integer?)) +(spec/def :inbox/topics set?) ;;;;NODE @@ -124,6 +127,9 @@ ;;;;NETWORK (spec/def ::network (spec/nilable string?)) +(spec/def ::peers-count (spec/nilable integer?)) +(spec/def ::peers-summary (spec/nilable vector?)) +(spec/def :inbox/fetching? (spec/nilable boolean?)) ;;;;NODE @@ -168,9 +174,11 @@ :node/after-start :node/after-stop :inbox/wnodes + :inbox/topics :inbox/password :inbox/sym-key-id :inbox/last-request + :inbox/fetching? :browser/browsers :browser/options :new/open-dapp @@ -195,6 +203,7 @@ ::network-status ::mailserver-status ::peers-count + ::peers-summary ::sync-listening-started ::sync-state ::sync-data diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index b421bc27d7..a4e3b7131e 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -270,13 +270,15 @@ (handlers/register-handler-fx :initialize-db (fn [{{:keys [status-module-initialized? status-node-started? - network-status network device-UUID] + network-status network peers-count peers-summary device-UUID] :or {network (get app-db :network)}} :db} [_ encryption-key]] {::init-store encryption-key :db (assoc app-db :contacts/contacts {} :network-status network-status + :peers-count peers-count + :peers-summary peers-summary :status-module-initialized? (or platform/ios? js/goog.DEBUG status-module-initialized?) :status-node-started? status-node-started? :network network @@ -285,7 +287,7 @@ (handlers/register-handler-db :initialize-account-db (fn [{:keys [accounts/accounts accounts/create contacts/contacts networks/networks - network network-status view-id navigation-stack + network network-status peers-count peers-summary view-id navigation-stack access-scope->commands-responses status-module-initialized? status-node-started? device-UUID] :or [network (get app-db :network)]} [_ address]] @@ -303,6 +305,8 @@ :account/account current-account :network-status network-status :network network + :peers-summary peers-summary + :peers-count peers-count :device-UUID device-UUID) console-contact (assoc :contacts/contacts {constants/console-chat-id console-contact}))))) @@ -398,6 +402,16 @@ {:result {:returned (dissoc data :origParams)}}]) (log/debug "Unknown jail signal " event)))) +(handlers/register-handler-fx + :discovery/summary + (fn [{:keys [db] :as cofx} [_ peers-summary]] + (let [peers-count (count peers-summary)] + (handlers-macro/merge-fx cofx + {:db (assoc db + :peers-summary peers-summary + :peers-count peers-count)} + (inbox/peers-summary-change-fx))))) + (handlers/register-handler-fx :signal-event (fn [_ [_ event-str]] @@ -407,12 +421,13 @@ to-dispatch (case type "sign-request.queued" [:sign-request-queued event] "sign-request.failed" [:sign-request-failed event] - "node.started" [:status-node-started] - "node.stopped" [:status-node-stopped] - "module.initialized" [:status-module-initialized] - "jail.signal" (handle-jail-signal event) - "envelope.sent" [:signals/envelope-status (:hash event) :sent] - "envelope.expired" [:signals/envelope-status (:hash event) :not-sent] + "node.started" [:status-node-started] + "node.stopped" [:status-node-stopped] + "module.initialized" [:status-module-initialized] + "jail.signal" (handle-jail-signal event) + "envelope.sent" [:signals/envelope-status (:hash event) :sent] + "envelope.expired" [:signals/envelope-status (:hash event) :not-sent] + "discovery.summary" [:discovery/summary event] (log/debug "Event " type " not handled"))] (when to-dispatch {:dispatch to-dispatch})))) @@ -437,13 +452,11 @@ (handlers/register-handler-fx :app-state-change (fn [{{:keys [network-status mailserver-status]} :db :as cofx} [_ state]] - (let [app-coming-from-background? (= state "active") - should-recover? (and app-coming-from-background? - (= network-status :online) - (not= mailserver-status :connecting))] + (let [app-coming-from-background? (= state "active")] (handlers-macro/merge-fx cofx {::app-state-change-fx state} - (inbox/recover-offline-inbox should-recover?))))) + (inbox/request-messages {:should-recover? app-coming-from-background? + :discover? true}))))) (handlers/register-handler-fx :request-permissions diff --git a/src/status_im/ui/screens/subs.cljs b/src/status_im/ui/screens/subs.cljs index 129982f6f6..20f228cd69 100644 --- a/src/status_im/ui/screens/subs.cljs +++ b/src/status_im/ui/screens/subs.cljs @@ -44,6 +44,10 @@ (reg-sub :peers-count :peers-count) (reg-sub :mailserver-status :mailserver-status) +(reg-sub :fetching? + (fn [db] + (get db :inbox/fetching?))) + (reg-sub :offline? :<- [:network-status] :<- [:sync-state] @@ -51,12 +55,15 @@ (or (= network-status :offline) (= sync-state :offline)))) -(reg-sub :connection-problem? - :<- [:mailserver-status] +(reg-sub :disconnected? :<- [:peers-count] - (fn [[mailserver-status peers-count]] - (or (= :disconnected mailserver-status) - (zero? peers-count)))) + (fn [peers-count] + (zero? peers-count))) + +(reg-sub :mailserver-error? + :<- [:mailserver-status] + (fn [mailserver-status] + (#{:error :disconnected} mailserver-status))) (reg-sub :syncing? :<- [:sync-state] diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index 94e61a015a..133d8f7f22 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -21,7 +21,7 @@ (def testfairy-enabled? (enabled? (get-config :TESTFAIRY_ENABLED))) (def stub-status-go? (enabled? (get-config :STUB_STATUS_GO 0))) (def mainnet-warning-enabled? (enabled? (get-config :MAINNET_WARNING_ENABLED 0))) -(def offline-inbox-enabled? (enabled? (get-config :OFFLINE_INBOX_ENABLED 0))) +(def offline-inbox-enabled? (enabled? (get-config :OFFLINE_INBOX_ENABLED "1"))) (def log-level (-> (get-config :LOG_LEVEL "error") string/lower-case diff --git a/src/status_im/utils/utils.cljs b/src/status_im/utils/utils.cljs index 5afe41909e..a62ccf7421 100644 --- a/src/status_im/utils/utils.cljs +++ b/src/status_im/utils/utils.cljs @@ -1,6 +1,7 @@ (ns status-im.utils.utils (:require [status-im.i18n :as i18n] - [status-im.react-native.js-dependencies :as rn-dependencies])) + [status-im.react-native.js-dependencies :as rn-dependencies] + [re-frame.core :as re-frame])) (defn show-popup ([title content] @@ -59,6 +60,14 @@ (defn set-timeout [cb ms] (.setTimeout rn-dependencies/background-timer cb ms)) +;; same as re-frame dispatch-later but using background timer for long +;; running timeouts +(re-frame/reg-fx + :utils/dispatch-later + (fn [params] + (doseq [{:keys [ms dispatch]} params] + (set-timeout #(re-frame/dispatch dispatch) ms)))) + (defn clear-timeout [id] (.clearTimeout rn-dependencies/background-timer id)) diff --git a/test/cljs/status_im/test/runner.cljs b/test/cljs/status_im/test/runner.cljs index b7138f75f4..454f54ce60 100644 --- a/test/cljs/status_im/test/runner.cljs +++ b/test/cljs/status_im/test/runner.cljs @@ -18,6 +18,7 @@ [status-im.test.chat.subs] [status-im.test.chat.views.message] [status-im.test.i18n] + [status-im.test.transport.inbox] [status-im.test.protocol.web3.inbox] [status-im.test.utils.utils] [status-im.test.utils.money] @@ -62,6 +63,7 @@ 'status-im.test.chat.models.message 'status-im.test.chat.views.message 'status-im.test.i18n + 'status-im.test.transport.inbox 'status-im.test.protocol.web3.inbox 'status-im.test.utils.utils 'status-im.test.utils.money diff --git a/test/cljs/status_im/test/transport/inbox.cljs b/test/cljs/status_im/test/transport/inbox.cljs new file mode 100644 index 0000000000..e4ca474548 --- /dev/null +++ b/test/cljs/status_im/test/transport/inbox.cljs @@ -0,0 +1,80 @@ +(ns status-im.test.transport.inbox + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.transport.inbox :as inbox] + [status-im.constants :as constants])) + +(deftest request-messages + (testing "mailserver not connected" + (is (= (inbox/request-messages {} {:db {:mailserver-status :connecting :inbox/sym-key-id :sym-key}}) + {:db + {:mailserver-status :connecting, + :inbox/sym-key-id :sym-key, + :inbox/topics #{"0xf8946aac"}}})) + (is (= (inbox/request-messages {:discover? false :topics ["Oxaaaaaaaa"]} {:db {:mailserver-status :connecting :inbox/sym-key-id :sym-key}}) + {:db + {:mailserver-status :connecting, + :inbox/sym-key-id :sym-key, + :inbox/topics #{"Oxaaaaaaaa"}}}))) + (testing "mailserver is connected" + (is (= (inbox/request-messages {} {:db {:mailserver-status :connected :inbox/sym-key-id :sym-key}}) + {:status-im.transport.inbox/request-messages + {:wnode nil, :topics ["0xf8946aac"], :sym-key-id :sym-key, :web3 nil}, + :db + {:mailserver-status :connected, + :inbox/sym-key-id :sym-key, + :inbox/fetching? true, + :inbox/topics #{}}, + :dispatch-later + [{:ms 5000, :dispatch [:inbox/remove-fetching-notification]}]}) + (= (inbox/request-messages {:discover? false :topics ["Oxaaaaaaaa"]} {:db {:mailserver-status :connected :inbox/sym-key-id :sym-key}}) + {:status-im.transport.inbox/request-messages + {:wnode nil, :topics ["Oxaaaaaaaa"], :sym-key-id :sym-key, :web3 nil}, + :db + {:mailserver-status :connected, + :inbox/sym-key-id :sym-key, + :inbox/fetching? true, + :inbox/topics #{}}, + :dispatch-later + [{:ms 5000, :dispatch [:inbox/remove-fetching-notification]}]})))) + +(defn cofx-fixtures [sym-key peers-count registered-peer?] + {:db {:mailserver-status :connected + :inbox/sym-key-id sym-key + :network "mainnet_rpc" + :peers-count peers-count + :peers-summary (if registered-peer? + [{:id "wnode-id"}] + []) + :account/account {:networks constants/default-networks + :settings {:wnode {:mainnet "mailserver-a"}}} + :inbox/wnodes {:mainnet {"mailserver-a" {:address "enode://wnode-id@ip"}}}}}) + +(defn peers-summary-change-fx-result [sym-key peers-count registered-peer?] + (update-in (inbox/peers-summary-change-fx (cofx-fixtures sym-key peers-count registered-peer?)) + [:db] dissoc :account/account :inbox/wnodes :peers-summary :peers-count)) + +(deftest peers-summary-change-fx + (testing "Mailserver is connected and sym-key doesn't exists" + (let [result (peers-summary-change-fx-result false 1 true)] + (is (= (into #{} (keys result)) + #{:db :status-im.transport.inbox/mark-trusted-peer :shh/generate-sym-key-from-password})))) + (testing "Mailserver is connected and sym-key exists" + (let [result (peers-summary-change-fx-result true 1 true)] + (is (= (into #{} (keys result)) + #{:db :status-im.transport.inbox/mark-trusted-peer})))) + (testing "Mailserver is not connected and sym-key doesn't exists" + (let [result (peers-summary-change-fx-result false 1 false)] + (is (= (into #{} (keys result)) + #{:db :status-im.transport.inbox/add-peer :utils/dispatch-later :shh/generate-sym-key-from-password})) + (is (= (get-in result [:db :mailserver-status]) + :connecting)))) + (testing "Mailserver is not connected and sym-key exists" + (let [result (peers-summary-change-fx-result true 1 false)] + (is (= (into #{} (keys result)) + #{:db :status-im.transport.inbox/add-peer :utils/dispatch-later})) + (is (= (get-in result [:db :mailserver-status]) + :connecting)))) + (testing "App is not connected to any peer" + (is (= (get-in (peers-summary-change-fx-result true 0 true) + [:db :mailserver-status]) + :disconnected))))