Publish contact updates periodically
Currently it's very easy for contact details to get out of sync, the simplest example is: A & B are contacts. A changes name. B receives the updated name. B re-install the app. Until A changes name again, B will not see their name, picture and won't be able to send push notifications. This PR changes the behavior to publish account informations to contacts every 24 hrs, to add some redundancy in this cases. It also publishes a contact code every 12hrs. Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
6a7efb8339
commit
7960fdef85
|
@ -102,12 +102,15 @@
|
|||
[{db :db} input-key text]
|
||||
{:db (update db :accounts/create merge {input-key text :error nil})})
|
||||
|
||||
(defn account-set-name [{{:accounts/keys [create] :as db} :db :as cofx}]
|
||||
(defn account-set-name [{{:accounts/keys [create] :as db} :db now :now :as cofx}]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db :accounts/create {:show-welcome? true})
|
||||
:notifications/request-notifications-permissions nil
|
||||
:dispatch [:navigate-to :home]}
|
||||
(accounts.update/account-update {:name (:name create)} {})))
|
||||
;; We set last updated as we are actually changing a field,
|
||||
;; unlike on recovery where the name is not set
|
||||
(accounts.update/account-update {:last-updated now
|
||||
:name (:name create)} {})))
|
||||
|
||||
(fx/defn next-step
|
||||
[{:keys [db] :as cofx} step password password-confirm]
|
||||
|
|
|
@ -1,9 +1,46 @@
|
|||
(ns status-im.accounts.update.core
|
||||
(:require [status-im.data-store.accounts :as accounts-store]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.data-store.transport :as transport-store]
|
||||
[status-im.transport.message.contact :as message.contact]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(fx/defn account-update-message [{:keys [db]}]
|
||||
(let [account (:account/account db)
|
||||
fcm-token (get-in db [:notifications :fcm-token])
|
||||
{:keys [name photo-path address]} account]
|
||||
(message.contact/ContactUpdate. name photo-path address fcm-token)))
|
||||
|
||||
(fx/defn send-contact-update-fx
|
||||
[{:keys [db] :as cofx} chat-id payload]
|
||||
(when-let [chat (get-in cofx [:db :transport/chats chat-id])]
|
||||
(let [updated-chat (assoc chat :resend? "contact-update")
|
||||
tx [(transport-store/save-transport-tx {:chat-id chat-id
|
||||
:chat updated-chat})]
|
||||
success-event [:transport/contact-message-sent chat-id]]
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:transport/chats chat-id :resend?]
|
||||
"contact-update")
|
||||
:data-store/tx tx}
|
||||
(protocol/send-with-pubkey {:chat-id chat-id
|
||||
:payload payload
|
||||
:success-event success-event})))))
|
||||
|
||||
(fx/defn contact-public-keys [{:keys [db]}]
|
||||
(reduce (fn [acc [_ {:keys [public-key dapp? pending?]}]]
|
||||
(if (and (not dapp?)
|
||||
(not pending?))
|
||||
(conj acc public-key)
|
||||
acc))
|
||||
#{}
|
||||
(:contacts/contacts db)))
|
||||
|
||||
(fx/defn send-contact-update [cofx payload]
|
||||
(let [public-keys (contact-public-keys cofx)]
|
||||
;;NOTE: chats with contacts use public-key as chat-id
|
||||
(map #(send-contact-update-fx % payload) public-keys)))
|
||||
|
||||
(fx/defn account-update
|
||||
"Takes effects (containing :db) + new account fields, adds all effects necessary for account update.
|
||||
Optionally, one can specify a success-event to be dispatched after fields are persisted."
|
||||
|
@ -18,7 +55,7 @@
|
|||
(if (or (:name new-account-fields) (:photo-path new-account-fields))
|
||||
(fx/merge cofx
|
||||
fx
|
||||
#(protocol/send (message.contact/ContactUpdate. name photo-path address fcm-token) nil %))
|
||||
#(protocol/send (account-update-message %) nil %))
|
||||
fx)))
|
||||
|
||||
(fx/defn clean-seed-phrase
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
(ns status-im.accounts.update.publisher
|
||||
(:require [status-im.constants :as constants]
|
||||
[status-im.accounts.update.core :as accounts]
|
||||
[status-im.pairing.core :as pairing]
|
||||
[status-im.data-store.accounts :as accounts-store]
|
||||
[status-im.transport.shh :as shh]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
;; Publish updates every 48 hours
|
||||
(def publish-updates-interval (* 48 60 60 1000))
|
||||
|
||||
(defn publish-update! [{:keys [db now web3]}]
|
||||
(let [my-public-key (get-in db [:account/account :public-key])
|
||||
peers-count (:peers-count db)
|
||||
last-updated (get-in
|
||||
db
|
||||
[:account/account :last-updated])]
|
||||
(when (and (pos? peers-count)
|
||||
(pos? last-updated)
|
||||
(< publish-updates-interval
|
||||
(- now last-updated)))
|
||||
(let [public-keys (accounts/contact-public-keys {:db db})
|
||||
payload (accounts/account-update-message {:db db})
|
||||
sync-message (pairing/sync-installation-account-message {:db db})]
|
||||
(doseq [pk public-keys]
|
||||
(shh/send-direct-message!
|
||||
web3
|
||||
{:pubKey pk
|
||||
:sig my-public-key
|
||||
:chat constants/contact-discovery
|
||||
:payload payload}
|
||||
[:accounts.update.callback/published]
|
||||
[:accounts.update.callback/failed-to-publish]
|
||||
1))
|
||||
(shh/send-direct-message!
|
||||
web3
|
||||
{:pubKey my-public-key
|
||||
:sig my-public-key
|
||||
:chat constants/contact-discovery
|
||||
:payload sync-message}
|
||||
[:accounts.update.callback/published]
|
||||
[:accounts.update.callback/failed-to-publish]
|
||||
1)))))
|
|
@ -4,8 +4,10 @@
|
|||
[status-im.data-store.chats :as chats-store]
|
||||
[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]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.transport.chat.core :as transport.chat]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.transport.message.public-chat :as public-chat]
|
||||
[status-im.ui.components.colors :as colors]
|
||||
|
@ -28,6 +30,9 @@
|
|||
([cofx chat-id]
|
||||
(multi-user-chat? (get-chat cofx chat-id))))
|
||||
|
||||
(def one-to-one-chat?
|
||||
(complement multi-user-chat?))
|
||||
|
||||
(defn public-chat?
|
||||
([chat]
|
||||
(:public? chat))
|
||||
|
@ -142,6 +147,8 @@
|
|||
(transport.chat/unsubscribe-from-chat % 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
|
||||
|
@ -217,10 +224,12 @@
|
|||
(fx/defn preload-chat-data
|
||||
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
|
||||
[{:keys [db] :as cofx} chat-id]
|
||||
(fx/merge cofx
|
||||
{:db (-> (assoc db :current-chat-id chat-id)
|
||||
(set-chat-ui-props {:validation-messages nil}))}
|
||||
(mark-messages-seen chat-id)))
|
||||
(let [chat (get-in db [:chats chat-id])]
|
||||
(fx/merge cofx
|
||||
{:db (-> (assoc db :current-chat-id chat-id)
|
||||
(set-chat-ui-props {:validation-messages nil}))}
|
||||
(contact-code/listen-to-chat chat-id)
|
||||
(mark-messages-seen chat-id))))
|
||||
|
||||
(fx/defn navigate-to-chat
|
||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
[status-im.data-store.messages :as data-store.messages]
|
||||
[status-im.data-store.chats :as data-store.chats]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.transport.message.contact :as message.contact]
|
||||
[status-im.transport.message.public-chat :as transport.public-chat]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.ui.screens.add-new.new-chat.db :as new-chat.db]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.fx :as fx]
|
||||
|
@ -47,16 +50,15 @@
|
|||
:address address
|
||||
:fcm-token fcm-token}))
|
||||
|
||||
(fx/defn add-new-contact [{:keys [db]} {:keys [public-key] :as contact}]
|
||||
(let [new-contact (assoc contact
|
||||
:pending? false
|
||||
:hide-contact? false
|
||||
:public-key public-key)]
|
||||
{:db (-> db
|
||||
(update-in [:contacts/contacts public-key]
|
||||
merge new-contact)
|
||||
(assoc-in [:contacts/new-identity] ""))
|
||||
:data-store/tx [(contacts-store/save-contact-tx new-contact)]}))
|
||||
(fx/defn upsert-contact [{:keys [db] :as cofx}
|
||||
{:keys [pending?
|
||||
public-key] :as contact}]
|
||||
(fx/merge cofx
|
||||
{:db (-> db
|
||||
(update-in [:contacts/contacts public-key] merge contact))
|
||||
:data-store/tx [(contacts-store/save-contact-tx contact)]}
|
||||
#(when-not pending?
|
||||
(contact-code/listen-to-chat % public-key))))
|
||||
|
||||
(fx/defn send-contact-request
|
||||
[{:keys [db] :as cofx} {:keys [public-key pending? dapp?] :as contact}]
|
||||
|
@ -65,11 +67,16 @@
|
|||
(protocol/send (message.contact/map->ContactRequestConfirmed (own-info db)) public-key cofx)
|
||||
(protocol/send (message.contact/map->ContactRequest (own-info db)) public-key cofx))))
|
||||
|
||||
(fx/defn add-contact [{:keys [db] :as cofx} public-key]
|
||||
(fx/defn add-contact
|
||||
"Add a contact and set pending to false"
|
||||
[{:keys [db] :as cofx} public-key]
|
||||
(when (not= (get-in db [:account/account :public-key]) public-key)
|
||||
(let [contact (build-contact cofx public-key)]
|
||||
(let [contact (-> (build-contact cofx public-key)
|
||||
(assoc :pending? false
|
||||
:hide-contact? false))]
|
||||
(fx/merge cofx
|
||||
(add-new-contact contact)
|
||||
{:db (assoc-in db [:contacts/new-identity] "")}
|
||||
(upsert-contact contact)
|
||||
(send-contact-request contact)))))
|
||||
|
||||
(fx/defn add-contacts-filter [{:keys [db]} public-key action]
|
||||
|
@ -244,10 +251,7 @@
|
|||
(when-not (= contact-props
|
||||
(select-keys contact [:public-key :address :photo-path
|
||||
:name :fcm-token :pending?]))
|
||||
{:db (update-in db [:contacts/contacts public-key]
|
||||
merge contact-props)
|
||||
:data-store/tx [(contacts-store/save-contact-tx
|
||||
contact-props)]})))))
|
||||
(upsert-contact cofx contact-props))))))
|
||||
|
||||
(def receive-contact-request handle-contact-update)
|
||||
(def receive-contact-request-confirmation handle-contact-update)
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
(ns status-im.contact-code.core
|
||||
"This namespace is used to listen for and publish contact-codes. We want to listen
|
||||
to contact codes once we engage in the conversation with someone, or once someone is
|
||||
in our contacts."
|
||||
(:require
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.transport.shh :as shh]
|
||||
[status-im.transport.message.public-chat :as transport.public-chat]
|
||||
[status-im.data-store.accounts :as data-store.accounts]
|
||||
[status-im.transport.chat.core :as transport.chat]
|
||||
[status-im.accounts.db :as accounts.db]))
|
||||
|
||||
(defn topic [pk]
|
||||
(str pk "-contact-code"))
|
||||
|
||||
(fx/defn listen [cofx chat-id]
|
||||
(transport.public-chat/join-public-chat
|
||||
cofx
|
||||
(topic chat-id)))
|
||||
|
||||
(fx/defn listen-to-chat
|
||||
"For a one-to-one chat, listen to the pk of the user, for a group chat
|
||||
listen for any member"
|
||||
[cofx chat-id]
|
||||
(let [{:keys [members
|
||||
public?
|
||||
is-active
|
||||
group-chat]} (get-in cofx [:db :chats chat-id])]
|
||||
(when is-active
|
||||
(cond
|
||||
(and group-chat
|
||||
(not public?))
|
||||
(apply fx/merge cofx
|
||||
(map listen members))
|
||||
(not public?)
|
||||
(listen cofx chat-id)))))
|
||||
|
||||
(fx/defn stop-listening
|
||||
"We can stop listening to contact codes when we don't have any active chat
|
||||
with the user (one-to-one or group-chat), and it is not in our contacts"
|
||||
[{:keys [db] :as cofx} their-public-key]
|
||||
(let [my-public-key (accounts.db/current-public-key cofx)
|
||||
active-group-chats (filter (fn [{:keys [is-active members members-joined]}]
|
||||
(and is-active
|
||||
(contains? members-joined my-public-key)
|
||||
(contains? members their-public-key)))
|
||||
(vals (:chats db)))]
|
||||
(when (and (not= false (get-in db [:contacts/contacts their-public-key :pending?]))
|
||||
(not= my-public-key their-public-key)
|
||||
(not (get-in db [:chats their-public-key :is-active]))
|
||||
(empty? active-group-chats))
|
||||
|
||||
(fx/merge
|
||||
cofx
|
||||
(transport.chat/unsubscribe-from-chat (topic their-public-key))))))
|
||||
|
||||
;; Publish contact code every 12hrs
|
||||
(def publish-contact-code-interval (* 12 60 60 1000))
|
||||
|
||||
(fx/defn init [cofx]
|
||||
(log/debug "initializing contact-code")
|
||||
(let [current-public-key (accounts.db/current-public-key cofx)]
|
||||
(listen cofx current-public-key)))
|
||||
|
||||
(defn publish! [{:keys [web3 now] :as cofx}]
|
||||
(let [current-public-key (accounts.db/current-public-key cofx)
|
||||
chat-id (topic current-public-key)
|
||||
peers-count (:peers-count @re-frame.db/app-db)
|
||||
last-published (get-in
|
||||
@re-frame.db/app-db
|
||||
[:account/account :last-published-contact-code])]
|
||||
(when (and (pos? peers-count)
|
||||
(< publish-contact-code-interval
|
||||
(- now last-published)))
|
||||
|
||||
(let [message {:chat chat-id
|
||||
:sig current-public-key
|
||||
:payload ""}]
|
||||
(shh/send-public-message!
|
||||
web3
|
||||
message
|
||||
[:contact-code.callback/contact-code-published]
|
||||
:contact-code.callback/contact-code-publishing-failed)))))
|
||||
|
||||
(fx/defn published [{:keys [now db] :as cofx}]
|
||||
(let [new-account (assoc (:account/account db)
|
||||
:last-published-contact-code
|
||||
now)]
|
||||
{:db (assoc db :account/account new-account)
|
||||
:data-store/base-tx [(data-store.accounts/save-account-tx new-account)]}))
|
||||
|
||||
(fx/defn publishing-failed [cofx]
|
||||
(log/warn "failed to publish contact-code"))
|
|
@ -230,3 +230,6 @@
|
|||
{:type "string[]" :optional true}
|
||||
:recent-stickers
|
||||
{:type "string[]" :optional true}}))
|
||||
(def v20 (assoc-in v19
|
||||
[:properties :last-published-contact-code]
|
||||
{:type :int :default 0}))
|
||||
|
|
|
@ -93,6 +93,11 @@
|
|||
|
||||
(def v24 v23)
|
||||
|
||||
(def v25 [network/v1
|
||||
bootnode/v4
|
||||
extension/v12
|
||||
account/v20])
|
||||
|
||||
;; put schemas ordered by version
|
||||
(def schemas [{:schema v1
|
||||
:schemaVersion 1
|
||||
|
@ -165,4 +170,7 @@
|
|||
:migration (constantly nil)}
|
||||
{:schema v24
|
||||
:schemaVersion 24
|
||||
:migration migrations/v24}])
|
||||
:migration migrations/v24}
|
||||
{:schema v25
|
||||
:schemaVersion 25
|
||||
:migration (constantly nil)}])
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
[status-im.network.core :as network]
|
||||
[status-im.notifications.core :as notifications]
|
||||
[status-im.pairing.core :as pairing]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.privacy-policy.core :as privacy-policy]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[status-im.qr-scanner.core :as qr-scanner]
|
||||
|
@ -154,6 +155,17 @@
|
|||
(fn [cofx _]
|
||||
(accounts.update/account-update cofx {:mainnet-warning-shown? true} {})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:accounts.update.callback/published
|
||||
(fn [{:keys [now] :as cofx} _]
|
||||
(accounts.update/account-update cofx {:last-updated now} {})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:accounts.update.callback/failed-to-publish
|
||||
(fn [{:keys [now] :as cofx} [_ message]]
|
||||
(log/warn "failed to publish account update" message)
|
||||
(accounts.update/account-update cofx {:last-updated now} {})))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:accounts.ui/dev-mode-switched
|
||||
(fn [cofx [_ dev-mode?]]
|
||||
|
@ -1583,6 +1595,16 @@
|
|||
(fn [cofx [_ initial-props]]
|
||||
{:db (assoc (:db cofx) :initial-props initial-props)}))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:contact-code.callback/contact-code-published
|
||||
(fn [cofx arg]
|
||||
(contact-code/published cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:contact-code.callback/contact-code-publishing-failed
|
||||
(fn [cofx _]
|
||||
(contact-code/publishing-failed cofx)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:pairing.ui/enable-installation-pressed
|
||||
(fn [cofx [_ installation-id]]
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[status-im.utils.clocks :as utils.clocks]
|
||||
[status-im.chat.models.message :as models.message]
|
||||
[status-im.contact.core :as models.contact]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.native-module.core :as native-module]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.transport.db :as transport.db]
|
||||
|
@ -483,14 +484,30 @@
|
|||
from)))
|
||||
last))
|
||||
|
||||
(fx/defn set-up-topic [cofx chat-id previous-chat]
|
||||
(fx/defn set-up-topic
|
||||
"Listen/Tear down the shared topic/contact-codes. Stop listening for members who
|
||||
have left the chat"
|
||||
[cofx chat-id previous-chat]
|
||||
(let [my-public-key (accounts.db/current-public-key cofx)
|
||||
new-chat (get-in cofx [:db :chats chat-id])]
|
||||
;; If we left the chat, teardown, otherwise upsert
|
||||
(if (and (joined? my-public-key previous-chat)
|
||||
(not (joined? my-public-key new-chat)))
|
||||
(transport.chat/unsubscribe-from-chat cofx chat-id)
|
||||
(transport.public-chat/join-group-chat cofx chat-id))))
|
||||
(apply fx/merge
|
||||
cofx
|
||||
(conj
|
||||
(map #(contact-code/stop-listening %)
|
||||
(:members new-chat))
|
||||
(transport.chat/unsubscribe-from-chat chat-id)))
|
||||
(apply fx/merge
|
||||
cofx
|
||||
(concat
|
||||
(map #(contact-code/listen-to-chat %)
|
||||
(:members new-chat))
|
||||
(map #(contact-code/stop-listening %)
|
||||
(clojure.set/difference (:members previous-chat)
|
||||
(:members new-chat)))
|
||||
[(transport.public-chat/join-group-chat chat-id)])))))
|
||||
|
||||
(fx/defn handle-membership-update
|
||||
"Upsert chat and receive message if valid"
|
||||
|
|
|
@ -239,56 +239,6 @@
|
|||
account-address
|
||||
success-fn)))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Periodic background job
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defn- async-periodic-run!
|
||||
([async-periodic-chan]
|
||||
(async-periodic-run! async-periodic-chan true))
|
||||
([async-periodic-chan worker-fn]
|
||||
(async/put! async-periodic-chan worker-fn)))
|
||||
|
||||
(defn- async-periodic-stop! [async-periodic-chan]
|
||||
(async/close! async-periodic-chan))
|
||||
|
||||
(defn- async-periodic-exec
|
||||
"Periodically execute an function.
|
||||
|
||||
Takes a work-fn of one argument `finished-fn -> any` this function
|
||||
is passed a finished-fn that must be called to signal that the work
|
||||
being performed in the work-fn is finished.
|
||||
|
||||
Returns a go channel that represents a way to control the looping process.
|
||||
|
||||
Stop the polling loop with `async-periodic-stop!`
|
||||
|
||||
The work-fn can be forced to run immediately with `async-periodic-run!`
|
||||
|
||||
Or you can queue up another fn `finished-fn -> any` to execute on
|
||||
the queue with `async-periodic-run!`."
|
||||
[work-fn interval-ms timeout-ms]
|
||||
{:pre [(fn? work-fn) (integer? interval-ms) (integer? timeout-ms)]}
|
||||
(let [do-now-chan (async/chan (async/sliding-buffer 1))
|
||||
try-it (fn [exec-fn catch-fn] (try (exec-fn) (catch :default e (catch-fn e))))]
|
||||
(go-loop []
|
||||
(let [timeout (async-util/timeout interval-ms)
|
||||
finished-chan (async/promise-chan)
|
||||
[v ch] (async/alts! [do-now-chan timeout])
|
||||
worker (if (and (= ch do-now-chan) (fn? v))
|
||||
v work-fn)]
|
||||
(when-not (and (= ch do-now-chan) (nil? v))
|
||||
;; don't let try catch be parsed by go-block
|
||||
(try-it #(worker (fn [] (async/put! finished-chan true)))
|
||||
(fn [e]
|
||||
(log/error "failed to run transaction sync" e)
|
||||
;; if an error occurs in work-fn log it and consider it done
|
||||
(async/put! finished-chan true)))
|
||||
;; sanity timeout for work-fn
|
||||
(async/alts! [finished-chan (async-util/timeout timeout-ms)])
|
||||
(recur))))
|
||||
do-now-chan))
|
||||
|
||||
;; -----------------------------------------------------------------------------
|
||||
;; Helpers functions that help determine if a background sync should execute
|
||||
;; -----------------------------------------------------------------------------
|
||||
|
@ -396,7 +346,7 @@
|
|||
(when (and (not= network-status :offline)
|
||||
(= app-state "active")
|
||||
(not= :custom chain))
|
||||
(async-periodic-run!
|
||||
(async-util/async-periodic-run!
|
||||
@polling-executor
|
||||
(partial transactions-query-helper web3 all-tokens account-address chain))))))
|
||||
|
||||
|
@ -421,9 +371,9 @@
|
|||
(defn- start-sync! [{:keys [:account/account network web3] :as options}]
|
||||
(let [account-address (:address account)]
|
||||
(when @polling-executor
|
||||
(async-periodic-stop! @polling-executor))
|
||||
(async-util/async-periodic-stop! @polling-executor))
|
||||
(reset! polling-executor
|
||||
(async-periodic-exec
|
||||
(async-util/async-periodic-exec
|
||||
(partial #'background-sync web3 account-address)
|
||||
sync-interval-ms
|
||||
sync-timeout-ms)))
|
||||
|
@ -442,7 +392,7 @@
|
|||
(re-frame/reg-fx
|
||||
::stop-sync-transactions
|
||||
#(when @polling-executor
|
||||
(async-periodic-stop! @polling-executor)))
|
||||
(async-util/async-periodic-stop! @polling-executor)))
|
||||
|
||||
(fx/defn stop-sync [_]
|
||||
{::stop-sync-transactions nil})
|
||||
|
|
|
@ -7,11 +7,15 @@
|
|||
[status-im.utils.config :as config]
|
||||
[status-im.utils.platform :as utils.platform]
|
||||
[status-im.chat.models :as models.chat]
|
||||
[status-im.transport.message.public-chat :as transport.public-chat]
|
||||
[status-im.accounts.db :as accounts.db]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.data-store.installations :as data-store.installations]
|
||||
[status-im.native-module.core :as native-module]
|
||||
[status-im.utils.identicon :as identicon]
|
||||
[status-im.contact.core :as contact]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.data-store.contacts :as data-store.contacts]
|
||||
[status-im.data-store.accounts :as data-store.accounts]
|
||||
[status-im.transport.message.pairing :as transport.pairing]))
|
||||
|
@ -227,16 +231,17 @@
|
|||
|
||||
(defn handle-sync-installation [{:keys [db] :as cofx} {:keys [contacts account chat]} sender]
|
||||
(when (= sender (accounts.db/current-public-key cofx))
|
||||
(let [new-contacts (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts))
|
||||
new-account (merge-account (:account/account db) account)]
|
||||
(fx/merge cofx
|
||||
{:db (assoc db
|
||||
:contacts/contacts new-contacts
|
||||
:account/account new-account)
|
||||
:data-store/base-tx [(data-store.accounts/save-account-tx new-account)]
|
||||
:data-store/tx [(data-store.contacts/save-contacts-tx (vals new-contacts))]}
|
||||
#(when (:public? chat)
|
||||
(models.chat/start-public-chat % (:chat-id chat) {:dont-navigate? true}))))))
|
||||
(let [new-contacts (vals (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts)))
|
||||
new-account (merge-account (:account/account db) account)
|
||||
contacts-fx (mapv contact/upsert-contact new-contacts)]
|
||||
(apply fx/merge
|
||||
cofx
|
||||
(concat
|
||||
[{:db (assoc db :account/account new-account)
|
||||
:data-store/base-tx [(data-store.accounts/save-account-tx new-account)]}
|
||||
#(when (:public? chat)
|
||||
(models.chat/start-public-chat % (:chat-id chat) {:dont-navigate? true}))]
|
||||
contacts-fx)))))
|
||||
|
||||
(defn handle-pair-installation [{:keys [db] :as cofx} {:keys [name installation-id device-type]} timestamp sender]
|
||||
(when (and (= sender (accounts.db/current-public-key cofx))
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
[status-im.mailserver.core :as mailserver]
|
||||
[status-im.transport.message.core :as message]
|
||||
[status-im.transport.partitioned-topic :as transport.topic]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.utils.publisher :as publisher]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[taoensso.timbre :as log]
|
||||
|
@ -54,6 +56,8 @@
|
|||
(assoc chat :chat-id chat-id)))
|
||||
(:transport/chats db))
|
||||
:on-success #(re-frame/dispatch [::sym-keys-added %])}}
|
||||
(publisher/start-fx)
|
||||
(contact-code/init)
|
||||
(mailserver/connect-to-mailserver)
|
||||
(message/resend-contact-messages [])))))
|
||||
|
||||
|
@ -100,11 +104,15 @@
|
|||
It is necessary to remove the filters because status-go there isn't currently a logout feature in status-go
|
||||
to clean-up after logout. When logging out of account A and logging in account B, account B would receive
|
||||
account A messages without this."
|
||||
[{:keys [db]} callback]
|
||||
[{:keys [db] :as cofx} callback]
|
||||
(let [{:transport/keys [filters]} db]
|
||||
{:shh/remove-filters {:filters (mapcat (fn [[chat-id chat-filters]]
|
||||
(map (fn [filter]
|
||||
[chat-id filter])
|
||||
chat-filters))
|
||||
filters)
|
||||
:callback callback}}))
|
||||
(fx/merge
|
||||
cofx
|
||||
|
||||
{:shh/remove-filters {:filters (mapcat (fn [[chat-id chat-filters]]
|
||||
(map (fn [filter]
|
||||
[chat-id filter])
|
||||
chat-filters))
|
||||
filters)
|
||||
:callback callback}}
|
||||
(publisher/stop-fx))))
|
||||
|
|
|
@ -108,8 +108,9 @@
|
|||
|
||||
(re-frame/reg-fx
|
||||
:shh/remove-filter
|
||||
(fn [{:keys [filter] :as params}]
|
||||
(when filter (remove-filter! params))))
|
||||
(fn [filters]
|
||||
(doseq [{:keys [filter] :as params} filters]
|
||||
(when filter (remove-filter! params)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:shh/remove-filters
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require [status-im.group-chats.core :as group-chats]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.pairing.core :as pairing]
|
||||
[status-im.accounts.update.core :as accounts.update]
|
||||
[status-im.data-store.transport :as transport-store]
|
||||
[status-im.transport.db :as transport.db]
|
||||
[status-im.transport.message.pairing :as transport.pairing]
|
||||
|
@ -67,33 +68,10 @@
|
|||
:success-event success-event})
|
||||
(pairing/send-installation-message-fx sync-message)))))
|
||||
|
||||
(fx/defn send-contact-update
|
||||
[{:keys [db] :as cofx} chat-id payload]
|
||||
(when-let [chat (get-in cofx [:db :transport/chats chat-id])]
|
||||
(let [updated-chat (assoc chat :resend? "contact-update")
|
||||
tx [(transport-store/save-transport-tx {:chat-id chat-id
|
||||
:chat updated-chat})]
|
||||
success-event [:transport/contact-message-sent chat-id]]
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:transport/chats chat-id :resend?]
|
||||
"contact-update")
|
||||
:data-store/tx tx}
|
||||
(protocol/send-with-pubkey {:chat-id chat-id
|
||||
:payload payload
|
||||
:success-event success-event})))))
|
||||
(extend-type transport.contact/ContactUpdate
|
||||
protocol/StatusMessage
|
||||
(send [this _ {:keys [db] :as cofx}]
|
||||
(let [contact-public-keys (reduce (fn [acc [_ {:keys [public-key dapp? pending?]}]]
|
||||
(if (and (not dapp?)
|
||||
(not pending?))
|
||||
(conj acc public-key)
|
||||
acc))
|
||||
#{}
|
||||
(:contacts/contacts db))
|
||||
;;NOTE: chats with contacts use public-key as chat-id
|
||||
send-contact-update-fxs (map #(send-contact-update % this) contact-public-keys)
|
||||
(let [send-contact-update-fxs (accounts.update/send-contact-update cofx this)
|
||||
sync-message (pairing/sync-installation-account-message cofx)
|
||||
fxs (conj send-contact-update-fxs
|
||||
(pairing/send-installation-message-fx sync-message))]
|
||||
|
|
|
@ -69,23 +69,24 @@
|
|||
(log/debug :shh/post-success))
|
||||
(re-frame/dispatch [error-event err resp]))))
|
||||
|
||||
(defn send-direct-message! [web3 direct-message success-event error-event count]
|
||||
(.. web3
|
||||
-shh
|
||||
(sendDirectMessage
|
||||
(clj->js (update direct-message :payload (comp transport.utils/from-utf8
|
||||
transit/serialize)))
|
||||
(handle-response success-event error-event count))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:shh/send-direct-message
|
||||
(fn [post-calls]
|
||||
(doseq [{:keys [web3 payload src dst success-event error-event]
|
||||
:or {error-event :transport/send-status-message-error}} post-calls]
|
||||
(let [chat (transport.topic/public-key->discovery-topic dst)
|
||||
direct-message (clj->js {:pubKey dst
|
||||
:sig src
|
||||
:chat chat
|
||||
:payload (-> payload
|
||||
transit/serialize
|
||||
transport.utils/from-utf8)})]
|
||||
(.. web3
|
||||
-shh
|
||||
(sendDirectMessage
|
||||
direct-message
|
||||
(handle-response success-event error-event 1)))))))
|
||||
(let [direct-message {:pubKey dst
|
||||
:sig src
|
||||
:chat (transport.topic/public-key->discovery-topic dst)
|
||||
:payload payload}]
|
||||
(send-direct-message! web3 direct-message success-event error-event 1)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:shh/send-pairing-message
|
||||
|
@ -123,21 +124,24 @@
|
|||
message
|
||||
(handle-response success-event error-event (count dsts)))))))))
|
||||
|
||||
(defn send-public-message! [web3 message success-event error-event]
|
||||
(.. web3
|
||||
-shh
|
||||
(sendPublicMessage
|
||||
(clj->js message)
|
||||
(handle-response success-event error-event 1))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:shh/send-public-message
|
||||
(fn [post-calls]
|
||||
(doseq [{:keys [web3 payload src chat success-event error-event]
|
||||
:or {error-event :transport/send-status-message-error}} post-calls]
|
||||
(let [message (clj->js {:chat chat
|
||||
:sig src
|
||||
:payload (-> payload
|
||||
transit/serialize
|
||||
transport.utils/from-utf8)})]
|
||||
(.. web3
|
||||
-shh
|
||||
(sendPublicMessage
|
||||
message
|
||||
(handle-response success-event error-event 1)))))))
|
||||
(let [message {:chat chat
|
||||
:sig src
|
||||
:payload (-> payload
|
||||
transit/serialize
|
||||
transport.utils/from-utf8)}]
|
||||
(send-public-message! web3 message success-event error-event)))))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:shh/post
|
||||
|
|
|
@ -50,3 +50,53 @@
|
|||
(run-task task-fn)
|
||||
(recur (async/<! task-queue)))
|
||||
task-queue))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Periodic background job
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defn async-periodic-run!
|
||||
([async-periodic-chan]
|
||||
(async-periodic-run! async-periodic-chan true))
|
||||
([async-periodic-chan worker-fn]
|
||||
(async/put! async-periodic-chan worker-fn)))
|
||||
|
||||
(defn async-periodic-stop! [async-periodic-chan]
|
||||
(async/close! async-periodic-chan))
|
||||
|
||||
(defn async-periodic-exec
|
||||
"Periodically execute an function.
|
||||
|
||||
Takes a work-fn of one argument `finished-fn -> any` this function
|
||||
is passed a finished-fn that must be called to signal that the work
|
||||
being performed in the work-fn is finished.
|
||||
|
||||
Returns a go channel that represents a way to control the looping process.
|
||||
|
||||
Stop the polling loop with `async-periodic-stop!`
|
||||
|
||||
The work-fn can be forced to run immediately with `async-periodic-run!`
|
||||
|
||||
Or you can queue up another fn `finished-fn -> any` to execute on
|
||||
the queue with `async-periodic-run!`."
|
||||
[work-fn interval-ms timeout-ms]
|
||||
{:pre [(fn? work-fn) (integer? interval-ms) (integer? timeout-ms)]}
|
||||
(let [do-now-chan (async/chan (async/sliding-buffer 1))
|
||||
try-it (fn [exec-fn catch-fn] (try (exec-fn) (catch :default e (catch-fn e))))]
|
||||
(async/go-loop []
|
||||
(let [timeout-chan (timeout interval-ms)
|
||||
finished-chan (async/promise-chan)
|
||||
[v ch] (async/alts! [do-now-chan timeout-chan])
|
||||
worker (if (and (= ch do-now-chan) (fn? v))
|
||||
v work-fn)]
|
||||
(when-not (and (= ch do-now-chan) (nil? v))
|
||||
;; don't let try catch be parsed by go-block
|
||||
(try-it #(worker (fn [] (async/put! finished-chan true)))
|
||||
(fn [e]
|
||||
(log/error "failed to run job" e)
|
||||
;; if an error occurs in work-fn log it and consider it done
|
||||
(async/put! finished-chan true)))
|
||||
;; sanity timeout for work-fn
|
||||
(async/alts! [finished-chan (timeout timeout-ms)])
|
||||
(recur))))
|
||||
do-now-chan))
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
(def ^:private mergable-keys
|
||||
#{:data-store/tx :data-store/base-tx :chat-received-message/add-fx
|
||||
:shh/add-new-sym-keys :shh/get-new-sym-keys :shh/post
|
||||
:shh/send-direct-message
|
||||
: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})
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
(ns status-im.utils.publisher
|
||||
(:require [re-frame.core :as re-frame]
|
||||
[re-frame.db]
|
||||
[status-im.accounts.update.publisher :as accounts]
|
||||
[status-im.contact-code.core :as contact-code]
|
||||
[status-im.utils.async :as async-util]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
(defonce polling-executor (atom nil))
|
||||
(def sync-interval-ms 120000)
|
||||
(def sync-timeout-ms 20000)
|
||||
|
||||
(defn- start-publisher! [web3]
|
||||
(when @polling-executor
|
||||
(async-util/async-periodic-stop! @polling-executor))
|
||||
(reset! polling-executor
|
||||
(async-util/async-periodic-exec
|
||||
(fn [done-fn]
|
||||
(let [cofx {:web3 web3
|
||||
:now (datetime/timestamp)
|
||||
:db @re-frame.db/app-db}]
|
||||
(accounts/publish-update! cofx)
|
||||
(contact-code/publish! cofx)
|
||||
(done-fn)))
|
||||
sync-interval-ms
|
||||
sync-timeout-ms)))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::start-publisher
|
||||
#(start-publisher! %))
|
||||
|
||||
(re-frame/reg-fx
|
||||
::stop-publisher
|
||||
#(when @polling-executor
|
||||
(async-util/async-periodic-stop! @polling-executor)))
|
||||
|
||||
(fx/defn start-fx [{:keys [web3]}]
|
||||
{::start-publisher web3})
|
||||
|
||||
(fx/defn stop-fx [cofx]
|
||||
{::stop-publisher []})
|
|
@ -168,7 +168,7 @@
|
|||
(testing "it adds the relevant transactions for realm"
|
||||
(let [actual (chat/remove-chat cofx chat-id)]
|
||||
(is (:data-store/tx actual))
|
||||
(is (= 3 (count (:data-store/tx actual))))))))
|
||||
(is (= 5 (count (:data-store/tx actual))))))))
|
||||
|
||||
(deftest multi-user-chat?
|
||||
(let [chat-id "1"]
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
(ns status-im.test.contact-code.core
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.contact-code.core :as contact-code]))
|
||||
|
||||
(def me "me")
|
||||
(def member-1 "member-1")
|
||||
(def member-1-topic "member-1-contact-code")
|
||||
(def member-2 "member-2")
|
||||
(def member-2-topic "member-2-contact-code")
|
||||
(def chat-id "chat-id")
|
||||
(def chat-id-topic "chat-id-contact-code")
|
||||
|
||||
(deftest listen-to-chat
|
||||
(testing "an inactive chat"
|
||||
(testing "it does nothing"
|
||||
(is (not (contact-code/listen-to-chat {:db {}} chat-id)))))
|
||||
(testing "an active 1-to-1 chat"
|
||||
(testing "it listen to the topic"
|
||||
(is (get-in
|
||||
(contact-code/listen-to-chat {:db {:chats {chat-id {:is-active true}}}}
|
||||
chat-id)
|
||||
[:db :transport/chats chat-id-topic]))))
|
||||
(testing "an active group chat"
|
||||
(testing "it listen to any member"
|
||||
(let [transport (get-in
|
||||
(contact-code/listen-to-chat {:db {:chats {chat-id
|
||||
{:is-active true
|
||||
:group-chat true
|
||||
:members #{member-1
|
||||
member-2}}}}}
|
||||
chat-id)
|
||||
[:db :transport/chats])]
|
||||
(is (not (get transport chat-id-topic)))
|
||||
(is (get transport member-1-topic))
|
||||
(is (get transport member-2-topic))))))
|
||||
|
||||
(deftest stop-listening
|
||||
(testing "the user is in our contacts"
|
||||
(testing "it does not remove transport"
|
||||
(is (not (contact-code/stop-listening {:db {:contacts/contacts
|
||||
{chat-id {:pending? false}}}}
|
||||
chat-id)))))
|
||||
(testing "the user is not in our contacts"
|
||||
(testing "the user is not in any group chats or 1-to1-"
|
||||
(testing "it removes the transport"
|
||||
(let [transport (contact-code/stop-listening {:db {:transport/chats
|
||||
{chat-id-topic {}}}}
|
||||
chat-id)]
|
||||
(is transport)
|
||||
(is (not (get transport chat-id-topic))))))
|
||||
(testing "the user is still in some group chats"
|
||||
(testing "we joined, and group chat is active it does not remove transport"
|
||||
(let [transport (contact-code/stop-listening {:db {:account/account {:public-key me}
|
||||
:chats
|
||||
{chat-id {:is-active true
|
||||
:members-joined #{me}
|
||||
:members #{member-1}}}
|
||||
:transport/chats
|
||||
{member-1-topic {}}}}
|
||||
member-1)]
|
||||
(is (not transport))))
|
||||
(testing "we didn't join, it removes transport"
|
||||
(let [transport (contact-code/stop-listening {:db {:account/account {:public-key me}
|
||||
:chats
|
||||
{chat-id {:is-active true
|
||||
:members-joined #{member-1}
|
||||
:members #{member-1}}}
|
||||
:transport/chats
|
||||
{member-1-topic {}}}}
|
||||
member-1)]
|
||||
(is transport)
|
||||
(is (not (get transport member-1-topic))))))
|
||||
(testing "we have a 1-to-1 chat with the user"
|
||||
(testing "it does not remove transport"
|
||||
(let [transport (contact-code/stop-listening {:db {:chats
|
||||
{member-1 {:is-active true}}}}
|
||||
member-1)]
|
||||
(is (not transport)))))))
|
|
@ -29,7 +29,7 @@
|
|||
:profile-image "image"
|
||||
:address "address"
|
||||
:fcm-token "token"}
|
||||
{})
|
||||
{:db {}})
|
||||
contact (get-in actual [:db :contacts/contacts public-key])]
|
||||
(testing "it stores the contact in the database"
|
||||
(is (:data-store/tx actual)))
|
||||
|
|
|
@ -73,8 +73,7 @@
|
|||
(is (= expected (pairing/merge-contact contact-1 contact-2))))))
|
||||
|
||||
(deftest handle-sync-installation-test
|
||||
(with-redefs [config/pairing-enabled? (constantly true)
|
||||
identicon/identicon (constantly "generated")]
|
||||
(with-redefs [identicon/identicon (constantly "generated")]
|
||||
|
||||
(testing "syncing contacts"
|
||||
(let [old-contact-1 {:name "old-contact-one"
|
||||
|
@ -164,28 +163,27 @@
|
|||
[:db :chats "status"]))))))))
|
||||
|
||||
(deftest handle-pair-installation-test
|
||||
(with-redefs [config/pairing-enabled? (constantly true)]
|
||||
(let [cofx {:db {:account/account {:public-key "us"}
|
||||
:pairing/installations {"1" {:has-bundle? true
|
||||
:installation-id "1"}
|
||||
"2" {:has-bundle? false
|
||||
:installation-id "2"}}}}
|
||||
pair-message {:device-type "ios"
|
||||
:name "name"
|
||||
:installation-id "1"}]
|
||||
(testing "not coming from us"
|
||||
(is (not (pairing/handle-pair-installation cofx pair-message 1 "not-us"))))
|
||||
(testing "coming from us"
|
||||
(is (= {"1" {:has-bundle? true
|
||||
:installation-id "1"
|
||||
:name "name"
|
||||
:last-paired 1
|
||||
:device-type "ios"}
|
||||
"2" {:has-bundle? false
|
||||
:installation-id "2"}}
|
||||
(get-in
|
||||
(pairing/handle-pair-installation cofx pair-message 1 "us")
|
||||
[:db :pairing/installations])))))))
|
||||
(let [cofx {:db {:account/account {:public-key "us"}
|
||||
:pairing/installations {"1" {:has-bundle? true
|
||||
:installation-id "1"}
|
||||
"2" {:has-bundle? false
|
||||
:installation-id "2"}}}}
|
||||
pair-message {:device-type "ios"
|
||||
:name "name"
|
||||
:installation-id "1"}]
|
||||
(testing "not coming from us"
|
||||
(is (not (pairing/handle-pair-installation cofx pair-message 1 "not-us"))))
|
||||
(testing "coming from us"
|
||||
(is (= {"1" {:has-bundle? true
|
||||
:installation-id "1"
|
||||
:name "name"
|
||||
:last-paired 1
|
||||
:device-type "ios"}
|
||||
"2" {:has-bundle? false
|
||||
:installation-id "2"}}
|
||||
(get-in
|
||||
(pairing/handle-pair-installation cofx pair-message 1 "us")
|
||||
[:db :pairing/installations]))))))
|
||||
|
||||
(deftest sync-installation-messages-test
|
||||
(testing "it creates a sync installation message"
|
||||
|
@ -225,23 +223,22 @@
|
|||
(is (= expected (pairing/sync-installation-messages cofx))))))
|
||||
|
||||
(deftest handle-bundles-added-test
|
||||
(with-redefs [config/pairing-enabled? (constantly true)]
|
||||
(let [installation-1 {:has-bundle? false
|
||||
:installation-id "installation-1"}
|
||||
cofx {:db {:account/account {:public-key "us"}
|
||||
:pairing/installations {"installation-1" installation-1}}}]
|
||||
(testing "new installations"
|
||||
(let [new-installation {:identity "us" :installationID "installation-2"}
|
||||
expected {"installation-1" installation-1
|
||||
"installation-2" {:has-bundle? true
|
||||
:installation-id "installation-2"}}]
|
||||
(is (= expected (get-in (pairing/handle-bundles-added cofx new-installation) [:db :pairing/installations])))))
|
||||
(testing "already existing installation"
|
||||
(let [old-installation {:identity "us" :installationID "installation-1"}]
|
||||
(is (not (pairing/handle-bundles-added cofx old-installation)))))
|
||||
(testing "not from us"
|
||||
(let [new-installation {:identity "not-us" :installationID "does-not-matter"}]
|
||||
(is (not (pairing/handle-bundles-added cofx new-installation))))))))
|
||||
(let [installation-1 {:has-bundle? false
|
||||
:installation-id "installation-1"}
|
||||
cofx {:db {:account/account {:public-key "us"}
|
||||
:pairing/installations {"installation-1" installation-1}}}]
|
||||
(testing "new installations"
|
||||
(let [new-installation {:identity "us" :installationID "installation-2"}
|
||||
expected {"installation-1" installation-1
|
||||
"installation-2" {:has-bundle? true
|
||||
:installation-id "installation-2"}}]
|
||||
(is (= expected (get-in (pairing/handle-bundles-added cofx new-installation) [:db :pairing/installations])))))
|
||||
(testing "already existing installation"
|
||||
(let [old-installation {:identity "us" :installationID "installation-1"}]
|
||||
(is (not (pairing/handle-bundles-added cofx old-installation)))))
|
||||
(testing "not from us"
|
||||
(let [new-installation {:identity "not-us" :installationID "does-not-matter"}]
|
||||
(is (not (pairing/handle-bundles-added cofx new-installation)))))))
|
||||
|
||||
(deftest has-paired-installations-test
|
||||
(testing "no paired devices"
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
[status-im.test.accounts.recover.core]
|
||||
[status-im.test.hardwallet.core]
|
||||
[status-im.test.contact-recovery.core]
|
||||
[status-im.test.contact-code.core]
|
||||
[status-im.test.ui.screens.currency-settings.models]
|
||||
[status-im.test.ui.screens.wallet.db]
|
||||
[status-im.test.sign-in.flow]))
|
||||
|
@ -131,6 +132,7 @@
|
|||
'status-im.test.ui.screens.wallet.db
|
||||
'status-im.test.browser.core
|
||||
'status-im.test.contact-recovery.core
|
||||
'status-im.test.contact-code.core
|
||||
'status-im.test.extensions.ethereum
|
||||
'status-im.test.browser.permissions
|
||||
'status-im.test.sign-in.flow)
|
||||
|
|
Loading…
Reference in New Issue