Refactor offline inbox events

- Add error handlers
- Memoize calls to add-peer and mark-trusted-peer
- Use re-frame events to control flow
This commit is contained in:
Dmitry Novotochinov 2017-12-27 12:25:39 +03:00
parent 9f6d8d7090
commit 5f02e4287f
No known key found for this signature in database
GPG Key ID: 267674DCC86628D9
7 changed files with 201 additions and 68 deletions

View File

@ -87,6 +87,10 @@
(def default-wnodes [default-wnode])
;; TODO(oskarth): Determine if this is the correct topic or not
(def inbox-topic "0xaabb11ee")
(def inbox-password "status-offline-inbox")
(def ^:const send-transaction-no-error-code "0")
(def ^:const send-transaction-default-error-code "1")
(def ^:const send-transaction-password-error-code "2")

View File

@ -100,10 +100,7 @@
:allowP2P true
:topics [f/status-topic]}
(l/message-listener listener-options))
(inbox/request-messages!
web3
{:enode inbox/cluster-enode}
#(log/info "offline inbox: request-messages response" %)))
(inbox/initialize! web3))
(f/add-filter!
web3
{:key identity

View File

@ -12,6 +12,8 @@
[status-im.utils.random :as random]
[status-im.protocol.message-cache :as cache]
[status-im.chat.utils :as chat.utils]
[status-im.protocol.web3.inbox :as inbox]
[status-im.protocol.web3.keys :as web3.keys]
[status-im.utils.datetime :as datetime]
[taoensso.timbre :as log :refer-macros [debug]]
[status-im.native-module.core :as status]
@ -214,9 +216,104 @@
(cache/init! messages)
(processed-messages/delete (str "ttl <=" now)))))
(re-frame/reg-fx
::add-peer
(fn [{:keys [wnode web3]}]
(inbox/add-peer wnode
#(re-frame/dispatch [::add-peer-success web3 %])
#(re-frame/dispatch [::add-peer-error %]))))
(re-frame/reg-fx
::mark-trusted-peer
(fn [{:keys [wnode web3]}]
(inbox/mark-trusted-peer wnode
#(re-frame/dispatch [::mark-trusted-peer-success web3 %])
#(re-frame/dispatch [::mark-trusted-peer-error %]))))
(re-frame/reg-fx
::get-sym-key
(fn [{:keys [web3 password]}]
(web3.keys/get-sym-key web3
password
#(re-frame/dispatch [::get-sym-key-success web3 %])
#(re-frame/dispatch [::get-sym-key-error %]))))
(re-frame/reg-fx
::request-messages
(fn [{:keys [wnode topic sym-key-id]}]
(inbox/request-messages wnode
topic
sym-key-id
#(re-frame/dispatch [::request-messages-success %])
#(re-frame/dispatch [::request-messages-error %]))))
;;;; Handlers
;; NOTE(dmitryn): events chain
;; add-peeer -> mark-trusted-peer -> get-sym-key -> request-messages
(handlers/register-handler-fx
:initialize-offline-inbox
(fn [{:keys [db]} [_ web3]]
(log/info "offline inbox: initialize")
(let [wnode (get-in db [:inbox/wnode :address])]
{::add-peer {:wnode wnode
:web3 web3}})))
(handlers/register-handler-fx
::add-peer-success
(fn [{:keys [db]} [_ web3 response]]
(let [wnode (get-in db [:inbox/wnode :address])]
(log/info "offline inbox: add-peer response" wnode response)
{::mark-trusted-peer {:wnode wnode
:web3 web3}})))
(handlers/register-handler-fx
::mark-trusted-peer-success
(fn [{:keys [db]} [_ web3 response]]
(let [wnode (get-in db [:inbox/wnode :address])
password (:inbox/password db)]
(log/info "offline inbox: mark-trusted-peer response" wnode response)
{::get-sym-key {:password password
:web3 web3}})))
(handlers/register-handler-fx
::get-sym-key-success
(fn [{:keys [db]} [_ web3 sym-key-id]]
(log/info "offline inbox: get-sym-key response" sym-key-id)
(let [wnode (get-in db [:inbox/wnode :address])
topic (:inbox/topic db)]
{::request-messages {:wnode wnode
:topic topic
:sym-key-id sym-key-id
:web3 web3}})))
(handlers/register-handler-fx
::request-messages-success
(fn [_ [_ response]]
(log/info "offline inbox: request-messages response" response)))
(handlers/register-handler-fx
::add-peer-error
(fn [_ [_ error]]
(log/error "offline inbox: add-peer error" error)))
(handlers/register-handler-fx
::mark-trusted-peer-error
(fn [_ [_ error]]
(log/error "offline inbox: mark-trusted-peer error" error)))
(handlers/register-handler-fx
::get-sym-key-error
(fn [_ [_ error]]
(log/error "offline inbox: get-sym-key error" error)))
(handlers/register-handler-fx
::request-messages-error
(fn [_ [_ error]]
(log/error "offline inbox: request-messages error" error)))
;;; INITIALIZE PROTOCOL
(handlers/register-handler-fx

View File

@ -1,67 +1,76 @@
(ns status-im.protocol.web3.inbox
(:require [status-im.constants :as constants]
[status-im.protocol.web3.utils :as utils]
[status-im.native-module.core :as status]
[status-im.protocol.web3.keys :as keys]
[taoensso.timbre :as log]))
(:require [status-im.native-module.core :as status]
[taoensso.timbre :as log]
[re-frame.core :as re-frame]
[clojure.string :as string]
[status-im.protocol.web3.keys :as keys]))
(def peers (atom #{}))
(def trusted-peers (atom #{}))
;; TODO(oskarth): Determine if this is the correct topic or not
;; If it is, use constant in other namespace
(def default-topic "0xaabb11ee")
;; NOTE(dmitryn) Expects JSON response like:
;; {"error": "msg"} or {"result": true}
(defn- parse-json [s]
(try
(-> s
js/JSON.parse
(js->clj :keywordize-keys true))
(catch :default e
{:error (.-message e)})))
(def inbox-password "status-offline-inbox")
(defn- response-handler [error-fn success-fn]
(fn [response]
(let [{:keys [error result]} (parse-json response)]
;; NOTE(dmitryn): AddPeer() may return {"error": ""}
;; assuming empty error is a success response
(if (seq error)
(error-fn error)
(success-fn result)))))
;; TODO(oskarth): Hardcoded to local enode for preMVP, will be in bootnodes later
(def default-enode "enode://0f51d75c9469de0852571c4618fe151265d4930ea35f968eb1a12e69c12f7cbabed856a12b31268a825ca2c9bafa47ef665b1b17be1ab71de83338c4b7439b24@127.0.0.1:30303")
;; adamb's status-cluster enode
(def cluster-enode (:address constants/default-wnode))
;; TODO(oskarth): Rewrite callback-heavy code with CSP and/or coeffects
;; TODO(oskarth): Memoize addPeer and markTrusted, similar to keys/get-sym-key
;; TODO(oskarth): Actually deal with errors, all in same cb - outside scope of this
(defn request-messages! [web3 {:keys [enode topic password]
:or {enode default-enode
password inbox-password
topic default-topic}} callback]
(status/add-peer
enode
(fn [res]
(log/info "offline inbox: add peer" enode res)
(let [args {:jsonrpc "2.0"
:id 1
:method "shh_markTrustedPeer"
:params [enode]}
payload (.stringify js/JSON (clj->js args))]
(log/info "offline inbox: mark-trusted-peer request")
(status/call-web3
payload
(fn [res2]
(log/info "offline inbox: mark-trusted-peer response" enode res2)
(keys/get-sym-key web3 password
(fn [sym-key-id]
(log/info "offline inbox: sym-key-id" sym-key-id)
(let [args {:jsonrpc "2.0"
:id 2
:method "shh_requestMessages"
;; NOTE: "from" and "to" parameters omitted here
;; by default "from" is 24 hours ago and "to" is time now
:params [{:mailServerPeer enode
:topic topic
:symKeyID sym-key-id}]}
payload (.stringify js/JSON (clj->js args))]
(log/info "offline inbox: request-messages request")
(log/info "offline inbox: request-messages args" (pr-str args))
(log/info "offline inbox: request-messages payload" (pr-str payload))
(status/call-web3 payload callback))))))))))
(defn add-peer [enode success-fn error-fn]
(if (@peers enode)
(success-fn true)
(status/add-peer enode
(response-handler error-fn (fn [result]
(swap! peers conj enode)
(success-fn result))))))
;; TODO(oskarth): Use web3 binding to do (.markTrustedPeer web3 enode cb)
;;
(defn mark-trusted-peer [enode success-fn error-fn]
(if (@trusted-peers enode)
(success-fn true)
(let [args {:jsonrpc "2.0"
:id 1
:method "shh_markTrustedPeer"
:params [enode]}
payload (.stringify js/JSON (clj->js args))]
(status/call-web3 payload
(response-handler error-fn (fn [result]
(swap! trusted-peers conj enode)
(success-fn result)))))))
;; TODO(oskarth): Use web3 binding instead of raw RPC above, pending binding and deps:
;; (.requestMessages (utils/shh web3)
;; (clj->js opts)
;; callback
;; #(log/warn :request-messages-error
;; (.stringify js/JSON (clj->js opts)) %))
(defn request-messages [wnode topic sym-key-id success-fn error-fn]
(log/info "offline inbox: sym-key-id" sym-key-id)
(let [args {:jsonrpc "2.0"
:id 2
:method "shh_requestMessages"
;; NOTE: "from" and "to" parameters omitted here
;; by default "from" is 24 hours ago and "to" is time now
:params [{:mailServerPeer wnode
:topic topic
:symKeyID sym-key-id}]}
payload (.stringify js/JSON (clj->js args))]
(log/info "offline inbox: request-messages request")
(log/info "offline inbox: request-messages args" (pr-str args))
(log/info "offline inbox: request-messages payload" (pr-str payload))
(status/call-web3 payload
(response-handler error-fn success-fn))))
(defn initialize! [web3]
(re-frame/dispatch [:initialize-offline-inbox web3]))

View File

@ -1,4 +1,5 @@
(ns status-im.protocol.web3.keys)
(ns status-im.protocol.web3.keys
(:require [taoensso.timbre :as log]))
(def status-key-password "status-key-password")
(def status-group-key-password "status-public-group-key-password")
@ -13,14 +14,20 @@
(defn get-sym-key
"Memoizes expensive calls by password."
[web3 password callback]
(if-let [key-id (get @password->keys password)]
(callback key-id)
(add-sym-key-from-password
([web3 password success-fn]
;; TODO:(dmitryn) add proper error handling
;; to other usages of get-sym-key fn
(get-sym-key web3 password success-fn #(log/error %)))
([web3 password success-fn error-fn]
(if-let [key-id (get @password->keys password)]
(success-fn key-id)
(add-sym-key-from-password
web3 password
(fn [err res]
(swap! password->keys assoc password res)
(callback res)))))
(if err
(error-fn err)
(do (swap! password->keys assoc password res)
(success-fn res))))))))
(defn reset-keys! []
(reset! password->keys {}))

View File

@ -13,7 +13,8 @@
status-im.commands.specs
status-im.ui.screens.profile.db
status-im.ui.screens.discover.db
status-im.ui.screens.network-settings.db))
status-im.ui.screens.network-settings.db
status-im.ui.screens.offline-messaging-settings.db))
(def transaction-send-default
{:symbol :ETH
@ -44,7 +45,10 @@
:prices {}
:notifications {}
:network constants/default-network
:networks/networks constants/default-networks})
:networks/networks constants/default-networks
:inbox/wnode constants/default-wnode
:inbox/topic constants/inbox-topic
:inbox/password constants/inbox-password})
;;;;GLOBAL
@ -122,7 +126,10 @@
:networks/selected-network
:networks/networks
:node/after-start
:node/after-stop]
:node/after-stop
:inbox/wnode
:inbox/topic
:inbox/password]
:opt-un
[::current-public-key
::modal

View File

@ -0,0 +1,12 @@
(ns status-im.ui.screens.offline-messaging-settings.db
(:require-macros [status-im.utils.db :refer [allowed-keys]])
(:require [cljs.spec.alpha :as spec]))
(def enode-address-regex #"enode://[a-zA-Z0-9]+\@\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b:(\d{1,5})")
(spec/def ::not-blank-string (spec/and string? seq))
(spec/def :wnode/address (spec/and string? #(re-matches enode-address-regex %)))
(spec/def :wnode/name ::not-blank-string)
(spec/def :inbox/topic ::not-blank-string)
(spec/def :inbox/password ::not-blank-string)
(spec/def :inbox/wnode (allowed-keys :req-un [:wnode/address :wnode/name]))