move transport (#18062)
This commit is contained in:
parent
5c30fd847a
commit
fe20fa4e99
|
@ -95,7 +95,6 @@ react-native.fs/unlink
|
||||||
react-native.fs/file-exists?
|
react-native.fs/file-exists?
|
||||||
status-im.ui.components.colors/white
|
status-im.ui.components.colors/white
|
||||||
status-im.ui.components.colors/black
|
status-im.ui.components.colors/black
|
||||||
status-im.transport.core-test/messages
|
|
||||||
status-im.ui.components.core/animated-header
|
status-im.ui.components.core/animated-header
|
||||||
status-im.ui.components.core/safe-area-provider
|
status-im.ui.components.core/safe-area-provider
|
||||||
status-im.ui.components.core/safe-area-consumer
|
status-im.ui.components.core/safe-area-consumer
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
[goog.object :as object]
|
[goog.object :as object]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.chat.models.mentions :as mentions]
|
[status-im.chat.models.mentions :as mentions]
|
||||||
[status-im.chat.models.message :as chat.message]
|
|
||||||
[status-im.chat.models.message-content :as message-content]
|
[status-im.chat.models.message-content :as message-content]
|
||||||
[status-im.data-store.messages :as data-store-messages]
|
[status-im.data-store.messages :as data-store-messages]
|
||||||
[status-im2.constants :as constants]
|
[status-im2.constants :as constants]
|
||||||
[status-im2.contexts.chat.composer.link-preview.events :as link-preview]
|
[status-im2.contexts.chat.composer.link-preview.events :as link-preview]
|
||||||
|
[status-im2.contexts.chat.messages.transport.events :as messages.transport]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.i18n :as i18n]
|
[utils.i18n :as i18n]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
|
@ -205,7 +205,7 @@
|
||||||
(rf/merge cofx
|
(rf/merge cofx
|
||||||
(clean-input (:current-chat-id db))
|
(clean-input (:current-chat-id db))
|
||||||
(link-preview/reset-unfurled)
|
(link-preview/reset-unfurled)
|
||||||
(chat.message/send-messages messages)))))
|
(messages.transport/send-chat-messages messages)))))
|
||||||
|
|
||||||
(rf/defn send-audio-message
|
(rf/defn send-audio-message
|
||||||
[{:keys [db] :as cofx} audio-path duration current-chat-id]
|
[{:keys [db] :as cofx} audio-path duration current-chat-id]
|
||||||
|
@ -214,25 +214,26 @@
|
||||||
(when-not (string/blank? audio-path)
|
(when-not (string/blank? audio-path)
|
||||||
(rf/merge
|
(rf/merge
|
||||||
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :responding-to-message] nil)}
|
{:db (assoc-in db [:chat/inputs current-chat-id :metadata :responding-to-message] nil)}
|
||||||
(chat.message/send-message
|
(messages.transport/send-chat-messages
|
||||||
(merge
|
[(merge
|
||||||
{:chat-id current-chat-id
|
{:chat-id current-chat-id
|
||||||
:content-type constants/content-type-audio
|
:content-type constants/content-type-audio
|
||||||
:audio-path audio-path
|
:audio-path audio-path
|
||||||
:audio-duration-ms duration
|
:audio-duration-ms duration
|
||||||
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})}
|
:text (i18n/label :t/update-to-listen-audio {"locale" "en"})}
|
||||||
(when message-id
|
(when message-id
|
||||||
{:response-to message-id})))))))
|
{:response-to message-id}))])))))
|
||||||
|
|
||||||
(rf/defn send-sticker-message
|
(rf/defn send-sticker-message
|
||||||
[cofx {:keys [hash packID pack]} current-chat-id]
|
[cofx {:keys [hash packID pack]} current-chat-id]
|
||||||
(when-not (or (string/blank? hash) (and (string/blank? packID) (string/blank? pack)))
|
(when-not (or (string/blank? hash) (and (string/blank? packID) (string/blank? pack)))
|
||||||
(chat.message/send-message cofx
|
(messages.transport/send-chat-messages
|
||||||
{:chat-id current-chat-id
|
cofx
|
||||||
:content-type constants/content-type-sticker
|
[{:chat-id current-chat-id
|
||||||
:sticker {:hash hash
|
:content-type constants/content-type-sticker
|
||||||
:pack (int (if (string/blank? packID) pack packID))}
|
:sticker {:hash hash
|
||||||
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})})))
|
:pack (int (if (string/blank? packID) pack packID))}
|
||||||
|
:text (i18n/label :t/update-to-see-sticker {"locale" "en"})}])))
|
||||||
|
|
||||||
(rf/defn send-edited-message
|
(rf/defn send-edited-message
|
||||||
[{:keys [db]
|
[{:keys [db]
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[status-im.chat.models.loading :as chat.loading]
|
[status-im.chat.models.loading :as chat.loading]
|
||||||
[status-im.data-store.messages :as data-store.messages]
|
[status-im.data-store.messages :as data-store.messages]
|
||||||
[status-im.transport.message.protocol :as protocol]
|
|
||||||
[status-im.utils.deprecated-types :as types]
|
[status-im.utils.deprecated-types :as types]
|
||||||
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
|
[status-im2.contexts.chat.messages.delete-message.events :as delete-message]
|
||||||
[status-im2.contexts.chat.messages.list.events :as message-list]
|
[status-im2.contexts.chat.messages.list.events :as message-list]
|
||||||
|
@ -21,12 +20,6 @@
|
||||||
[db chat-id clock-value]
|
[db chat-id clock-value]
|
||||||
(>= (get-in db [:chats chat-id :deleted-at-clock-value]) clock-value))
|
(>= (get-in db [:chats chat-id :deleted-at-clock-value]) clock-value))
|
||||||
|
|
||||||
(defn add-timeline-message
|
|
||||||
[acc chat-id message-id message]
|
|
||||||
(-> acc
|
|
||||||
(update-in [:db :messages chat-id] assoc message-id message)
|
|
||||||
(update-in [:db :message-lists chat-id] message-list/add message)))
|
|
||||||
|
|
||||||
(defn hide-message
|
(defn hide-message
|
||||||
"Hide chat message, rebuild message-list"
|
"Hide chat message, rebuild message-list"
|
||||||
[{:keys [db]} chat-id message-id]
|
[{:keys [db]} chat-id message-id]
|
||||||
|
@ -145,14 +138,6 @@
|
||||||
:on-error #(log/error "failed to re-send message" %)}]}
|
:on-error #(log/error "failed to re-send message" %)}]}
|
||||||
(update-message-status chat-id message-id :sending)))
|
(update-message-status chat-id message-id :sending)))
|
||||||
|
|
||||||
(rf/defn send-message
|
|
||||||
[cofx message]
|
|
||||||
(protocol/send-chat-messages cofx [message]))
|
|
||||||
|
|
||||||
(rf/defn send-messages
|
|
||||||
[cofx messages]
|
|
||||||
(protocol/send-chat-messages cofx messages))
|
|
||||||
|
|
||||||
(rf/defn handle-removed-messages
|
(rf/defn handle-removed-messages
|
||||||
{:events [::handle-removed-messages]}
|
{:events [::handle-removed-messages]}
|
||||||
[{:keys [db] :as cofx} removed-messages]
|
[{:keys [db] :as cofx} removed-messages]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
(:require
|
(:require
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.data-store.reactions :as data-store.reactions]
|
[status-im.data-store.reactions :as data-store.reactions]
|
||||||
[status-im.transport.message.protocol :as message.protocol]
|
|
||||||
[status-im2.constants :as constants]
|
[status-im2.constants :as constants]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[utils.re-frame :as rf]
|
[utils.re-frame :as rf]
|
||||||
|
@ -63,23 +62,6 @@
|
||||||
(let [reactions-w-chat-id (map #(assoc % :chat-id chat-id) reactions)]
|
(let [reactions-w-chat-id (map #(assoc % :chat-id chat-id) reactions)]
|
||||||
{:db (update db :reactions (process-reactions (:chats db)) reactions-w-chat-id)})))
|
{:db (update db :reactions (process-reactions (:chats db)) reactions-w-chat-id)})))
|
||||||
|
|
||||||
|
|
||||||
;; Send reactions
|
|
||||||
|
|
||||||
|
|
||||||
(rf/defn send-emoji-reaction
|
|
||||||
{:events [:models.reactions/send-emoji-reaction]}
|
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
|
||||||
(message.protocol/send-reaction cofx
|
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
|
||||||
|
|
||||||
(rf/defn send-retract-emoji-reaction
|
|
||||||
{:events [:models.reactions/send-emoji-reaction-retraction]}
|
|
||||||
[{{:keys [current-chat-id]} :db :as cofx} reaction]
|
|
||||||
(message.protocol/send-retract-reaction cofx
|
|
||||||
(update reaction :chat-id #(or % current-chat-id))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn message-reactions
|
(defn message-reactions
|
||||||
[current-public-key reactions]
|
[current-public-key reactions]
|
||||||
(reduce
|
(reduce
|
||||||
|
|
|
@ -32,9 +32,7 @@
|
||||||
status-im.pairing.core
|
status-im.pairing.core
|
||||||
status-im.profile.core
|
status-im.profile.core
|
||||||
status-im.search.core
|
status-im.search.core
|
||||||
status-im.signals.core
|
|
||||||
status-im.stickers.core
|
status-im.stickers.core
|
||||||
status-im.transport.core
|
|
||||||
status-im.ui.components.invite.events
|
status-im.ui.components.invite.events
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
status-im.ui.screens.notifications-settings.events
|
status-im.ui.screens.notifications-settings.events
|
||||||
|
|
|
@ -412,3 +412,17 @@
|
||||||
(rf/merge cofx
|
(rf/merge cofx
|
||||||
{:db (dissoc db :mailserver.edit/mailserver)}
|
{:db (dissoc db :mailserver.edit/mailserver)}
|
||||||
(navigation/navigate-to :edit-mailserver nil)))
|
(navigation/navigate-to :edit-mailserver nil)))
|
||||||
|
|
||||||
|
(defn add-mailservers
|
||||||
|
[db mailservers]
|
||||||
|
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
|
||||||
|
(let [updated-mailserver
|
||||||
|
(-> mailserver
|
||||||
|
(update :id keyword)
|
||||||
|
(assoc :name (if (seq name) name id))
|
||||||
|
(dissoc :fleet))]
|
||||||
|
(assoc-in db
|
||||||
|
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
||||||
|
updated-mailserver)))
|
||||||
|
db
|
||||||
|
mailservers))
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
(ns ^{:doc "API to init and stop whisper messaging"} status-im.transport.core
|
|
||||||
(:require
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im.pairing.core :as pairing]
|
|
||||||
[status-im.stickers.core :as stickers]
|
|
||||||
status-im.transport.shh
|
|
||||||
[status-im2.common.universal-links :as universal-links]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[utils.re-frame :as rf]))
|
|
||||||
|
|
||||||
(rf/defn set-node-info
|
|
||||||
{:events [:transport.callback/node-info-fetched]}
|
|
||||||
[{:keys [db]} node-info]
|
|
||||||
{:db (assoc db :node-info node-info)})
|
|
||||||
|
|
||||||
(rf/defn fetch-node-info-fx
|
|
||||||
[_]
|
|
||||||
{:json-rpc/call [{:method "admin_nodeInfo"
|
|
||||||
:on-success #(re-frame/dispatch [:transport.callback/node-info-fetched %])
|
|
||||||
:on-error #(log/error "node-info: failed error" %)}]})
|
|
||||||
|
|
||||||
(defn add-mailservers
|
|
||||||
[db mailservers]
|
|
||||||
(reduce (fn [db {:keys [fleet id name] :as mailserver}]
|
|
||||||
(let [updated-mailserver
|
|
||||||
(-> mailserver
|
|
||||||
(update :id keyword)
|
|
||||||
(assoc :name (if (seq name) name id))
|
|
||||||
(dissoc :fleet))]
|
|
||||||
(assoc-in db
|
|
||||||
[:mailserver/mailservers (keyword fleet) (keyword id)]
|
|
||||||
updated-mailserver)))
|
|
||||||
db
|
|
||||||
mailservers))
|
|
||||||
|
|
||||||
(rf/defn start-messenger
|
|
||||||
"We should only start receiving messages/processing topics once all the
|
|
||||||
initializiation is completed, otherwise we might receive messages/topics
|
|
||||||
when the state has not been properly initialized."
|
|
||||||
[_]
|
|
||||||
{:json-rpc/call [{:method "wakuext_startMessenger"
|
|
||||||
:on-success #(re-frame/dispatch [::messenger-started %])
|
|
||||||
:on-error #(log/error "failed to start messenger")}]})
|
|
||||||
|
|
||||||
(rf/defn messenger-started
|
|
||||||
{:events [::messenger-started]}
|
|
||||||
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
|
||||||
(log/info "Messenger started")
|
|
||||||
(let [new-account? (get db :onboarding/new-account?)]
|
|
||||||
(rf/merge cofx
|
|
||||||
{:db (-> db
|
|
||||||
(assoc :messenger/started? true)
|
|
||||||
(add-mailservers mailservers))}
|
|
||||||
(fetch-node-info-fx)
|
|
||||||
(pairing/init)
|
|
||||||
(stickers/load-packs)
|
|
||||||
(when-not new-account?
|
|
||||||
(universal-links/process-stored-event)))))
|
|
|
@ -1,59 +0,0 @@
|
||||||
(ns ^{:doc "Protocol API and protocol utils"} status-im.transport.message.protocol
|
|
||||||
(:require
|
|
||||||
[clojure.set :as set]
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[taoensso.timbre :as log]
|
|
||||||
[utils.re-frame :as rf]))
|
|
||||||
|
|
||||||
(defn- link-preview->rpc
|
|
||||||
[preview]
|
|
||||||
(update preview
|
|
||||||
:thumbnail
|
|
||||||
(fn [thumbnail]
|
|
||||||
(set/rename-keys thumbnail {:data-uri :dataUri}))))
|
|
||||||
|
|
||||||
(defn build-message
|
|
||||||
[msg]
|
|
||||||
(-> msg
|
|
||||||
(update :link-previews #(map link-preview->rpc %))
|
|
||||||
(set/rename-keys
|
|
||||||
{:album-id :albumId
|
|
||||||
:audio-duration-ms :audioDurationMs
|
|
||||||
:audio-path :audioPath
|
|
||||||
:chat-id :chatId
|
|
||||||
:community-id :communityId
|
|
||||||
:content-type :contentType
|
|
||||||
:ens-name :ensName
|
|
||||||
:image-height :imageHeight
|
|
||||||
:image-path :imagePath
|
|
||||||
:image-width :imageWidth
|
|
||||||
:link-previews :linkPreviews
|
|
||||||
:response-to :responseTo
|
|
||||||
:sticker :sticker
|
|
||||||
:text :text})))
|
|
||||||
|
|
||||||
(rf/defn send-chat-messages
|
|
||||||
[_ messages]
|
|
||||||
{:json-rpc/call [{:method "wakuext_sendChatMessages"
|
|
||||||
:params [(mapv build-message messages)]
|
|
||||||
:js-response true
|
|
||||||
:on-success #(re-frame/dispatch [:transport/message-sent %])
|
|
||||||
:on-error #(do
|
|
||||||
(log/warn "failed to send a message" %)
|
|
||||||
(js/alert (str "failed to send a message: " %)))}]})
|
|
||||||
|
|
||||||
(rf/defn send-reaction
|
|
||||||
[_ {:keys [message-id chat-id emoji-id]}]
|
|
||||||
{:json-rpc/call [{:method "wakuext_sendEmojiReaction"
|
|
||||||
:params [chat-id message-id emoji-id]
|
|
||||||
:js-response true
|
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
|
||||||
:on-error #(log/error "failed to send a reaction" %)}]})
|
|
||||||
|
|
||||||
(rf/defn send-retract-reaction
|
|
||||||
[_ {:keys [emoji-reaction-id]}]
|
|
||||||
{:json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction"
|
|
||||||
:params [emoji-reaction-id]
|
|
||||||
:js-response true
|
|
||||||
:on-success #(re-frame/dispatch [:sanitize-messages-and-process-response %])
|
|
||||||
:on-error #(log/error "failed to send a reaction retraction" %)}]})
|
|
|
@ -1,35 +0,0 @@
|
||||||
(ns ^{:doc "Whisper API and events for managing keys and posting messages"} status-im.transport.shh
|
|
||||||
(:require
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im2.common.json-rpc.events :as json-rpc]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defn generate-sym-key-from-password
|
|
||||||
[{:keys [password on-success on-error]}]
|
|
||||||
(json-rpc/call {:method "waku_generateSymKeyFromPassword"
|
|
||||||
:params [password]
|
|
||||||
:on-success on-success
|
|
||||||
:on-error on-error}))
|
|
||||||
|
|
||||||
(defn get-sym-key
|
|
||||||
[{:keys [sym-key-id on-success on-error]}]
|
|
||||||
(json-rpc/call {:method "waku_getSymKey"
|
|
||||||
:params [sym-key-id]
|
|
||||||
:on-success on-success
|
|
||||||
:on-error on-error}))
|
|
||||||
|
|
||||||
(defn log-error
|
|
||||||
[error]
|
|
||||||
(log/error :shh/get-new-sym-key-error error))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:shh/generate-sym-key-from-password
|
|
||||||
(fn [{:keys [password on-success]}]
|
|
||||||
(generate-sym-key-from-password
|
|
||||||
{:password password
|
|
||||||
:on-success (fn [sym-key-id]
|
|
||||||
(get-sym-key {:sym-key-id sym-key-id
|
|
||||||
:on-success (fn [sym-key]
|
|
||||||
(on-success sym-key sym-key-id))
|
|
||||||
:on-error log-error}))
|
|
||||||
:on-error log-error})))
|
|
|
@ -1,18 +0,0 @@
|
||||||
(ns ^{:doc "Utils for transport layer"} status-im.transport.utils
|
|
||||||
(:require
|
|
||||||
[clojure.string :as string]))
|
|
||||||
|
|
||||||
(defn extract-enode-id
|
|
||||||
[enode]
|
|
||||||
(-> enode
|
|
||||||
(string/split #"/")
|
|
||||||
(get 2 "")
|
|
||||||
(string/split #":")
|
|
||||||
(get 0 "")
|
|
||||||
(string/split "@")
|
|
||||||
(get 0)))
|
|
||||||
|
|
||||||
(defn extract-url-components
|
|
||||||
[address]
|
|
||||||
(when address
|
|
||||||
(rest (re-matches #"enode://(.*?)@(.*):(.*)" address))))
|
|
|
@ -7,7 +7,6 @@
|
||||||
[react-native.mail :as react-native-mail]
|
[react-native.mail :as react-native-mail]
|
||||||
[react-native.platform :as platform]
|
[react-native.platform :as platform]
|
||||||
[status-im.bottom-sheet.events :as bottom-sheet]
|
[status-im.bottom-sheet.events :as bottom-sheet]
|
||||||
[status-im.transport.utils :as transport.utils]
|
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.utils.build :as build]
|
[status-im.utils.build :as build]
|
||||||
[status-im.utils.deprecated-types :as types]
|
[status-im.utils.deprecated-types :as types]
|
||||||
|
@ -38,6 +37,11 @@
|
||||||
{:json-rpc/call [{:method "web3_clientVersion"
|
{:json-rpc/call [{:method "web3_clientVersion"
|
||||||
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
|
:on-success #(re-frame/dispatch [:logging/store-web3-client-version %])}]})
|
||||||
|
|
||||||
|
(defn extract-url-components
|
||||||
|
[address]
|
||||||
|
(when address
|
||||||
|
(rest (re-matches #"enode://(.*?)@(.*):(.*)" address))))
|
||||||
|
|
||||||
(defn email-body
|
(defn email-body
|
||||||
"logs attached"
|
"logs attached"
|
||||||
[{:keys [:web3-node-version :mailserver/current-id
|
[{:keys [:web3-node-version :mailserver/current-id
|
||||||
|
@ -46,7 +50,7 @@
|
||||||
build-version (str build/version " (" build-number ")")
|
build-version (str build/version " (" build-number ")")
|
||||||
separator (string/join (take 40 (repeat "-")))
|
separator (string/join (take 40 (repeat "-")))
|
||||||
[enode-id ip-address port]
|
[enode-id ip-address port]
|
||||||
(transport.utils/extract-url-components (:enode node-info))]
|
(extract-url-components (:enode node-info))]
|
||||||
(string/join
|
(string/join
|
||||||
"\n"
|
"\n"
|
||||||
(concat [(i18n/label :t/report-bug-email-template
|
(concat [(i18n/label :t/report-bug-email-template
|
||||||
|
@ -68,7 +72,7 @@
|
||||||
(mapcat
|
(mapcat
|
||||||
(fn [{:keys [enode]}]
|
(fn [{:keys [enode]}]
|
||||||
(let [[enode-id ip-address port]
|
(let [[enode-id ip-address port]
|
||||||
(transport.utils/extract-url-components enode)]
|
(extract-url-components enode)]
|
||||||
[(str "id: " enode-id)
|
[(str "id: " enode-id)
|
||||||
(str "ip: " ip-address)
|
(str "ip: " ip-address)
|
||||||
(str "port: " port)
|
(str "port: " port)
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
(ns status-im2.common.pairing.events
|
||||||
|
(:require
|
||||||
|
[quo.foundations.colors :as colors]
|
||||||
|
[status-im2.constants :as constants]
|
||||||
|
[status-im2.contexts.communities.discover.events]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
|
(rf/defn handle-local-pairing-signals
|
||||||
|
[{:keys [db]} {:keys [type action data error] :as event}]
|
||||||
|
(log/info "local pairing signal received"
|
||||||
|
{:event event})
|
||||||
|
(let [{:keys [account password]} data
|
||||||
|
role (get-in db [:syncing :role])
|
||||||
|
receiver? (= role constants/local-pairing-role-receiver)
|
||||||
|
sender? (= role constants/local-pairing-role-sender)
|
||||||
|
connection-success? (and (= type
|
||||||
|
constants/local-pairing-event-connection-success)
|
||||||
|
(= action
|
||||||
|
constants/local-pairing-action-connect))
|
||||||
|
error-on-pairing? (contains? constants/local-pairing-event-errors type)
|
||||||
|
completed-pairing? (and (= type
|
||||||
|
constants/local-pairing-event-transfer-success)
|
||||||
|
(= action
|
||||||
|
constants/local-pairing-action-pairing-installation))
|
||||||
|
received-account? (and (= type
|
||||||
|
constants/local-pairing-event-received-account)
|
||||||
|
(= action
|
||||||
|
constants/local-pairing-action-pairing-account)
|
||||||
|
(and (some? account) (some? password)))
|
||||||
|
multiaccount-data (when received-account?
|
||||||
|
(merge account {:password password}))
|
||||||
|
navigate-to-syncing-devices? (and (or connection-success? error-on-pairing?) receiver?)
|
||||||
|
user-in-syncing-devices-screen? (or (= (:view-id db) :syncing-progress)
|
||||||
|
(= (:view-id db) :syncing-progress-intro))
|
||||||
|
user-in-sign-in-intro-screen? (= (:view-id db) :sign-in-intro)]
|
||||||
|
(merge {:db (cond-> db
|
||||||
|
connection-success?
|
||||||
|
(assoc-in [:syncing :pairing-status] :connected)
|
||||||
|
|
||||||
|
received-account?
|
||||||
|
(assoc-in [:syncing :profile] multiaccount-data)
|
||||||
|
|
||||||
|
error-on-pairing?
|
||||||
|
(assoc-in [:syncing :pairing-status] :error)
|
||||||
|
|
||||||
|
completed-pairing?
|
||||||
|
(assoc-in [:syncing :pairing-status] :completed))}
|
||||||
|
(cond
|
||||||
|
(and navigate-to-syncing-devices? (not user-in-syncing-devices-screen?))
|
||||||
|
{:dispatch (if user-in-sign-in-intro-screen?
|
||||||
|
[:navigate-to-within-stack [:syncing-progress-intro :sign-in-intro]]
|
||||||
|
[:navigate-to :syncing-progress])}
|
||||||
|
|
||||||
|
(and completed-pairing? sender?)
|
||||||
|
{:dispatch [:syncing/clear-states]}
|
||||||
|
|
||||||
|
(and completed-pairing? receiver?)
|
||||||
|
{:dispatch [:profile.login/local-paired-user]}
|
||||||
|
|
||||||
|
(and error-on-pairing? (some? error))
|
||||||
|
{:dispatch [:toasts/upsert
|
||||||
|
{:icon :i/alert
|
||||||
|
:icon-color colors/danger-50
|
||||||
|
:text error}]}))))
|
|
@ -1,13 +1,12 @@
|
||||||
(ns status-im.signals.core
|
(ns status-im2.common.signals.events
|
||||||
(:require
|
(:require
|
||||||
[quo.foundations.colors :as colors]
|
|
||||||
[status-im.chat.models.message :as models.message]
|
[status-im.chat.models.message :as models.message]
|
||||||
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
|
[status-im.ethereum.subscriptions :as ethereum.subscriptions]
|
||||||
[status-im.mailserver.core :as mailserver]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.transport.message.core :as transport.message]
|
|
||||||
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
[status-im.visibility-status-updates.core :as visibility-status-updates]
|
||||||
[status-im2.constants :as constants]
|
[status-im2.common.pairing.events :as pairing]
|
||||||
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
||||||
|
[status-im2.contexts.chat.messages.transport.events :as messages.transport]
|
||||||
[status-im2.contexts.communities.discover.events]
|
[status-im2.contexts.communities.discover.events]
|
||||||
[status-im2.contexts.profile.login.events :as profile.login]
|
[status-im2.contexts.profile.login.events :as profile.login]
|
||||||
[status-im2.contexts.push-notifications.local.events :as local-notifications]
|
[status-im2.contexts.push-notifications.local.events :as local-notifications]
|
||||||
|
@ -29,64 +28,6 @@
|
||||||
[{:keys [db]} peer-stats]
|
[{:keys [db]} peer-stats]
|
||||||
{:db (assoc db :peer-stats peer-stats :peers-count (count (:peers peer-stats)))})
|
{:db (assoc db :peer-stats peer-stats :peers-count (count (:peers peer-stats)))})
|
||||||
|
|
||||||
(rf/defn handle-local-pairing-signals
|
|
||||||
[{:keys [db]} {:keys [type action data error] :as event}]
|
|
||||||
(log/info "local pairing signal received"
|
|
||||||
{:event event})
|
|
||||||
(let [{:keys [account password]} data
|
|
||||||
role (get-in db [:syncing :role])
|
|
||||||
receiver? (= role constants/local-pairing-role-receiver)
|
|
||||||
sender? (= role constants/local-pairing-role-sender)
|
|
||||||
connection-success? (and (= type
|
|
||||||
constants/local-pairing-event-connection-success)
|
|
||||||
(= action
|
|
||||||
constants/local-pairing-action-connect))
|
|
||||||
error-on-pairing? (contains? constants/local-pairing-event-errors type)
|
|
||||||
completed-pairing? (and (= type
|
|
||||||
constants/local-pairing-event-transfer-success)
|
|
||||||
(= action
|
|
||||||
constants/local-pairing-action-pairing-installation))
|
|
||||||
received-account? (and (= type
|
|
||||||
constants/local-pairing-event-received-account)
|
|
||||||
(= action
|
|
||||||
constants/local-pairing-action-pairing-account)
|
|
||||||
(and (some? account) (some? password)))
|
|
||||||
multiaccount-data (when received-account?
|
|
||||||
(merge account {:password password}))
|
|
||||||
navigate-to-syncing-devices? (and (or connection-success? error-on-pairing?) receiver?)
|
|
||||||
user-in-syncing-devices-screen? (or (= (:view-id db) :syncing-progress)
|
|
||||||
(= (:view-id db) :syncing-progress-intro))
|
|
||||||
user-in-sign-in-intro-screen? (= (:view-id db) :sign-in-intro)]
|
|
||||||
(merge {:db (cond-> db
|
|
||||||
connection-success?
|
|
||||||
(assoc-in [:syncing :pairing-status] :connected)
|
|
||||||
|
|
||||||
received-account?
|
|
||||||
(assoc-in [:syncing :profile] multiaccount-data)
|
|
||||||
|
|
||||||
error-on-pairing?
|
|
||||||
(assoc-in [:syncing :pairing-status] :error)
|
|
||||||
|
|
||||||
completed-pairing?
|
|
||||||
(assoc-in [:syncing :pairing-status] :completed))}
|
|
||||||
(cond
|
|
||||||
(and navigate-to-syncing-devices? (not user-in-syncing-devices-screen?))
|
|
||||||
{:dispatch (if user-in-sign-in-intro-screen?
|
|
||||||
[:navigate-to-within-stack [:syncing-progress-intro :sign-in-intro]]
|
|
||||||
[:navigate-to :syncing-progress])}
|
|
||||||
|
|
||||||
(and completed-pairing? sender?)
|
|
||||||
{:dispatch [:syncing/clear-states]}
|
|
||||||
|
|
||||||
(and completed-pairing? receiver?)
|
|
||||||
{:dispatch [:profile.login/local-paired-user]}
|
|
||||||
|
|
||||||
(and error-on-pairing? (some? error))
|
|
||||||
{:dispatch [:toasts/upsert
|
|
||||||
{:icon :i/alert
|
|
||||||
:icon-color colors/danger-50
|
|
||||||
:text error}]}))))
|
|
||||||
|
|
||||||
(rf/defn process
|
(rf/defn process
|
||||||
{:events [:signals/signal-received]}
|
{:events [:signals/signal-received]}
|
||||||
[{:keys [db] :as cofx} event-str]
|
[{:keys [db] :as cofx} event-str]
|
||||||
|
@ -101,18 +42,18 @@
|
||||||
"backup.performed" {:db (assoc-in db
|
"backup.performed" {:db (assoc-in db
|
||||||
[:profile/profile :last-backup]
|
[:profile/profile :last-backup]
|
||||||
(.-lastBackup event-js))}
|
(.-lastBackup event-js))}
|
||||||
"envelope.sent" (transport.message/update-envelopes-status cofx
|
"envelope.sent" (messages.transport/update-envelopes-status cofx
|
||||||
(:ids
|
(:ids
|
||||||
(js->clj event-js
|
(js->clj event-js
|
||||||
:keywordize-keys
|
:keywordize-keys
|
||||||
true))
|
true))
|
||||||
:sent)
|
:sent)
|
||||||
"envelope.expired" (transport.message/update-envelopes-status cofx
|
"envelope.expired" (messages.transport/update-envelopes-status cofx
|
||||||
(:ids
|
(:ids
|
||||||
(js->clj event-js
|
(js->clj event-js
|
||||||
:keywordize-keys
|
:keywordize-keys
|
||||||
true))
|
true))
|
||||||
:not-sent)
|
:not-sent)
|
||||||
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js
|
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js
|
||||||
:keywordize-keys
|
:keywordize-keys
|
||||||
true)]
|
true)]
|
||||||
|
@ -126,9 +67,9 @@
|
||||||
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
||||||
"mediaserver.started" {:db (assoc db :mediaserver/port (.-port event-js))}
|
"mediaserver.started" {:db (assoc db :mediaserver/port (.-port event-js))}
|
||||||
"wakuv2.peerstats" (wakuv2-peer-stats cofx (js->clj event-js :keywordize-keys true))
|
"wakuv2.peerstats" (wakuv2-peer-stats cofx (js->clj event-js :keywordize-keys true))
|
||||||
"messages.new" (transport.message/sanitize-messages-and-process-response cofx
|
"messages.new" (messages.transport/sanitize-messages-and-process-response cofx
|
||||||
event-js
|
event-js
|
||||||
true)
|
true)
|
||||||
"wallet" (ethereum.subscriptions/new-wallet-event cofx
|
"wallet" (ethereum.subscriptions/new-wallet-event cofx
|
||||||
(js->clj event-js
|
(js->clj event-js
|
||||||
:keywordize-keys
|
:keywordize-keys
|
||||||
|
@ -141,7 +82,7 @@
|
||||||
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
|
"status.updates.timedout" (visibility-status-updates/handle-visibility-status-updates
|
||||||
cofx
|
cofx
|
||||||
(js->clj event-js :keywordize-keys true))
|
(js->clj event-js :keywordize-keys true))
|
||||||
"localPairing" (handle-local-pairing-signals
|
"localPairing" (pairing/handle-local-pairing-signals
|
||||||
cofx
|
cofx
|
||||||
(js->clj event-js :keywordize-keys true))
|
(js->clj event-js :keywordize-keys true))
|
||||||
"curated.communities.update" (rf/dispatch [:fetched-contract-communities
|
"curated.communities.update" (rf/dispatch [:fetched-contract-communities
|
|
@ -9,11 +9,8 @@
|
||||||
(defn- on-press
|
(defn- on-press
|
||||||
[{:keys [own message-id emoji-id emoji-reaction-id]}]
|
[{:keys [own message-id emoji-id emoji-reaction-id]}]
|
||||||
(if own
|
(if own
|
||||||
(rf/dispatch [:models.reactions/send-emoji-reaction-retraction
|
(rf/dispatch [:reactions/send-emoji-reaction-retraction emoji-reaction-id])
|
||||||
{:message-id message-id
|
(rf/dispatch [:reactions/send-emoji-reaction
|
||||||
:emoji-id emoji-id
|
|
||||||
:emoji-reaction-id emoji-reaction-id}])
|
|
||||||
(rf/dispatch [:models.reactions/send-emoji-reaction
|
|
||||||
{:message-id message-id
|
{:message-id message-id
|
||||||
:emoji-id emoji-id}])))
|
:emoji-id emoji-id}])))
|
||||||
|
|
||||||
|
|
|
@ -192,11 +192,8 @@
|
||||||
:on-press
|
:on-press
|
||||||
(fn []
|
(fn []
|
||||||
(if emoji-reaction-id
|
(if emoji-reaction-id
|
||||||
(rf/dispatch [:models.reactions/send-emoji-reaction-retraction
|
(rf/dispatch [:reactions/send-emoji-reaction-retraction emoji-reaction-id])
|
||||||
{:message-id message-id
|
(rf/dispatch [:reactions/send-emoji-reaction
|
||||||
:emoji-id id
|
|
||||||
:emoji-reaction-id emoji-reaction-id}])
|
|
||||||
(rf/dispatch [:models.reactions/send-emoji-reaction
|
|
||||||
{:message-id message-id
|
{:message-id message-id
|
||||||
:emoji-id id}]))
|
:emoji-id id}]))
|
||||||
(rf/dispatch [:hide-bottom-sheet]))}])]))
|
(rf/dispatch [:hide-bottom-sheet]))}])]))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(ns ^{:doc "Definition of the StatusMessage protocol"} status-im.transport.message.core
|
(ns status-im2.contexts.chat.messages.transport.events
|
||||||
(:require
|
(:require
|
||||||
|
[clojure.set :as set]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[status-im.browser.core :as browser]
|
[status-im.browser.core :as browser]
|
||||||
[status-im.chat.models.message :as models.message]
|
[status-im.chat.models.message :as models.message]
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
[status-im2.contexts.chat.messages.pin.events :as messages.pin]
|
[status-im2.contexts.chat.messages.pin.events :as messages.pin]
|
||||||
[status-im2.contexts.contacts.events :as models.contact]
|
[status-im2.contexts.contacts.events :as models.contact]
|
||||||
[status-im2.contexts.shell.activity-center.events :as activity-center]
|
[status-im2.contexts.shell.activity-center.events :as activity-center]
|
||||||
|
[taoensso.timbre :as log]
|
||||||
[utils.re-frame :as rf]))
|
[utils.re-frame :as rf]))
|
||||||
|
|
||||||
(rf/defn process-next
|
(rf/defn process-next
|
||||||
|
@ -347,3 +349,58 @@
|
||||||
cofx
|
cofx
|
||||||
(conj set-hash-fxs
|
(conj set-hash-fxs
|
||||||
#(sanitize-messages-and-process-response % response-js false)))))
|
#(sanitize-messages-and-process-response % response-js false)))))
|
||||||
|
|
||||||
|
(defn- link-preview->rpc
|
||||||
|
[preview]
|
||||||
|
(update preview
|
||||||
|
:thumbnail
|
||||||
|
(fn [thumbnail]
|
||||||
|
(set/rename-keys thumbnail {:data-uri :dataUri}))))
|
||||||
|
|
||||||
|
(defn build-message
|
||||||
|
[msg]
|
||||||
|
(-> msg
|
||||||
|
(update :link-previews #(map link-preview->rpc %))
|
||||||
|
(set/rename-keys
|
||||||
|
{:album-id :albumId
|
||||||
|
:audio-duration-ms :audioDurationMs
|
||||||
|
:audio-path :audioPath
|
||||||
|
:chat-id :chatId
|
||||||
|
:community-id :communityId
|
||||||
|
:content-type :contentType
|
||||||
|
:ens-name :ensName
|
||||||
|
:image-height :imageHeight
|
||||||
|
:image-path :imagePath
|
||||||
|
:image-width :imageWidth
|
||||||
|
:link-previews :linkPreviews
|
||||||
|
:response-to :responseTo
|
||||||
|
:sticker :sticker
|
||||||
|
:text :text})))
|
||||||
|
|
||||||
|
(rf/defn send-chat-messages
|
||||||
|
[_ messages]
|
||||||
|
{:json-rpc/call [{:method "wakuext_sendChatMessages"
|
||||||
|
:params [(mapv build-message messages)]
|
||||||
|
:js-response true
|
||||||
|
:on-success #(rf/dispatch [:transport/message-sent %])
|
||||||
|
:on-error #(do
|
||||||
|
(log/warn "failed to send a message" %)
|
||||||
|
(js/alert (str "failed to send a message: " %)))}]})
|
||||||
|
|
||||||
|
(rf/defn send-emoji-reaction
|
||||||
|
{:events [:reactions/send-emoji-reaction]}
|
||||||
|
[{{:keys [current-chat-id]} :db} {:keys [message-id emoji-id]}]
|
||||||
|
{:json-rpc/call [{:method "wakuext_sendEmojiReaction"
|
||||||
|
:params [current-chat-id message-id emoji-id]
|
||||||
|
:js-response true
|
||||||
|
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
|
||||||
|
:on-error #(log/error "failed to send a reaction" %)}]})
|
||||||
|
|
||||||
|
(rf/defn send-retract-emoji-reaction
|
||||||
|
{:events [:reactions/send-emoji-reaction-retraction]}
|
||||||
|
[_ emoji-reaction-id]
|
||||||
|
{:json-rpc/call [{:method "wakuext_sendEmojiReactionRetraction"
|
||||||
|
:params [emoji-reaction-id]
|
||||||
|
:js-response true
|
||||||
|
:on-success #(rf/dispatch [:sanitize-messages-and-process-response %])
|
||||||
|
:on-error #(log/error "failed to send a reaction retraction" %)}]})
|
|
@ -9,10 +9,13 @@
|
||||||
[status-im.data-store.switcher-cards :as switcher-cards-store]
|
[status-im.data-store.switcher-cards :as switcher-cards-store]
|
||||||
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
|
[status-im.data-store.visibility-status-updates :as visibility-status-updates-store]
|
||||||
[status-im.group-chats.core :as group-chats]
|
[status-im.group-chats.core :as group-chats]
|
||||||
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.mobile-sync-settings.core :as mobile-network]
|
[status-im.mobile-sync-settings.core :as mobile-network]
|
||||||
[status-im.transport.core :as transport]
|
[status-im.pairing.core :as pairing]
|
||||||
|
[status-im.stickers.core :as stickers]
|
||||||
[status-im2.common.keychain.events :as keychain]
|
[status-im2.common.keychain.events :as keychain]
|
||||||
[status-im2.common.log :as logging]
|
[status-im2.common.log :as logging]
|
||||||
|
[status-im2.common.universal-links :as universal-links]
|
||||||
[status-im2.config :as config]
|
[status-im2.config :as config]
|
||||||
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
[status-im2.contexts.chat.messages.link-preview.events :as link-preview]
|
||||||
[status-im2.contexts.contacts.events :as contacts]
|
[status-im2.contexts.contacts.events :as contacts]
|
||||||
|
@ -110,7 +113,10 @@
|
||||||
network-id (str (get-in networks
|
network-id (str (get-in networks
|
||||||
[current-network :config :NetworkId]))]
|
[current-network :config :NetworkId]))]
|
||||||
(rf/merge cofx
|
(rf/merge cofx
|
||||||
(cond-> {:wallet-legacy/initialize-transactions-management-enabled nil
|
(cond-> {:json-rpc/call [{:method "wakuext_startMessenger"
|
||||||
|
:on-success #(re-frame/dispatch [:messenger-started %])
|
||||||
|
:on-error #(log/error "failed to start messenger")}]
|
||||||
|
:wallet-legacy/initialize-transactions-management-enabled nil
|
||||||
:wallet-legacy/initialize-wallet
|
:wallet-legacy/initialize-wallet
|
||||||
[network-id
|
[network-id
|
||||||
current-network-config
|
current-network-config
|
||||||
|
@ -122,7 +128,6 @@
|
||||||
(assoc :chat/open-last-chat (get-in db [:profile/profile :key-uid]))
|
(assoc :chat/open-last-chat (get-in db [:profile/profile :key-uid]))
|
||||||
notifications-enabled?
|
notifications-enabled?
|
||||||
(assoc :effects/push-notifications-enable nil))
|
(assoc :effects/push-notifications-enable nil))
|
||||||
(transport/start-messenger)
|
|
||||||
(contacts/initialize-contacts)
|
(contacts/initialize-contacts)
|
||||||
(browser/initialize-browser)
|
(browser/initialize-browser)
|
||||||
(mobile-network/on-network-status-change)
|
(mobile-network/on-network-status-change)
|
||||||
|
@ -133,6 +138,28 @@
|
||||||
(visibility-status-updates-store/fetch-visibility-status-updates-rpc)
|
(visibility-status-updates-store/fetch-visibility-status-updates-rpc)
|
||||||
(switcher-cards-store/fetch-switcher-cards-rpc))))
|
(switcher-cards-store/fetch-switcher-cards-rpc))))
|
||||||
|
|
||||||
|
(rf/defn messenger-started
|
||||||
|
{:events [:messenger-started]}
|
||||||
|
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
||||||
|
(log/info "Messenger started")
|
||||||
|
(let [new-account? (get db :onboarding-2/new-account?)]
|
||||||
|
(rf/merge cofx
|
||||||
|
{:db (-> db
|
||||||
|
(assoc :messenger/started? true)
|
||||||
|
(mailserver/add-mailservers mailservers))
|
||||||
|
:json-rpc/call [{:method "admin_nodeInfo"
|
||||||
|
:on-success #(re-frame/dispatch [:node-info-fetched %])
|
||||||
|
:on-error #(log/error "node-info: failed error" %)}]}
|
||||||
|
(pairing/init)
|
||||||
|
(stickers/load-packs)
|
||||||
|
(when-not new-account?
|
||||||
|
(universal-links/process-stored-event)))))
|
||||||
|
|
||||||
|
(rf/defn set-node-info
|
||||||
|
{:events [:node-info-fetched]}
|
||||||
|
[{:keys [db]} node-info]
|
||||||
|
{:db (assoc db :node-info node-info)})
|
||||||
|
|
||||||
(rf/defn login-node-signal
|
(rf/defn login-node-signal
|
||||||
[{{:onboarding/keys [recovered-account? new-account?] :as db} :db :as cofx}
|
[{{:onboarding/keys [recovered-account? new-account?] :as db} :db :as cofx}
|
||||||
{:keys [settings account ensUsernames error]}]
|
{:keys [settings account ensUsernames error]}]
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
(:require
|
(:require
|
||||||
;; NOTE: Do NOT sort i18n-resources because it MUST be loaded first.
|
;; NOTE: Do NOT sort i18n-resources because it MUST be loaded first.
|
||||||
[status-im2.setup.i18n-resources :as i18n-resources]
|
[status-im2.setup.i18n-resources :as i18n-resources]
|
||||||
|
|
||||||
#_{:clj-kondo/ignore [:unsorted-required-namespaces]}
|
#_{:clj-kondo/ignore [:unsorted-required-namespaces]}
|
||||||
[native-module.core :as native-module]
|
[native-module.core :as native-module]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
status-im2.common.font.events
|
status-im2.common.font.events
|
||||||
[status-im2.common.json-rpc.events]
|
[status-im2.common.json-rpc.events]
|
||||||
status-im2.common.password-authentication.events
|
status-im2.common.password-authentication.events
|
||||||
|
status-im2.common.signals.events
|
||||||
status-im2.common.theme.events
|
status-im2.common.theme.events
|
||||||
[status-im2.common.toasts.events]
|
[status-im2.common.toasts.events]
|
||||||
[status-im2.contexts.add-new-contact.events]
|
[status-im2.contexts.add-new-contact.events]
|
||||||
|
|
|
@ -19,6 +19,6 @@
|
||||||
(do ~@body)
|
(do ~@body)
|
||||||
(do
|
(do
|
||||||
(test-helpers.integration/create-multiaccount!)
|
(test-helpers.integration/create-multiaccount!)
|
||||||
(rf-test/wait-for [:status-im.transport.core/messenger-started]
|
(rf-test/wait-for [:messenger-started]
|
||||||
(test-helpers.integration/assert-messenger-started)
|
(test-helpers.integration/assert-messenger-started)
|
||||||
~@body))))
|
~@body))))
|
||||||
|
|
Loading…
Reference in New Issue