mirror of
https://github.com/status-im/status-mobile.git
synced 2025-02-26 15:21:08 +00:00
Move mailserver logic/gaps/ranges to status-go
This commit moves most of the mailserver logic to status-go. - Filters are now removed and not passed to the client anymore - Ranges have been removed - Gaps are now messages with a different content type - Upsert/Save chat has been removed and instead we have more specific endpoints such as CreatePublicChat/CreateOneToOneChat/CreateProfileChat - Creation of timeline/profile chat has been moved to status-go Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
929925af39
commit
dd5c30b7a0
@ -1,6 +1,5 @@
|
|||||||
(ns status-im.chat.db
|
(ns status-im.chat.db
|
||||||
(:require [clojure.string :as clojure.string]
|
(:require [status-im.constants :as constants]))
|
||||||
[status-im.mailserver.constants :as mailserver.constants]))
|
|
||||||
|
|
||||||
(defn group-chat-name
|
(defn group-chat-name
|
||||||
[{:keys [public? name]}]
|
[{:keys [public? name]}]
|
||||||
@ -48,89 +47,42 @@
|
|||||||
(conj messages-with-datemarks {:value (:datemark (peek messages-with-datemarks))
|
(conj messages-with-datemarks {:value (:datemark (peek messages-with-datemarks))
|
||||||
:type :datemark}))))
|
:type :datemark}))))
|
||||||
|
|
||||||
(defn gap? [{:keys [type]}]
|
(defn last-gap
|
||||||
(= type :gap))
|
"last-gap is a special gap that is put last in the message stream"
|
||||||
|
[chat-id synced-from]
|
||||||
|
{:message-id "0x123"
|
||||||
|
:message-type constants/message-type-gap
|
||||||
|
:chat-id chat-id
|
||||||
|
:content-type constants/content-type-gap
|
||||||
|
:gap-ids #{:first-gap}
|
||||||
|
:gap-parameters {:from synced-from}})
|
||||||
|
|
||||||
(defn check-gap
|
(defn collapse-gaps
|
||||||
[gaps previous-message next-message]
|
"collapse-gaps will take an array of messages and collapse any gap next to
|
||||||
(let [previous-timestamp (:whisper-timestamp previous-message)
|
each other in a single gap.
|
||||||
next-whisper-timestamp (:whisper-timestamp next-message)
|
It will also append one last gap if the last message is a non-gap"
|
||||||
next-timestamp (:timestamp next-message)
|
[messages chat-id synced-from]
|
||||||
ignore-next-message? (> (js/Math.abs
|
(let [messages-with-gaps (reduce
|
||||||
(- next-whisper-timestamp next-timestamp))
|
(fn [acc {:keys [gap-parameters message-id] :as message}]
|
||||||
120000)]
|
(let [last-element (peek acc)]
|
||||||
(reduce
|
(cond
|
||||||
(fn [acc {:keys [from to id]}]
|
;; If it's a message, just add
|
||||||
(let [from-ms (* from 1000)
|
(empty? gap-parameters)
|
||||||
to-ms (* to 1000)]
|
(conj acc message)
|
||||||
(if (and next-message
|
|
||||||
(not ignore-next-message?)
|
;; Both are gaps, merge them
|
||||||
(or
|
|
||||||
(and (nil? previous-timestamp)
|
|
||||||
(< from-ms next-whisper-timestamp))
|
|
||||||
(and
|
(and
|
||||||
(< previous-timestamp from-ms)
|
(seq (:gap-parameters last-element))
|
||||||
(< to-ms next-whisper-timestamp))
|
(seq gap-parameters))
|
||||||
(and
|
(conj (pop acc) (update last-element :gap-ids conj message-id))
|
||||||
(< from-ms previous-timestamp)
|
|
||||||
(< to-ms next-whisper-timestamp))))
|
|
||||||
(-> acc
|
|
||||||
(update :gaps-number inc)
|
|
||||||
(update-in [:gap :ids] conj id))
|
|
||||||
(reduced acc))))
|
|
||||||
{:gaps-number 0
|
|
||||||
:gap nil}
|
|
||||||
gaps)))
|
|
||||||
|
|
||||||
(defn add-gap [messages gaps]
|
;; it's a gap
|
||||||
(conj messages
|
:else
|
||||||
{:type :gap
|
(conj acc (assoc message :gap-ids #{message-id})))))
|
||||||
:value (clojure.string/join (:ids gaps))
|
[]
|
||||||
:gaps gaps}))
|
messages)]
|
||||||
|
;; If it's a gap or the chat is still syncing, do nothing
|
||||||
(defn add-gaps
|
(if (or (nil? synced-from)
|
||||||
"Converts message groups into sequence of messages interspersed with datemarks,
|
(:gap-ids (peek messages-with-gaps)))
|
||||||
with correct user statuses associated into message"
|
messages-with-gaps
|
||||||
[message-list messages-gaps
|
(conj messages-with-gaps (last-gap chat-id synced-from)))))
|
||||||
{:keys [highest-request-to lowest-request-from]} all-loaded? public?]
|
|
||||||
(transduce
|
|
||||||
(map identity)
|
|
||||||
(fn
|
|
||||||
([]
|
|
||||||
(let [acc {:messages (list)
|
|
||||||
:previous-message nil
|
|
||||||
:gaps messages-gaps}]
|
|
||||||
(if (and
|
|
||||||
public?
|
|
||||||
all-loaded?
|
|
||||||
(not (nil? highest-request-to))
|
|
||||||
(not (nil? lowest-request-from))
|
|
||||||
(< (- highest-request-to lowest-request-from)
|
|
||||||
mailserver.constants/max-gaps-range))
|
|
||||||
(update acc :messages conj {:type :gap
|
|
||||||
:value (str :first-gap)
|
|
||||||
:first-gap? true})
|
|
||||||
acc)))
|
|
||||||
([{:keys [messages previous-message gaps]} message]
|
|
||||||
(let [{:keys [gaps-number gap]}
|
|
||||||
(check-gap gaps previous-message message)
|
|
||||||
add-gap? (pos? gaps-number)]
|
|
||||||
{:messages (cond-> messages
|
|
||||||
|
|
||||||
add-gap?
|
|
||||||
(add-gap gap)
|
|
||||||
|
|
||||||
:always
|
|
||||||
(conj message))
|
|
||||||
:previous-message message
|
|
||||||
:gaps (if add-gap?
|
|
||||||
(drop gaps-number gaps)
|
|
||||||
gaps)}))
|
|
||||||
([{:keys [messages gaps]}]
|
|
||||||
(cond-> messages
|
|
||||||
(seq gaps)
|
|
||||||
(add-gap {:ids (map :id gaps)}))))
|
|
||||||
(reverse message-list)))
|
|
||||||
|
|
||||||
(def map->sorted-seq
|
|
||||||
(comp (partial map second) (partial sort-by first)))
|
|
||||||
|
@ -38,127 +38,3 @@
|
|||||||
(:datemark m4)))
|
(:datemark m4)))
|
||||||
(is (= {:type :datemark
|
(is (= {:type :datemark
|
||||||
:value "Dec 31, 1999"} d2)))))
|
:value "Dec 31, 1999"} d2)))))
|
||||||
|
|
||||||
(deftest add-gaps
|
|
||||||
(testing "empty state"
|
|
||||||
(is (empty?
|
|
||||||
(db/add-gaps
|
|
||||||
nil
|
|
||||||
nil
|
|
||||||
nil
|
|
||||||
false
|
|
||||||
false))))
|
|
||||||
(testing "empty state pub-chat"
|
|
||||||
(is (=
|
|
||||||
[{:type :gap
|
|
||||||
:value ":first-gap"
|
|
||||||
:first-gap? true}]
|
|
||||||
(db/add-gaps
|
|
||||||
nil
|
|
||||||
nil
|
|
||||||
{:lowest-request-from 10
|
|
||||||
:highest-request-to 30}
|
|
||||||
true
|
|
||||||
true))))
|
|
||||||
(testing "simple case with gap"
|
|
||||||
(is (= '({:whisper-timestamp 40000
|
|
||||||
:message-id :m4
|
|
||||||
:timestamp 40000}
|
|
||||||
{:type :gap
|
|
||||||
:value ":gapid1"
|
|
||||||
:gaps {:ids [:gapid1]}}
|
|
||||||
{:whisper-timestamp 30000
|
|
||||||
:timestamp 30000
|
|
||||||
:message-id :m3}
|
|
||||||
{:value "today"
|
|
||||||
:type :datemark
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:whisper-timestamp 20000
|
|
||||||
:timestamp 20000
|
|
||||||
:message-id :m2}
|
|
||||||
{:whisper-timestamp 10000
|
|
||||||
:timestamp 10000
|
|
||||||
:message-id :m1}
|
|
||||||
{:value "yesterday"
|
|
||||||
:type :datemark
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000})
|
|
||||||
(db/add-gaps
|
|
||||||
[{:message-id :m4
|
|
||||||
:whisper-timestamp 40000
|
|
||||||
:timestamp 40000}
|
|
||||||
{:message-id :m3
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:type :datemark
|
|
||||||
:value "today"
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:message-id :m2
|
|
||||||
:whisper-timestamp 20000
|
|
||||||
:timestamp 20000}
|
|
||||||
{:message-id :m1
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000}
|
|
||||||
{:type :datemark
|
|
||||||
:value "yesterday"
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000}]
|
|
||||||
[{:from 25
|
|
||||||
:to 30
|
|
||||||
:id :gapid1}]
|
|
||||||
nil
|
|
||||||
nil
|
|
||||||
nil))))
|
|
||||||
(testing "simple case with gap after all messages"
|
|
||||||
(is (= '({:type :gap
|
|
||||||
:value ":gapid1"
|
|
||||||
:gaps {:ids (:gapid1)}}
|
|
||||||
{:whisper-timestamp 40000
|
|
||||||
:message-id :m4
|
|
||||||
:timestamp 40000}
|
|
||||||
{:whisper-timestamp 30000
|
|
||||||
:message-id :m3
|
|
||||||
:timestamp 30000}
|
|
||||||
{:value "today"
|
|
||||||
:type :datemark
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:whisper-timestamp 20000
|
|
||||||
:message-id :m2
|
|
||||||
:timestamp 20000}
|
|
||||||
{:whisper-timestamp 10000
|
|
||||||
:message-id :m1
|
|
||||||
:timestamp 10000}
|
|
||||||
{:value "yesterday"
|
|
||||||
:type :datemark
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000})
|
|
||||||
(db/add-gaps
|
|
||||||
[{:message-id :m4
|
|
||||||
:whisper-timestamp 40000
|
|
||||||
:timestamp 40000}
|
|
||||||
{:message-id :m3
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:type :datemark
|
|
||||||
:value "today"
|
|
||||||
:whisper-timestamp 30000
|
|
||||||
:timestamp 30000}
|
|
||||||
{:message-id :m2
|
|
||||||
:whisper-timestamp 20000
|
|
||||||
:timestamp 20000}
|
|
||||||
{:message-id :m1
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000}
|
|
||||||
{:type :datemark
|
|
||||||
:value "yesterday"
|
|
||||||
:whisper-timestamp 10000
|
|
||||||
:timestamp 10000}]
|
|
||||||
[{:from 100
|
|
||||||
:to 110
|
|
||||||
:id :gapid1}]
|
|
||||||
nil
|
|
||||||
nil
|
|
||||||
nil)))))
|
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||||
[status-im.transport.filters.core :as transport.filters]
|
[status-im.chat.models.message-list :as message-list]
|
||||||
[status-im.data-store.chats :as chats-store]
|
[status-im.data-store.chats :as chats-store]
|
||||||
[status-im.data-store.messages :as messages-store]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.mailserver.core :as mailserver]
|
|
||||||
[status-im.ui.components.colors :as colors]
|
[status-im.ui.components.colors :as colors]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.navigation :as navigation]
|
[status-im.navigation :as navigation]
|
||||||
@ -16,8 +14,6 @@
|
|||||||
[status-im.utils.utils :as utils]
|
[status-im.utils.utils :as utils]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.add-new.db :as new-public-chat.db]
|
[status-im.add-new.db :as new-public-chat.db]
|
||||||
[status-im.mailserver.topics :as mailserver.topics]
|
|
||||||
[status-im.mailserver.constants :as mailserver.constants]
|
|
||||||
[status-im.chat.models.loading :as loading]
|
[status-im.chat.models.loading :as loading]
|
||||||
[status-im.ui.screens.chat.state :as chat.state]))
|
[status-im.ui.screens.chat.state :as chat.state]))
|
||||||
|
|
||||||
@ -83,33 +79,6 @@
|
|||||||
[{:keys [current-chat-id] :as db} kvs]
|
[{:keys [current-chat-id] :as db} kvs]
|
||||||
(update-in db [:chat-ui-props current-chat-id] merge kvs))
|
(update-in db [:chat-ui-props current-chat-id] merge kvs))
|
||||||
|
|
||||||
(defn dissoc-join-time-fields [db chat-id]
|
|
||||||
(update-in db [:chats chat-id] dissoc
|
|
||||||
:join-time-mail-request-id
|
|
||||||
:might-have-join-time-messages?))
|
|
||||||
|
|
||||||
(fx/defn join-time-messages-checked
|
|
||||||
"The key :might-have-join-time-messages? in public chats signals that
|
|
||||||
the public chat is freshly (re)created and requests for messages to the
|
|
||||||
mailserver for the topic has not completed yet. Likewise, the key
|
|
||||||
:join-time-mail-request-id is associated a little bit after, to signal that
|
|
||||||
the request to mailserver was a success. When request is signalled complete
|
|
||||||
by mailserver, corresponding event :chat.ui/join-time-messages-checked
|
|
||||||
dissociates these two fileds via this function, thereby signalling that the
|
|
||||||
public chat is not fresh anymore."
|
|
||||||
{:events [:chat.ui/join-time-messages-checked]}
|
|
||||||
[{:keys [db] :as cofx} chat-id]
|
|
||||||
(when (:might-have-join-time-messages? (get-chat cofx chat-id))
|
|
||||||
{:db (dissoc-join-time-fields db chat-id)}))
|
|
||||||
|
|
||||||
(fx/defn join-time-messages-checked-for-chats
|
|
||||||
[{:keys [db]} chat-ids]
|
|
||||||
{:db (reduce #(if (:might-have-join-time-messages? (get-chat {:db %1} %2))
|
|
||||||
(dissoc-join-time-fields %1 %2)
|
|
||||||
%1)
|
|
||||||
db
|
|
||||||
chat-ids)})
|
|
||||||
|
|
||||||
(defn- create-new-chat
|
(defn- create-new-chat
|
||||||
[chat-id {:keys [db now]}]
|
[chat-id {:keys [db now]}]
|
||||||
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
||||||
@ -132,10 +101,7 @@
|
|||||||
chat-props)
|
chat-props)
|
||||||
new? (not (get-in db [:chats chat-id]))
|
new? (not (get-in db [:chats chat-id]))
|
||||||
public? (public-chat? chat)]
|
public? (public-chat? chat)]
|
||||||
(fx/merge cofx
|
{:db (update-in db [:chats chat-id] merge chat)}))
|
||||||
{:db (update-in db [:chats chat-id] merge chat)}
|
|
||||||
(when (and public? new? (not timeline?))
|
|
||||||
(transport.filters/load-chat chat-id)))))
|
|
||||||
|
|
||||||
(defn map-chats [{:keys [db] :as cofx}]
|
(defn map-chats [{:keys [db] :as cofx}]
|
||||||
(fn [val]
|
(fn [val]
|
||||||
@ -155,52 +121,14 @@
|
|||||||
[{:keys [db] :as cofx} chats]
|
[{:keys [db] :as cofx} chats]
|
||||||
(let [chats (map (map-chats cofx) chats)
|
(let [chats (map (map-chats cofx) chats)
|
||||||
filtered-chats (filter (filter-chats db) chats)]
|
filtered-chats (filter (filter-chats db) chats)]
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update db :chats #(reduce
|
{:db (update db :chats #(reduce
|
||||||
(fn [acc {:keys [chat-id] :as chat}]
|
(fn [acc {:keys [chat-id] :as chat}]
|
||||||
(update acc chat-id merge chat))
|
(update acc chat-id merge chat))
|
||||||
%
|
%
|
||||||
chats))}
|
chats))}))
|
||||||
(transport.filters/load-chats filtered-chats))))
|
|
||||||
|
|
||||||
(fx/defn upsert-chat
|
|
||||||
"Upsert chat when not deleted"
|
|
||||||
[{:keys [db] :as cofx} {:keys [chat-id] :as chat-props} on-success]
|
|
||||||
(fx/merge cofx
|
|
||||||
(ensure-chat chat-props)
|
|
||||||
#(chats-store/save-chat % (get-in % [:db :chats chat-id]) on-success)))
|
|
||||||
|
|
||||||
(fx/defn handle-save-chat
|
|
||||||
{:events [::save-chat]}
|
|
||||||
[{:keys [db] :as cofx} chat-id on-success]
|
|
||||||
(chats-store/save-chat cofx (get-in db [:chats chat-id]) on-success))
|
|
||||||
|
|
||||||
(fx/defn add-public-chat
|
|
||||||
"Adds new public group chat to db"
|
|
||||||
[cofx topic profile-public-key timeline?]
|
|
||||||
(upsert-chat cofx
|
|
||||||
{:chat-id topic
|
|
||||||
:timeline? timeline?
|
|
||||||
:profile-public-key profile-public-key
|
|
||||||
:is-active true
|
|
||||||
:name topic
|
|
||||||
:chat-name (str "#" topic)
|
|
||||||
:group-chat true
|
|
||||||
:chat-type (cond timeline?
|
|
||||||
constants/timeline-chat-type
|
|
||||||
profile-public-key
|
|
||||||
constants/profile-chat-type
|
|
||||||
:else
|
|
||||||
constants/public-chat-type)
|
|
||||||
:contacts #{}
|
|
||||||
:public? true
|
|
||||||
:might-have-join-time-messages? (get-in cofx [:db :multiaccount :use-mailservers?])
|
|
||||||
:unviewed-messages-count 0}
|
|
||||||
nil))
|
|
||||||
|
|
||||||
(fx/defn clear-history
|
(fx/defn clear-history
|
||||||
"Clears history of the particular chat"
|
"Clears history of the particular chat"
|
||||||
{:events [:chat.ui/clear-history]}
|
|
||||||
[{:keys [db] :as cofx} chat-id remove-chat?]
|
[{:keys [db] :as cofx} chat-id remove-chat?]
|
||||||
(let [{:keys [last-message public?
|
(let [{:keys [last-message public?
|
||||||
deleted-at-clock-value]} (get-in db [:chats chat-id])
|
deleted-at-clock-value]} (get-in db [:chats chat-id])
|
||||||
@ -209,24 +137,39 @@
|
|||||||
(or (:clock-value last-message)
|
(or (:clock-value last-message)
|
||||||
deleted-at-clock-value
|
deleted-at-clock-value
|
||||||
(utils.clocks/send 0)))]
|
(utils.clocks/send 0)))]
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:messages chat-id] {})
|
(assoc-in [:messages chat-id] {})
|
||||||
(update-in [:message-lists] dissoc chat-id)
|
(update-in [:message-lists] dissoc chat-id)
|
||||||
(update-in [:chats chat-id] merge
|
(update-in [:chats chat-id] merge
|
||||||
{:last-message nil
|
{:last-message nil
|
||||||
:unviewed-messages-count 0
|
:unviewed-messages-count 0
|
||||||
:deleted-at-clock-value last-message-clock-value}))}
|
:deleted-at-clock-value last-message-clock-value}))}))
|
||||||
(messages-store/delete-messages-by-chat-id chat-id)
|
|
||||||
#(chats-store/save-chat % (get-in % [:db :chats chat-id]) nil))))
|
(fx/defn clear-history-handler
|
||||||
|
"Clears history of the particular chat"
|
||||||
|
{:events [:chat.ui/clear-history]}
|
||||||
|
[{:keys [db] :as cofx} chat-id remove-chat?]
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db db
|
||||||
|
::json-rpc/call [{:method "wakuext_clearHistory"
|
||||||
|
:params [{:id chat-id}]
|
||||||
|
:on-success #(re-frame/dispatch [::history-cleared chat-id %])
|
||||||
|
:on-error #(log/error "failed to clear history " chat-id %)}]}
|
||||||
|
(clear-history chat-id remove-chat?)))
|
||||||
|
|
||||||
(fx/defn deactivate-chat
|
(fx/defn deactivate-chat
|
||||||
"Deactivate chat in db, no side effects"
|
"Deactivate chat in db, no side effects"
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
|
(fx/merge
|
||||||
|
cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats chat-id :is-active] false)
|
(assoc-in [:chats chat-id :is-active] false)
|
||||||
(assoc-in [:current-chat-id] nil))})
|
(assoc-in [:current-chat-id] nil))
|
||||||
|
::json-rpc/call [{:method "wakuext_deactivateChat"
|
||||||
|
:params [{:id chat-id}]
|
||||||
|
:on-success #(log/debug "chat deactivated" chat-id)
|
||||||
|
:on-error #(log/error "failed to create public chat" chat-id %)}]}
|
||||||
|
(clear-history chat-id true)))
|
||||||
|
|
||||||
(fx/defn offload-messages
|
(fx/defn offload-messages
|
||||||
{:events [:offload-messages]}
|
{:events [:offload-messages]}
|
||||||
@ -250,12 +193,8 @@
|
|||||||
{:events [:chat.ui/remove-chat]}
|
{:events [:chat.ui/remove-chat]}
|
||||||
[{:keys [db now] :as cofx} chat-id]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(mailserver/remove-gaps chat-id)
|
|
||||||
(mailserver/remove-range chat-id)
|
|
||||||
(deactivate-chat chat-id)
|
(deactivate-chat chat-id)
|
||||||
(offload-messages chat-id)
|
(offload-messages chat-id)
|
||||||
(clear-history chat-id true)
|
|
||||||
(transport.filters/stop-listening chat-id)
|
|
||||||
(when (not (= (:view-id db) :home))
|
(when (not (= (:view-id db) :home))
|
||||||
(navigation/navigate-to-cofx :home {}))))
|
(navigation/navigate-to-cofx :home {}))))
|
||||||
|
|
||||||
@ -263,10 +202,7 @@
|
|||||||
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
|
"Takes chat-id and coeffects map, returns effects necessary when navigating to chat"
|
||||||
{:events [:chat.ui/preload-chat-data]}
|
{:events [:chat.ui/preload-chat-data]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
(fx/merge cofx
|
(loading/load-messages cofx chat-id))
|
||||||
(when-not (or (group-chat? cofx chat-id) (timeline-chat? cofx chat-id))
|
|
||||||
(transport.filters/load-chat chat-id))
|
|
||||||
(loading/load-messages chat-id)))
|
|
||||||
|
|
||||||
(fx/defn navigate-to-chat
|
(fx/defn navigate-to-chat
|
||||||
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
"Takes coeffects map and chat-id, returns effects necessary for navigation and preloading data"
|
||||||
@ -279,18 +215,29 @@
|
|||||||
(preload-chat-data chat-id)
|
(preload-chat-data chat-id)
|
||||||
(navigation/navigate-to-cofx :chat-stack {:screen :chat})))
|
(navigation/navigate-to-cofx :chat-stack {:screen :chat})))
|
||||||
|
|
||||||
|
(fx/defn handle-clear-history-response
|
||||||
|
{:events [::history-cleared]}
|
||||||
|
[{:keys [db] :as cofx} chat-id response]
|
||||||
|
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
||||||
|
{:db (assoc-in db [:chats chat-id] chat)}))
|
||||||
|
|
||||||
|
(fx/defn handle-one-to-one-chat-created
|
||||||
|
{:events [::one-to-one-chat-created]}
|
||||||
|
[{:keys [db] :as cofx} chat-id response]
|
||||||
|
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
||||||
|
{:db (assoc-in db [:chats chat-id] chat)
|
||||||
|
:dispatch [:chat.ui/navigate-to-chat chat-id]}))
|
||||||
|
|
||||||
(fx/defn start-chat
|
(fx/defn start-chat
|
||||||
"Start a chat, making sure it exists"
|
"Start a chat, making sure it exists"
|
||||||
{:events [:chat.ui/start-chat]}
|
{:events [:chat.ui/start-chat]}
|
||||||
[{:keys [db] :as cofx} chat-id]
|
[{:keys [db] :as cofx} chat-id]
|
||||||
;; don't allow to open chat with yourself
|
;; don't allow to open chat with yourself
|
||||||
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
|
(when (not= (multiaccounts.model/current-public-key cofx) chat-id)
|
||||||
(fx/merge cofx
|
{::json-rpc/call [{:method "wakuext_createOneToOneChat"
|
||||||
{:dispatch [:chat.ui/navigate-to-chat chat-id]}
|
:params [{:id chat-id}]
|
||||||
(upsert-chat {:chat-id chat-id
|
:on-success #(re-frame/dispatch [::one-to-one-chat-created chat-id %])
|
||||||
:is-active true}
|
:on-error #(log/error "failed to create one-to-on chat" chat-id %)}]}))
|
||||||
nil)
|
|
||||||
(transport.filters/load-chat chat-id))))
|
|
||||||
|
|
||||||
(defn profile-chat-topic [public-key]
|
(defn profile-chat-topic [public-key]
|
||||||
(str "@" public-key))
|
(str "@" public-key))
|
||||||
@ -298,44 +245,60 @@
|
|||||||
(defn my-profile-chat-topic [db]
|
(defn my-profile-chat-topic [db]
|
||||||
(profile-chat-topic (get-in db [:multiaccount :public-key])))
|
(profile-chat-topic (get-in db [:multiaccount :public-key])))
|
||||||
|
|
||||||
|
(fx/defn handle-public-chat-created
|
||||||
|
{:events [::public-chat-created]}
|
||||||
|
[{:keys [db] :as cofx} chat-id {:keys [dont-navigate?]} response]
|
||||||
|
(let [chat (chats-store/<-rpc (first (:chats response)))
|
||||||
|
db-with-chat {:db (assoc-in db [:chats chat-id] chat)}]
|
||||||
|
(if dont-navigate?
|
||||||
|
db-with-chat
|
||||||
|
(assoc db-with-chat :dispatch [:chat.ui/navigate-to-chat chat-id]))))
|
||||||
|
|
||||||
|
(fx/defn create-public-chat-go [cofx chat-id opts]
|
||||||
|
{::json-rpc/call [{:method "wakuext_createPublicChat"
|
||||||
|
:params [{:id chat-id}]
|
||||||
|
:on-success #(re-frame/dispatch [::public-chat-created chat-id opts %])
|
||||||
|
:on-error #(log/error "failed to create public chat" chat-id %)}]})
|
||||||
|
|
||||||
(fx/defn start-public-chat
|
(fx/defn start-public-chat
|
||||||
"Starts a new public chat"
|
"Starts a new public chat"
|
||||||
{:events [:chat.ui/start-public-chat]}
|
{:events [:chat.ui/start-public-chat]}
|
||||||
[cofx topic {:keys [dont-navigate? profile-public-key navigation-reset?]}]
|
[cofx topic {:keys [dont-navigate? profile-public-key] :as opts}]
|
||||||
(if (or (new-public-chat.db/valid-topic? topic) profile-public-key)
|
(if (or (new-public-chat.db/valid-topic? topic) profile-public-key)
|
||||||
(if (active-chat? cofx topic)
|
(if (active-chat? cofx topic)
|
||||||
(when-not dont-navigate?
|
(when-not dont-navigate?
|
||||||
(if navigation-reset?
|
(navigate-to-chat cofx topic))
|
||||||
(fx/merge cofx
|
(create-public-chat-go
|
||||||
{:dispatch [:chat.ui/navigate-to-chat topic]}
|
cofx
|
||||||
(navigation/navigate-to-cofx :home {}))
|
topic
|
||||||
(navigate-to-chat cofx topic)))
|
opts))
|
||||||
(fx/merge cofx
|
|
||||||
(add-public-chat topic profile-public-key false)
|
|
||||||
(transport.filters/load-chat topic)
|
|
||||||
#(when navigation-reset?
|
|
||||||
(navigation/navigate-to-cofx % :home {}))
|
|
||||||
#(when-not dont-navigate?
|
|
||||||
{:dispatch [:chat.ui/navigate-to-chat topic]})))
|
|
||||||
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
|
{:utils/show-popup {:title (i18n/label :t/cant-open-public-chat)
|
||||||
:content (i18n/label :t/invalid-public-chat-topic)}}))
|
:content (i18n/label :t/invalid-public-chat-topic)}}))
|
||||||
|
|
||||||
|
(fx/defn profile-chat-created
|
||||||
|
{:events [::profile-chat-created]}
|
||||||
|
[{:keys [db] :as cofx} chat-id response navigate-to?]
|
||||||
|
(fx/merge
|
||||||
|
cofx
|
||||||
|
{:db db}
|
||||||
|
#(when response
|
||||||
|
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
||||||
|
{:db (assoc-in db [:chats chat-id] chat)}))
|
||||||
|
#(when navigate-to?
|
||||||
|
{:dispatch-n [[:chat.ui/preload-chat-data chat-id]
|
||||||
|
[:navigate-to :profile nil]]})))
|
||||||
|
|
||||||
(fx/defn start-profile-chat
|
(fx/defn start-profile-chat
|
||||||
"Starts a new profile chat"
|
"Starts a new profile chat"
|
||||||
{:events [:start-profile-chat]}
|
{:events [:start-profile-chat]}
|
||||||
[cofx profile-public-key]
|
[cofx profile-public-key navigate-to?]
|
||||||
(let [topic (profile-chat-topic profile-public-key)]
|
(let [chat-id (profile-chat-topic profile-public-key)]
|
||||||
(when-not (active-chat? cofx topic)
|
(if (active-chat? cofx chat-id)
|
||||||
(fx/merge cofx
|
{:dispatch [::profile-chat-created chat-id nil navigate-to?]}
|
||||||
(add-public-chat topic profile-public-key false)
|
{::json-rpc/call [{:method "wakuext_createProfileChat"
|
||||||
(transport.filters/load-chat topic)))))
|
:params [{:id profile-public-key}]
|
||||||
|
:on-success #(re-frame/dispatch [::profile-chat-created chat-id % navigate-to?])
|
||||||
(fx/defn start-timeline-chat
|
:on-error #(log/error "failed to create profile chat" chat-id %)}]})))
|
||||||
"Starts a new timeline chat"
|
|
||||||
{:events [:chat/start-timeline-chat]}
|
|
||||||
[cofx]
|
|
||||||
(when-not (active-chat? cofx constants/timeline-chat-id)
|
|
||||||
(add-public-chat cofx constants/timeline-chat-id nil true)))
|
|
||||||
|
|
||||||
(fx/defn disable-chat-cooldown
|
(fx/defn disable-chat-cooldown
|
||||||
"Turns off chat cooldown (protection against message spamming)"
|
"Turns off chat cooldown (protection against message spamming)"
|
||||||
@ -357,22 +320,21 @@
|
|||||||
(log/error "mute chat failed" chat-id error)
|
(log/error "mute chat failed" chat-id error)
|
||||||
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
|
{:db (assoc-in db [:chats chat-id :muted] (not muted?))})
|
||||||
|
|
||||||
|
(fx/defn mute-chat-successful
|
||||||
|
{:events [::mute-chat-successful]}
|
||||||
|
[{:keys [db]} chat-id response]
|
||||||
|
(let [chat (chats-store/<-rpc (first (:chats response)))]
|
||||||
|
{:db (assoc-in db [:chats chat-id] chat)}))
|
||||||
|
|
||||||
(fx/defn mute-chat
|
(fx/defn mute-chat
|
||||||
{:events [::mute-chat-toggled]}
|
{:events [::mute-chat-toggled]}
|
||||||
[{:keys [db] :as cofx} chat-id muted?]
|
[{:keys [db] :as cofx} chat-id muted?]
|
||||||
(let [method (if muted? "muteChat" "unmuteChat")
|
(let [method (if muted? "muteChat" "unmuteChat")]
|
||||||
chat (get-in db [:chats chat-id])]
|
|
||||||
;; chat does not exist, create and then mute
|
|
||||||
(if-not chat
|
|
||||||
(upsert-chat cofx
|
|
||||||
{:is-active true
|
|
||||||
:chat-id chat-id}
|
|
||||||
#(re-frame/dispatch [::mute-chat-toggled chat-id muted?]))
|
|
||||||
{:db (assoc-in db [:chats chat-id :muted] muted?)
|
{:db (assoc-in db [:chats chat-id :muted] muted?)
|
||||||
::json-rpc/call [{:method (json-rpc/call-ext-method method)
|
::json-rpc/call [{:method (json-rpc/call-ext-method method)
|
||||||
:params [chat-id]
|
:params [chat-id]
|
||||||
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
|
:on-error #(re-frame/dispatch [::mute-chat-failed chat-id muted? %])
|
||||||
:on-success #(log/info method "successful" chat-id)}]})))
|
:on-success #(re-frame/dispatch [::mute-chat-successful chat-id %])}]}))
|
||||||
|
|
||||||
(fx/defn show-profile
|
(fx/defn show-profile
|
||||||
{:events [:chat.ui/show-profile]}
|
{:events [:chat.ui/show-profile]}
|
||||||
@ -382,10 +344,8 @@
|
|||||||
(navigation/navigate-to-cofx cofx :profile-stack {:screen :my-profile})
|
(navigation/navigate-to-cofx cofx :profile-stack {:screen :my-profile})
|
||||||
(fx/merge
|
(fx/merge
|
||||||
cofx
|
cofx
|
||||||
{:db (assoc db :contacts/identity identity)
|
{:db (assoc db :contacts/identity identity)}
|
||||||
:dispatch [:chat.ui/preload-chat-data (profile-chat-topic identity)]}
|
(start-profile-chat identity true)))))
|
||||||
(start-profile-chat identity)
|
|
||||||
(navigation/navigate-to-cofx :profile nil)))))
|
|
||||||
|
|
||||||
(fx/defn clear-history-pressed
|
(fx/defn clear-history-pressed
|
||||||
{:events [:chat.ui/clear-history-pressed]}
|
{:events [:chat.ui/clear-history-pressed]}
|
||||||
@ -398,35 +358,61 @@
|
|||||||
(re-frame/dispatch [:bottom-sheet/hide])
|
(re-frame/dispatch [:bottom-sheet/hide])
|
||||||
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
|
(re-frame/dispatch [:chat.ui/clear-history chat-id false]))}})
|
||||||
|
|
||||||
|
(fx/defn gaps-failed
|
||||||
|
{:events [::gaps-failed]}
|
||||||
|
[{:keys [db]} chat-id gap-ids error]
|
||||||
|
(log/error "failed to fetch gaps" chat-id gap-ids error)
|
||||||
|
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
||||||
|
|
||||||
|
(fx/defn sync-chat-from-sync-from-failed
|
||||||
|
{:events [::sync-chat-from-sync-from-failed]}
|
||||||
|
[{:keys [db]} chat-id error]
|
||||||
|
(log/error "failed to sync chat" chat-id error)
|
||||||
|
{:db (dissoc db :mailserver/fetching-gaps-in-progress)})
|
||||||
|
|
||||||
|
(fx/defn sync-chat-from-sync-from-success
|
||||||
|
{:events [::sync-chat-from-sync-from-success]}
|
||||||
|
[{:keys [db] :as cofx} chat-id synced-from]
|
||||||
|
(log/debug "synced success" chat-id synced-from)
|
||||||
|
{:db
|
||||||
|
(-> db
|
||||||
|
(assoc-in [:chats chat-id :synced-from] synced-from)
|
||||||
|
(dissoc :mailserver/fetching-gaps-in-progress))})
|
||||||
|
|
||||||
|
(fx/defn gaps-filled
|
||||||
|
{:events [::gaps-filled]}
|
||||||
|
[{:keys [db] :as cofx} chat-id message-ids]
|
||||||
|
(fx/merge
|
||||||
|
cofx
|
||||||
|
{:db (-> db
|
||||||
|
(update-in [:messages chat-id] (fn [messages] (apply dissoc messages message-ids)))
|
||||||
|
(dissoc :mailserver/fetching-gaps-in-progress))}
|
||||||
|
(message-list/rebuild-message-list chat-id)))
|
||||||
|
|
||||||
|
(fx/defn fill-gaps
|
||||||
|
[cofx chat-id gap-ids]
|
||||||
|
{::json-rpc/call [{:method "wakuext_fillGaps"
|
||||||
|
:params [chat-id gap-ids]
|
||||||
|
:on-success #(re-frame/dispatch [::gaps-filled chat-id gap-ids %])
|
||||||
|
:on-error #(re-frame/dispatch [::gaps-failed chat-id gap-ids %])}]})
|
||||||
|
|
||||||
|
(fx/defn sync-chat-from-sync-from
|
||||||
|
[cofx chat-id]
|
||||||
|
(log/debug "syncing chat from sync from")
|
||||||
|
{::json-rpc/call [{:method "wakuext_syncChatFromSyncedFrom"
|
||||||
|
:params [chat-id]
|
||||||
|
:on-success #(re-frame/dispatch [::sync-chat-from-sync-from-success chat-id %])
|
||||||
|
:on-error #(re-frame/dispatch [::sync-chat-from-sync-from-failed chat-id %])}]})
|
||||||
|
|
||||||
(fx/defn chat-ui-fill-gaps
|
(fx/defn chat-ui-fill-gaps
|
||||||
{:events [:chat.ui/fill-gaps]}
|
{:events [:chat.ui/fill-gaps]}
|
||||||
[{:keys [db] :as cofx} gap-ids chat-id]
|
[{:keys [db] :as cofx} chat-id gap-ids]
|
||||||
(let [topics (mailserver.topics/topics-for-chat db chat-id)
|
(log/info "filling gaps" chat-id gap-ids)
|
||||||
gaps (keep
|
(fx/merge cofx
|
||||||
(fn [id]
|
{:db (assoc db :mailserver/fetching-gaps-in-progress gap-ids)}
|
||||||
(get-in db [:mailserver/gaps chat-id id]))
|
(if (= gap-ids #{:first-gap})
|
||||||
gap-ids)]
|
(sync-chat-from-sync-from chat-id)
|
||||||
(mailserver/fill-the-gap
|
(fill-gaps chat-id gap-ids))))
|
||||||
cofx
|
|
||||||
{:gaps gaps
|
|
||||||
:topics topics
|
|
||||||
:chat-id chat-id})))
|
|
||||||
|
|
||||||
(fx/defn chat-ui-fetch-more
|
|
||||||
{:events [:chat.ui/fetch-more]}
|
|
||||||
[{:keys [db] :as cofx} chat-id]
|
|
||||||
(let [{:keys [lowest-request-from]}
|
|
||||||
(get-in db [:mailserver/ranges chat-id])
|
|
||||||
|
|
||||||
topics (mailserver.topics/topics-for-chat db chat-id)
|
|
||||||
gaps [{:id :first-gap
|
|
||||||
:to lowest-request-from
|
|
||||||
:from (- lowest-request-from mailserver.constants/one-day)}]]
|
|
||||||
(mailserver/fill-the-gap
|
|
||||||
cofx
|
|
||||||
{:gaps gaps
|
|
||||||
:topics topics
|
|
||||||
:chat-id chat-id})))
|
|
||||||
|
|
||||||
(fx/defn chat-ui-remove-chat-pressed
|
(fx/defn chat-ui-remove-chat-pressed
|
||||||
{:events [:chat.ui/remove-chat-pressed]}
|
{:events [:chat.ui/remove-chat-pressed]}
|
||||||
|
@ -28,9 +28,7 @@
|
|||||||
new-chats)
|
new-chats)
|
||||||
chats (merge old-chats chats)]
|
chats (merge old-chats chats)]
|
||||||
{:db (assoc db :chats chats
|
{:db (assoc db :chats chats
|
||||||
:chats/loading? false)
|
:chats/loading? false)}))
|
||||||
:dispatch-n [[:chat/start-timeline-chat]
|
|
||||||
[:start-profile-chat (get-in db [:multiaccount :public-key])]]}))
|
|
||||||
|
|
||||||
(fx/defn initialize-chats
|
(fx/defn initialize-chats
|
||||||
"Initialize persisted chats on startup"
|
"Initialize persisted chats on startup"
|
||||||
@ -115,8 +113,7 @@
|
|||||||
(when (or first-request cursor)
|
(when (or first-request cursor)
|
||||||
(merge
|
(merge
|
||||||
{:db (assoc-in db [:pagination-info chat-id :loading-messages?] true)}
|
{:db (assoc-in db [:pagination-info chat-id :loading-messages?] true)}
|
||||||
{:utils/dispatch-later [{:ms 100 :dispatch [:load-more-reactions cursor chat-id]}
|
{:utils/dispatch-later [{:ms 100 :dispatch [:load-more-reactions cursor chat-id]}]}
|
||||||
{:ms 100 :dispatch [:load-gaps chat-id]}]}
|
|
||||||
(data-store.messages/messages-by-chat-id-rpc
|
(data-store.messages/messages-by-chat-id-rpc
|
||||||
chat-id
|
chat-id
|
||||||
cursor
|
cursor
|
||||||
|
@ -28,35 +28,11 @@
|
|||||||
(update-in [:db :messages chat-id] assoc message-id message)
|
(update-in [:db :messages chat-id] assoc message-id message)
|
||||||
(update-in [:db :message-lists chat-id] message-list/add message)))
|
(update-in [:db :message-lists chat-id] message-list/add message)))
|
||||||
|
|
||||||
;;TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
|
||||||
(fx/defn rebuild-message-list
|
|
||||||
[{:keys [db]} chat-id]
|
|
||||||
{:db (assoc-in db [:message-lists chat-id]
|
|
||||||
(message-list/add-many nil (vals (get-in db [:messages chat-id]))))})
|
|
||||||
|
|
||||||
(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]
|
||||||
;;TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
;;TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
||||||
(rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
|
(message-list/rebuild-message-list {:db (update-in db [:messages chat-id] dissoc message-id)} chat-id))
|
||||||
|
|
||||||
(fx/defn join-times-messages-checked
|
|
||||||
"The key :might-have-join-time-messages? in public chats signals that
|
|
||||||
the public chat is freshly (re)created and requests for messages to the
|
|
||||||
mailserver for the topic has not completed yet. Likewise, the key
|
|
||||||
:join-time-mail-request-id is associated a little bit after, to signal that
|
|
||||||
the request to mailserver was a success. When request is signalled complete
|
|
||||||
by mailserver, corresponding event :chat.ui/join-times-messages-checked
|
|
||||||
dissociates these two fileds via this function, thereby signalling that the
|
|
||||||
public chat is not fresh anymore."
|
|
||||||
{:events [:chat/join-times-messages-checked]}
|
|
||||||
[{:keys [db] :as cofx} chat-ids]
|
|
||||||
(reduce (fn [acc chat-id]
|
|
||||||
(cond-> acc
|
|
||||||
(:might-have-join-time-messages? (chat-model/get-chat cofx chat-id))
|
|
||||||
(update :db #(chat-model/dissoc-join-time-fields % chat-id))))
|
|
||||||
{:db db}
|
|
||||||
chat-ids))
|
|
||||||
|
|
||||||
(fx/defn add-senders-to-chat-users
|
(fx/defn add-senders-to-chat-users
|
||||||
{:events [:chat/add-senders-to-chat-users]}
|
{:events [:chat/add-senders-to-chat-users]}
|
||||||
@ -209,7 +185,7 @@
|
|||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (update-in db [:messages chat-id] dissoc message-id)}
|
{:db (update-in db [:messages chat-id] dissoc message-id)}
|
||||||
(data-store.messages/delete-message message-id)
|
(data-store.messages/delete-message message-id)
|
||||||
(rebuild-message-list chat-id)))
|
(message-list/rebuild-message-list chat-id)))
|
||||||
|
|
||||||
(fx/defn send-message
|
(fx/defn send-message
|
||||||
[cofx message]
|
[cofx message]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
(ns status-im.chat.models.message-list
|
(ns status-im.chat.models.message-list
|
||||||
(:require [status-im.constants :as constants]
|
(:require [status-im.constants :as constants]
|
||||||
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
["functional-red-black-tree" :as rb-tree]))
|
["functional-red-black-tree" :as rb-tree]))
|
||||||
|
|
||||||
@ -180,3 +181,9 @@
|
|||||||
(if message-list
|
(if message-list
|
||||||
(array-seq (.-values message-list))
|
(array-seq (.-values message-list))
|
||||||
[]))
|
[]))
|
||||||
|
|
||||||
|
;;TODO this is too expensive, probably we could mark message somehow and just hide it in the UI
|
||||||
|
(fx/defn rebuild-message-list
|
||||||
|
[{:keys [db]} chat-id]
|
||||||
|
{:db (assoc-in db [:message-lists chat-id]
|
||||||
|
(add-many nil (vals (get-in db [:messages chat-id]))))})
|
||||||
|
@ -1,67 +1,8 @@
|
|||||||
(ns status-im.chat.models-test
|
(ns status-im.chat.models-test
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||||
[status-im.utils.gfycat.core :as gfycat]
|
|
||||||
[status-im.utils.identicon :as identicon]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.utils.clocks :as utils.clocks]
|
[status-im.utils.clocks :as utils.clocks]
|
||||||
[status-im.chat.models :as chat]))
|
[status-im.chat.models :as chat]))
|
||||||
|
|
||||||
(deftest upsert-chat-test
|
|
||||||
(testing "upserting a non existing chat"
|
|
||||||
(let [chat-id "some-chat-id"
|
|
||||||
contact-name "contact-name"
|
|
||||||
chat-props {:chat-id chat-id
|
|
||||||
:extra-prop "some"}
|
|
||||||
cofx {:now "now"
|
|
||||||
:db {:contacts/contacts {chat-id
|
|
||||||
{:name contact-name}}}}
|
|
||||||
response (chat/upsert-chat cofx chat-props nil)
|
|
||||||
actual-chat (get-in response [:db :chats chat-id])]
|
|
||||||
(testing "it adds the chat to the chats collection"
|
|
||||||
(is actual-chat))
|
|
||||||
(testing "it adds the extra props"
|
|
||||||
(is (= "some" (:extra-prop actual-chat))))
|
|
||||||
(testing "it adds the chat id"
|
|
||||||
(is (= chat-id (:chat-id actual-chat))))
|
|
||||||
(testing "it pulls the name from the contacts"
|
|
||||||
(is (= contact-name (:name actual-chat))))
|
|
||||||
(testing "it sets the timestamp"
|
|
||||||
(is (= "now" (:timestamp actual-chat))))
|
|
||||||
(testing "it adds the contact-id to the contact field"
|
|
||||||
(is (= chat-id (-> actual-chat :contacts first))))))
|
|
||||||
(testing "upserting an existing chat"
|
|
||||||
(let [chat-id "some-chat-id"
|
|
||||||
chat-props {:chat-id chat-id
|
|
||||||
:name "new-name"
|
|
||||||
:extra-prop "some"}
|
|
||||||
cofx {:db {:chats {chat-id {:is-active true
|
|
||||||
:name "old-name"}}}}
|
|
||||||
response (chat/upsert-chat cofx chat-props nil)
|
|
||||||
actual-chat (get-in response [:db :chats chat-id])]
|
|
||||||
(testing "it adds the chat to the chats collection"
|
|
||||||
(is actual-chat))
|
|
||||||
(testing "it adds the extra props"
|
|
||||||
(is (= "some" (:extra-prop actual-chat))))
|
|
||||||
(testing "it updates existins props"
|
|
||||||
(is (= "new-name" (:name actual-chat)))))))
|
|
||||||
|
|
||||||
(deftest add-public-chat
|
|
||||||
(with-redefs [gfycat/generate-gfy (constantly "generated")
|
|
||||||
identicon/identicon (constantly "generated")]
|
|
||||||
(let [topic "topic"
|
|
||||||
fx (chat/add-public-chat {:db {}} topic nil nil)
|
|
||||||
chat (get-in fx [:db :chats topic])]
|
|
||||||
(testing "it sets the name"
|
|
||||||
(is (= topic (:name chat))))
|
|
||||||
(testing "it sets the participants"
|
|
||||||
(is (= #{} (:contacts chat))))
|
|
||||||
(testing "it sets the chat-id"
|
|
||||||
(is (= topic (:chat-id chat))))
|
|
||||||
(testing "it sets the group-chat flag"
|
|
||||||
(is (:group-chat chat)))
|
|
||||||
(testing "it does not sets the public flag"
|
|
||||||
(is (:public? chat))))))
|
|
||||||
|
|
||||||
(deftest clear-history-test
|
(deftest clear-history-test
|
||||||
(let [chat-id "1"
|
(let [chat-id "1"
|
||||||
cofx {:db {:message-lists {chat-id [{:something "a"}]}
|
cofx {:db {:message-lists {chat-id [{:something "a"}]}
|
||||||
@ -96,11 +37,7 @@
|
|||||||
:last-message nil)
|
:last-message nil)
|
||||||
chat-id
|
chat-id
|
||||||
true)]
|
true)]
|
||||||
(is (= 42 (get-in actual [:db :chats chat-id :deleted-at-clock-value]))))))
|
(is (= 42 (get-in actual [:db :chats chat-id :deleted-at-clock-value]))))))))
|
||||||
(testing "it adds the relevant rpc calls"
|
|
||||||
(let [actual (chat/clear-history cofx chat-id true)]
|
|
||||||
(is (::json-rpc/call actual))
|
|
||||||
(is (= 2 (count (::json-rpc/call actual))))))))
|
|
||||||
|
|
||||||
(deftest remove-chat-test
|
(deftest remove-chat-test
|
||||||
(let [chat-id "1"
|
(let [chat-id "1"
|
||||||
@ -110,17 +47,13 @@
|
|||||||
:chats {chat-id {:last-message {:clock-value 10}}}}}]
|
:chats {chat-id {:last-message {:clock-value 10}}}}}]
|
||||||
(testing "it deletes all the messages"
|
(testing "it deletes all the messages"
|
||||||
(let [actual (chat/remove-chat cofx chat-id)]
|
(let [actual (chat/remove-chat cofx chat-id)]
|
||||||
(is (= {} (get-in actual [:db :messages chat-id])))))
|
(is (= nil (get-in actual [:db :messages chat-id])))))
|
||||||
(testing "it sets a deleted-at-clock-value equal to the last message clock-value"
|
(testing "it sets a deleted-at-clock-value equal to the last message clock-value"
|
||||||
(let [actual (chat/remove-chat cofx chat-id)]
|
(let [actual (chat/remove-chat cofx chat-id)]
|
||||||
(is (= 10 (get-in actual [:db :chats chat-id :deleted-at-clock-value])))))
|
(is (= 10 (get-in actual [:db :chats chat-id :deleted-at-clock-value])))))
|
||||||
(testing "it sets the chat as inactive"
|
(testing "it sets the chat as inactive"
|
||||||
(let [actual (chat/remove-chat cofx chat-id)]
|
(let [actual (chat/remove-chat cofx chat-id)]
|
||||||
(is (= false (get-in actual [:db :chats chat-id :is-active])))))
|
(is (= false (get-in actual [:db :chats chat-id :is-active])))))))
|
||||||
(testing "it makes the relevant json-rpc calls"
|
|
||||||
(let [actual (chat/remove-chat cofx chat-id)]
|
|
||||||
(is (::json-rpc/call actual))
|
|
||||||
(is (= 4 (count (::json-rpc/call actual))))))))
|
|
||||||
|
|
||||||
(deftest multi-user-chat?
|
(deftest multi-user-chat?
|
||||||
(let [chat-id "1"]
|
(let [chat-id "1"]
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
(def ^:const content-type-image 7)
|
(def ^:const content-type-image 7)
|
||||||
(def ^:const content-type-audio 8)
|
(def ^:const content-type-audio 8)
|
||||||
(def ^:const content-type-community 9)
|
(def ^:const content-type-community 9)
|
||||||
|
(def ^:const content-type-gap 10)
|
||||||
|
|
||||||
(def ^:const emoji-reaction-love 1)
|
(def ^:const emoji-reaction-love 1)
|
||||||
(def ^:const emoji-reaction-thumbs-up 2)
|
(def ^:const emoji-reaction-thumbs-up 2)
|
||||||
@ -47,6 +48,8 @@
|
|||||||
(def ^:const message-type-public-group 2)
|
(def ^:const message-type-public-group 2)
|
||||||
(def ^:const message-type-private-group 3)
|
(def ^:const message-type-private-group 3)
|
||||||
(def ^:const message-type-private-group-system-message 4)
|
(def ^:const message-type-private-group-system-message 4)
|
||||||
|
(def ^:const message-type-community-chat 5)
|
||||||
|
(def ^:const message-type-gap 6)
|
||||||
|
|
||||||
(def ^:const command-state-request-address-for-transaction 1)
|
(def ^:const command-state-request-address-for-transaction 1)
|
||||||
(def ^:const command-state-request-address-for-transaction-declined 2)
|
(def ^:const command-state-request-address-for-transaction-declined 2)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
[status-im.data-store.contacts :as contacts-store]
|
[status-im.data-store.contacts :as contacts-store]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.mailserver.core :as mailserver]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.transport.filters.core :as transport.filters]
|
|
||||||
[status-im.navigation :as navigation]
|
[status-im.navigation :as navigation]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
@ -57,7 +56,6 @@
|
|||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:contacts/contacts public-key] merge contact))}
|
(update-in [:contacts/contacts public-key] merge contact))}
|
||||||
(transport.filters/load-contact contact)
|
|
||||||
(fn [cf]
|
(fn [cf]
|
||||||
(contacts-store/save-contact cf
|
(contacts-store/save-contact cf
|
||||||
(get-in cf [:db :contacts/contacts public-key])
|
(get-in cf [:db :contacts/contacts public-key])
|
||||||
@ -98,10 +96,11 @@
|
|||||||
(let [new-contact (update contact
|
(let [new-contact (update contact
|
||||||
:system-tags
|
:system-tags
|
||||||
(fnil #(disj % :contact/added) #{}))]
|
(fnil #(disj % :contact/added) #{}))]
|
||||||
(fx/merge cofx
|
|
||||||
{:db (assoc-in db [:contacts/contacts public-key] new-contact)
|
{:db (assoc-in db [:contacts/contacts public-key] new-contact)
|
||||||
:dispatch [:offload-messages constants/timeline-chat-id]}
|
::json-rpc/call [{:method "wakuext_removeContact"
|
||||||
(contacts-store/save-contact new-contact nil))))
|
:params [public-key]
|
||||||
|
:on-success #(log/debug "contact removed successfully")}]
|
||||||
|
:dispatch [:offload-messages constants/timeline-chat-id]}))
|
||||||
|
|
||||||
(fx/defn create-contact
|
(fx/defn create-contact
|
||||||
"Create entry in contacts"
|
"Create entry in contacts"
|
||||||
@ -137,8 +136,7 @@
|
|||||||
(update-in [:contacts/contacts public-key] merge contact))
|
(update-in [:contacts/contacts public-key] merge contact))
|
||||||
::json-rpc/call [{:method "wakuext_ensVerified"
|
::json-rpc/call [{:method "wakuext_ensVerified"
|
||||||
:params [public-key ens-name]
|
:params [public-key ens-name]
|
||||||
:on-success #(log/debug "ens name verified successuful")}]}
|
:on-success #(log/debug "ens name verified successuful")}]})))
|
||||||
(transport.filters/load-contact contact))))
|
|
||||||
|
|
||||||
(fx/defn update-nickname
|
(fx/defn update-nickname
|
||||||
{:events [:contacts/update-nickname]}
|
{:events [:contacts/update-nickname]}
|
||||||
|
@ -75,6 +75,8 @@
|
|||||||
type->rpc
|
type->rpc
|
||||||
(clojure.set/rename-keys {:chat-id :id
|
(clojure.set/rename-keys {:chat-id :id
|
||||||
:membership-update-events :membershipUpdateEvents
|
:membership-update-events :membershipUpdateEvents
|
||||||
|
:synced-from :syncedFrom
|
||||||
|
:synced-to :syncedTo
|
||||||
:unviewed-messages-count :unviewedMessagesCount
|
:unviewed-messages-count :unviewedMessagesCount
|
||||||
:last-message :lastMessage
|
:last-message :lastMessage
|
||||||
:community-id :communityId
|
:community-id :communityId
|
||||||
@ -83,7 +85,7 @@
|
|||||||
:last-clock-value :lastClockValue
|
:last-clock-value :lastClockValue
|
||||||
:profile-public-key :profile})
|
:profile-public-key :profile})
|
||||||
(dissoc :public? :group-chat :messages
|
(dissoc :public? :group-chat :messages
|
||||||
:might-have-join-time-messages? :chat-type
|
:chat-type
|
||||||
:contacts :admins :members-joined)))
|
:contacts :admins :members-joined)))
|
||||||
|
|
||||||
(defn <-rpc [chat]
|
(defn <-rpc [chat]
|
||||||
@ -92,6 +94,8 @@
|
|||||||
unmarshal-members
|
unmarshal-members
|
||||||
(clojure.set/rename-keys {:id :chat-id
|
(clojure.set/rename-keys {:id :chat-id
|
||||||
:communityId :community-id
|
:communityId :community-id
|
||||||
|
:syncedFrom :synced-from
|
||||||
|
:syncedTo :synced-to
|
||||||
:membershipUpdateEvents :membership-update-events
|
:membershipUpdateEvents :membership-update-events
|
||||||
:deletedAtClockValue :deleted-at-clock-value
|
:deletedAtClockValue :deleted-at-clock-value
|
||||||
:chatType :chat-type
|
:chatType :chat-type
|
||||||
@ -104,16 +108,8 @@
|
|||||||
(update :last-message #(when % (messages/<-rpc %)))
|
(update :last-message #(when % (messages/<-rpc %)))
|
||||||
(dissoc :members)))
|
(dissoc :members)))
|
||||||
|
|
||||||
(fx/defn save-chat [cofx {:keys [chat-id] :as chat} on-success]
|
|
||||||
{::json-rpc/call [{:method (json-rpc/call-ext-method "saveChat")
|
|
||||||
:params [(->rpc chat)]
|
|
||||||
:on-success #(do
|
|
||||||
(log/debug "saved chat" chat-id "successfuly")
|
|
||||||
(when on-success (on-success)))
|
|
||||||
:on-failure #(log/error "failed to save chat" chat-id %)}]})
|
|
||||||
|
|
||||||
(fx/defn fetch-chats-rpc [cofx {:keys [on-success]}]
|
(fx/defn fetch-chats-rpc [cofx {:keys [on-success]}]
|
||||||
{::json-rpc/call [{:method (json-rpc/call-ext-method "chats")
|
{::json-rpc/call [{:method (json-rpc/call-ext-method "activeChats")
|
||||||
:params []
|
:params []
|
||||||
:on-success #(on-success (map <-rpc %))
|
:on-success #(on-success (map <-rpc %))
|
||||||
:on-failure #(log/error "failed to fetch chats" 0 -1 %)}]})
|
:on-failure #(log/error "failed to fetch chats" 0 -1 %)}]})
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
(ns status-im.data-store.mailservers
|
|
||||||
(:require [status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defn mailserver-request-gaps->rpc
|
|
||||||
[{:keys [chat-id] :as gap}]
|
|
||||||
(-> gap
|
|
||||||
(assoc :chatId chat-id)
|
|
||||||
(dissoc :chat-id)))
|
|
||||||
|
|
||||||
(fx/defn load-gaps
|
|
||||||
[cofx chat-id success-fn]
|
|
||||||
{::json-rpc/call [{:method "mailservers_getMailserverRequestGaps"
|
|
||||||
:params [chat-id]
|
|
||||||
:on-success #(let [indexed-gaps (reduce (fn [acc {:keys [id] :as g}]
|
|
||||||
(assoc acc id g))
|
|
||||||
{}
|
|
||||||
%)]
|
|
||||||
(success-fn chat-id indexed-gaps))
|
|
||||||
:on-failure #(log/error "failed to fetch gaps" %)}]})
|
|
||||||
|
|
||||||
(fx/defn save-gaps
|
|
||||||
[cofx gaps]
|
|
||||||
{::json-rpc/call [{:method "mailservers_addMailserverRequestGaps"
|
|
||||||
:params [(map mailserver-request-gaps->rpc gaps)]
|
|
||||||
:on-success #(log/info "saved gaps successfully")
|
|
||||||
:on-failure #(log/error "failed to save gap" %)}]})
|
|
||||||
|
|
||||||
(fx/defn delete-gaps
|
|
||||||
[cofx ids]
|
|
||||||
{::json-rpc/call [{:method "mailservers_deleteMailserverRequestGaps"
|
|
||||||
:params [ids]
|
|
||||||
:on-success #(log/info "deleted gaps successfully")
|
|
||||||
:on-failure #(log/error "failed to delete gap" %)}]})
|
|
||||||
|
|
||||||
(fx/defn delete-gaps-by-chat-id
|
|
||||||
[cofx chat-id]
|
|
||||||
{::json-rpc/call [{:method "mailservers_deleteMailserverRequestGapsByChatID"
|
|
||||||
:params [chat-id]
|
|
||||||
:on-success #(log/info "deleted gaps successfully")
|
|
||||||
:on-failure #(log/error "failed to delete gap" %)}]})
|
|
@ -19,6 +19,7 @@
|
|||||||
(clojure.set/rename-keys {:id :message-id
|
(clojure.set/rename-keys {:id :message-id
|
||||||
:whisperTimestamp :whisper-timestamp
|
:whisperTimestamp :whisper-timestamp
|
||||||
:commandParameters :command-parameters
|
:commandParameters :command-parameters
|
||||||
|
:gapParameters :gap-parameters
|
||||||
:messageType :message-type
|
:messageType :message-type
|
||||||
:localChatId :chat-id
|
:localChatId :chat-id
|
||||||
:communityId :community-id
|
:communityId :community-id
|
||||||
|
@ -36,6 +36,12 @@
|
|||||||
"waku_getSymKey" {}
|
"waku_getSymKey" {}
|
||||||
"waku_markTrustedPeer" {}
|
"waku_markTrustedPeer" {}
|
||||||
"wakuext_post" {}
|
"wakuext_post" {}
|
||||||
|
"wakuext_requestAllHistoricMessages" {}
|
||||||
|
"wakuext_fillGaps" {}
|
||||||
|
"wakuext_syncChatFromSyncedFrom" {}
|
||||||
|
"wakuext_createPublicChat" {}
|
||||||
|
"wakuext_createOneToOneChat" {}
|
||||||
|
"wakuext_createProfileChat" {}
|
||||||
"wakuext_startMessenger" {}
|
"wakuext_startMessenger" {}
|
||||||
"wakuext_sendPairInstallation" {}
|
"wakuext_sendPairInstallation" {}
|
||||||
"wakuext_syncDevices" {}
|
"wakuext_syncDevices" {}
|
||||||
@ -63,6 +69,7 @@
|
|||||||
"wakuext_sendContactUpdate" {}
|
"wakuext_sendContactUpdate" {}
|
||||||
"wakuext_sendContactUpdates" {}
|
"wakuext_sendContactUpdates" {}
|
||||||
"wakuext_chats" {}
|
"wakuext_chats" {}
|
||||||
|
"wakuext_activeChats" {}
|
||||||
"wakuext_addSystemMessages" {}
|
"wakuext_addSystemMessages" {}
|
||||||
"wakuext_deleteMessagesFrom" {}
|
"wakuext_deleteMessagesFrom" {}
|
||||||
"wakuext_deleteMessagesByChatID" {}
|
"wakuext_deleteMessagesByChatID" {}
|
||||||
@ -76,6 +83,8 @@
|
|||||||
"wakuext_muteChat" {}
|
"wakuext_muteChat" {}
|
||||||
"wakuext_unmuteChat" {}
|
"wakuext_unmuteChat" {}
|
||||||
"wakuext_contacts" {}
|
"wakuext_contacts" {}
|
||||||
|
"wakuext_removeContact" {}
|
||||||
|
"wakuext_clearHistory" {}
|
||||||
"wakuext_prepareContent" {}
|
"wakuext_prepareContent" {}
|
||||||
"wakuext_blockContact" {}
|
"wakuext_blockContact" {}
|
||||||
"wakuext_updateMailservers" {}
|
"wakuext_updateMailservers" {}
|
||||||
@ -85,6 +94,7 @@
|
|||||||
"wakuext_getLinkPreviewWhitelist" {}
|
"wakuext_getLinkPreviewWhitelist" {}
|
||||||
"wakuext_getLinkPreviewData" {}
|
"wakuext_getLinkPreviewData" {}
|
||||||
"wakuext_requestCommunityInfoFromMailserver" {}
|
"wakuext_requestCommunityInfoFromMailserver" {}
|
||||||
|
"wakuext_deactivateChat" {}
|
||||||
;;TODO not used anywhere?
|
;;TODO not used anywhere?
|
||||||
"wakuext_deleteChat" {}
|
"wakuext_deleteChat" {}
|
||||||
"wakuext_saveContact" {}
|
"wakuext_saveContact" {}
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
status-im.profile.core
|
status-im.profile.core
|
||||||
status-im.chat.models.images
|
status-im.chat.models.images
|
||||||
status-im.ui.screens.privacy-and-security-settings.events
|
status-im.ui.screens.privacy-and-security-settings.events
|
||||||
status-im.mailserver.topics
|
|
||||||
status-im.multiaccounts.login.core
|
status-im.multiaccounts.login.core
|
||||||
status-im.multiaccounts.logout.core
|
status-im.multiaccounts.logout.core
|
||||||
status-im.multiaccounts.update.core
|
status-im.multiaccounts.update.core
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.chat.models :as models.chat]
|
[status-im.chat.models :as models.chat]
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.group-chats.db :as group-chats.db]
|
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.transport.filters.core :as transport.filters]
|
|
||||||
[status-im.navigation :as navigation]
|
[status-im.navigation :as navigation]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
@ -17,8 +14,13 @@
|
|||||||
{:events [:navigate-chat-updated]}
|
{:events [:navigate-chat-updated]}
|
||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(if (get-in cofx [:db :chats chat-id :is-active])
|
(if (get-in cofx [:db :chats chat-id :is-active])
|
||||||
(models.chat/navigate-to-chat cofx chat-id)
|
(models.chat/navigate-to-chat cofx chat-id)))
|
||||||
(navigation/navigate-to-cofx cofx :home {})))
|
|
||||||
|
(fx/defn handle-chat-removed
|
||||||
|
{:events [:chat-removed]}
|
||||||
|
[_ response]
|
||||||
|
{:dispatch-n [[:sanitize-messages-and-process-response response]
|
||||||
|
[:navigate-to :home]]})
|
||||||
|
|
||||||
(fx/defn handle-chat-update
|
(fx/defn handle-chat-update
|
||||||
{:events [:chat-updated]}
|
{:events [:chat-updated]}
|
||||||
@ -35,21 +37,6 @@
|
|||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
||||||
|
|
||||||
(fx/defn set-up-filter
|
|
||||||
"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 (multiaccounts.model/current-public-key cofx)
|
|
||||||
new-chat (get-in cofx [:db :chats chat-id])
|
|
||||||
members (:members-joined new-chat)]
|
|
||||||
;; If we left the chat do nothing
|
|
||||||
(when-not (and (group-chats.db/joined? my-public-key previous-chat)
|
|
||||||
(not (group-chats.db/joined? my-public-key new-chat)))
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
(transport.filters/upsert-group-chat-topics)
|
|
||||||
(transport.filters/load-members members)))))
|
|
||||||
|
|
||||||
(fx/defn join-chat
|
(fx/defn join-chat
|
||||||
{:events [:group-chats.ui/join-pressed]}
|
{:events [:group-chats.ui/join-pressed]}
|
||||||
[_ chat-id]
|
[_ chat-id]
|
||||||
@ -111,7 +98,7 @@
|
|||||||
{::json-rpc/call [{:method (json-rpc/call-ext-method "leaveGroupChat")
|
{::json-rpc/call [{:method (json-rpc/call-ext-method "leaveGroupChat")
|
||||||
:params [nil chat-id true]
|
:params [nil chat-id true]
|
||||||
:js-response true
|
:js-response true
|
||||||
:on-success #(re-frame/dispatch [:chat-updated %])}]})
|
:on-success #(re-frame/dispatch [:chat-removed %])}]})
|
||||||
|
|
||||||
(fx/defn remove
|
(fx/defn remove
|
||||||
"Remove chat"
|
"Remove chat"
|
||||||
@ -119,9 +106,6 @@
|
|||||||
[cofx chat-id]
|
[cofx chat-id]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(models.chat/deactivate-chat chat-id)
|
(models.chat/deactivate-chat chat-id)
|
||||||
(models.chat/upsert-chat {:chat-id chat-id
|
|
||||||
:is-active false}
|
|
||||||
nil)
|
|
||||||
(navigation/navigate-to-cofx :home {})))
|
(navigation/navigate-to-cofx :home {})))
|
||||||
|
|
||||||
(def not-blank?
|
(def not-blank?
|
||||||
@ -231,4 +215,3 @@
|
|||||||
:on-accept #(do
|
:on-accept #(do
|
||||||
(re-frame/dispatch [:bottom-sheet/hide])
|
(re-frame/dispatch [:bottom-sheet/hide])
|
||||||
(re-frame/dispatch [:group-chats.ui/leave-chat-confirmed chat-id]))}})
|
(re-frame/dispatch [:group-chats.ui/leave-chat-confirmed chat-id]))}})
|
||||||
|
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
(ns ^{:doc "Mailserver events and API"}
|
(ns ^{:doc "Mailserver events and API"}
|
||||||
status-im.mailserver.core
|
status-im.mailserver.core
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[clojure.set :as clojure.set]
|
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[status-im.data-store.mailservers :as data-store.mailservers]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
[status-im.ethereum.json-rpc :as json-rpc]
|
||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.mailserver.constants :as constants]
|
[status-im.mailserver.constants :as constants]
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.node.core :as node]
|
[status-im.node.core :as node]
|
||||||
@ -16,9 +13,6 @@
|
|||||||
[status-im.utils.config :as config]
|
[status-im.utils.config :as config]
|
||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.random :as rand]
|
|
||||||
[status-im.utils.utils :as utils]
|
|
||||||
[status-im.mailserver.topics :as topics]
|
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
;; How do mailserver work ?
|
;; How do mailserver work ?
|
||||||
@ -34,9 +28,6 @@
|
|||||||
;; as soon as the mailserver becomes available
|
;; as soon as the mailserver becomes available
|
||||||
|
|
||||||
|
|
||||||
(def limit (atom constants/default-limit))
|
|
||||||
(def success-counter (atom 0))
|
|
||||||
|
|
||||||
(defn connected? [db id]
|
(defn connected? [db id]
|
||||||
(= (:mailserver/current-id db) id))
|
(= (:mailserver/current-id db) id))
|
||||||
|
|
||||||
@ -77,19 +68,16 @@
|
|||||||
(fetch db preference))
|
(fetch db preference))
|
||||||
preference)))
|
preference)))
|
||||||
|
|
||||||
(defn add-peer! [enode]
|
|
||||||
(status/add-peer enode
|
|
||||||
(handlers/response-handler
|
|
||||||
#(log/debug "mailserver: add-peer success" %)
|
|
||||||
#(log/error "mailserver: add-peer error" %))))
|
|
||||||
|
|
||||||
;; We now wait for a confirmation from the mailserver before marking the message
|
;; We now wait for a confirmation from the mailserver before marking the message
|
||||||
;; as sent.
|
;; as sent.
|
||||||
(defn update-mailservers! [enodes]
|
(defn update-mailservers! [enodes on-success]
|
||||||
(json-rpc/call
|
(json-rpc/call
|
||||||
{:method (json-rpc/call-ext-method "updateMailservers")
|
{:method (json-rpc/call-ext-method "updateMailservers")
|
||||||
:params [enodes]
|
:params [enodes]
|
||||||
:on-success #(log/debug "mailserver: update-mailservers success" %)
|
:on-success #(do
|
||||||
|
(log/debug "mailserver: update-mailservers success" %)
|
||||||
|
(when on-success
|
||||||
|
(on-success)))
|
||||||
:on-error #(log/error "mailserver: update-mailservers error" %)}))
|
:on-error #(log/error "mailserver: update-mailservers error" %)}))
|
||||||
|
|
||||||
(defn remove-peer! [enode]
|
(defn remove-peer! [enode]
|
||||||
@ -104,11 +92,6 @@
|
|||||||
#(log/info "mailserver: remove-peer success" %)
|
#(log/info "mailserver: remove-peer success" %)
|
||||||
#(log/error "mailserver: remove-peer error" %))))))
|
#(log/error "mailserver: remove-peer error" %))))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/add-peer
|
|
||||||
(fn [enode]
|
|
||||||
(add-peer! enode)))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:mailserver/remove-peer
|
:mailserver/remove-peer
|
||||||
(fn [enode]
|
(fn [enode]
|
||||||
@ -116,61 +99,8 @@
|
|||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:mailserver/update-mailservers
|
:mailserver/update-mailservers
|
||||||
(fn [enodes]
|
(fn [[enodes on-success]]
|
||||||
(update-mailservers! enodes)))
|
(update-mailservers! enodes on-success)))
|
||||||
|
|
||||||
(defn decrease-limit []
|
|
||||||
(max constants/min-limit (/ @limit 2)))
|
|
||||||
|
|
||||||
(defn increase-limit []
|
|
||||||
(min constants/max-limit (* @limit 2)))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/set-limit
|
|
||||||
(fn [n]
|
|
||||||
(reset! limit n)))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/increase-limit
|
|
||||||
(fn []
|
|
||||||
(if (>= @success-counter 2)
|
|
||||||
(reset! limit (increase-limit))
|
|
||||||
(swap! success-counter inc))))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/decrease-limit
|
|
||||||
(fn []
|
|
||||||
(reset! limit (decrease-limit))
|
|
||||||
(reset! success-counter 0)))
|
|
||||||
|
|
||||||
(defn mark-trusted-peer! [enode]
|
|
||||||
(json-rpc/call
|
|
||||||
{:method "waku_markTrustedPeer"
|
|
||||||
:params [enode]
|
|
||||||
:on-success
|
|
||||||
#(re-frame/dispatch [:mailserver.callback/mark-trusted-peer-success %])
|
|
||||||
:on-error
|
|
||||||
#(re-frame/dispatch [:mailserver.callback/mark-trusted-peer-error %])}))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/mark-trusted-peer
|
|
||||||
(fn [enode]
|
|
||||||
(mark-trusted-peer! enode)))
|
|
||||||
|
|
||||||
(fx/defn generate-mailserver-symkey
|
|
||||||
[{:keys [db] :as cofx} {:keys [password id] :as mailserver}]
|
|
||||||
(let [current-fleet (node/current-fleet-key db)]
|
|
||||||
{:db (assoc-in db [:mailserver/mailservers current-fleet id
|
|
||||||
:generating-sym-key?]
|
|
||||||
true)
|
|
||||||
:shh/generate-sym-key-from-password
|
|
||||||
{:password password
|
|
||||||
:on-success
|
|
||||||
(fn [_ sym-key-id]
|
|
||||||
(re-frame/dispatch
|
|
||||||
[:mailserver.callback/generate-mailserver-symkey-success
|
|
||||||
mailserver sym-key-id]))
|
|
||||||
:on-error #(log/error "mailserver: get-sym-key error" %)}}))
|
|
||||||
|
|
||||||
(defn registered-peer?
|
(defn registered-peer?
|
||||||
"truthy if the enode is a registered peer"
|
"truthy if the enode is a registered peer"
|
||||||
@ -181,80 +111,28 @@
|
|||||||
(defn update-mailserver-state [db state]
|
(defn update-mailserver-state [db state]
|
||||||
(assoc db :mailserver/state state))
|
(assoc db :mailserver/state state))
|
||||||
|
|
||||||
(fx/defn mark-trusted-peer
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [{:keys [address sym-key-id generating-sym-key?] :as mailserver}
|
|
||||||
(fetch-current db)]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update-mailserver-state db :added)
|
|
||||||
:mailserver/mark-trusted-peer address}
|
|
||||||
(when-not (or sym-key-id generating-sym-key?)
|
|
||||||
(generate-mailserver-symkey mailserver)))))
|
|
||||||
|
|
||||||
(fx/defn add-peer
|
(fx/defn add-peer
|
||||||
[{:keys [db now] :as cofx}]
|
[{:keys [db now] :as cofx}]
|
||||||
(let [{:keys [address sym-key-id generating-sym-key?] :as mailserver}
|
(let [{:keys [address] :as mailserver}
|
||||||
(fetch-current db)]
|
(fetch-current db)]
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db (assoc
|
{:db (assoc
|
||||||
(update-mailserver-state db :connecting)
|
(update-mailserver-state db :connecting)
|
||||||
:mailserver/last-connection-attempt now)
|
:mailserver/last-connection-attempt now)
|
||||||
:mailserver/add-peer address
|
|
||||||
;; Any message sent before this takes effect will not be marked as sent
|
;; Any message sent before this takes effect will not be marked as sent
|
||||||
;; probably we should improve the UX so that is more transparent to the
|
;; probably we should improve the UX so that is more transparent to the
|
||||||
;; user
|
;; user
|
||||||
:mailserver/update-mailservers [address]}
|
:mailserver/update-mailservers [[address]]}))
|
||||||
(when-not (or sym-key-id generating-sym-key?)
|
|
||||||
(generate-mailserver-symkey mailserver)))))
|
|
||||||
|
|
||||||
(defn executing-gap-request?
|
|
||||||
[{:mailserver/keys [current-request fetching-gaps-in-progress]}]
|
|
||||||
(= (get fetching-gaps-in-progress (:chat-id current-request))
|
|
||||||
(select-keys
|
|
||||||
current-request
|
|
||||||
[:from :to :force-to? :topics :chat-id])))
|
|
||||||
|
|
||||||
(fx/defn disconnect-from-mailserver
|
(fx/defn disconnect-from-mailserver
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
(let [{:keys [address]} (fetch-current db)
|
(let [{:keys [address]} (fetch-current db)
|
||||||
{:keys [peers-summary]} db
|
{:keys [peers-summary]} db]
|
||||||
gap-request? (executing-gap-request? db)]
|
{:db (dissoc db :mailserver/current-request :mailserver/fetching-gaps-in-progress)
|
||||||
{:db (cond-> (dissoc db :mailserver/current-request)
|
|
||||||
gap-request?
|
|
||||||
(-> (assoc :mailserver/fetching-gaps-in-progress {})
|
|
||||||
(dissoc :mailserver/planned-gap-requests)))
|
|
||||||
|
|
||||||
:mailserver/remove-peer address}))
|
:mailserver/remove-peer address}))
|
||||||
|
|
||||||
(defn fetch-use-mailservers? [{:keys [db]}]
|
(defn fetch-use-mailservers? [{:keys [db]}]
|
||||||
(get-in db [:multiaccount :use-mailservers?]))
|
(get-in db [:multiaccount :use-mailservers?]))
|
||||||
|
|
||||||
(fx/defn connect-to-mailserver
|
|
||||||
"Add mailserver as a peer using `::add-peer` cofx and generate sym-key when
|
|
||||||
it doesn't exists
|
|
||||||
Peer summary will change and we will receive a signal from status go when
|
|
||||||
this is successful
|
|
||||||
A connection-check is made after `connection timeout` is reached and
|
|
||||||
mailserver-state is changed to error if it is not connected by then
|
|
||||||
No attempt is made if mailserver usage is disabled"
|
|
||||||
{:events [:mailserver.ui/reconnect-mailserver-pressed]}
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [{:keys [address]} (fetch-current db)
|
|
||||||
{:keys [peers-summary]} db
|
|
||||||
use-mailservers? (fetch-use-mailservers? cofx)
|
|
||||||
added? (registered-peer? peers-summary address)
|
|
||||||
gap-request? (executing-gap-request? db)]
|
|
||||||
(when use-mailservers?
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (cond-> (dissoc db :mailserver/current-request)
|
|
||||||
gap-request?
|
|
||||||
(-> (assoc :mailserver/fetching-gaps-in-progress {})
|
|
||||||
(dissoc :mailserver/planned-gap-requests)))}
|
|
||||||
(if added?
|
|
||||||
(mark-trusted-peer)
|
|
||||||
(add-peer))))))
|
|
||||||
|
|
||||||
(defn pool-size [fleet-size]
|
(defn pool-size [fleet-size]
|
||||||
(.ceil js/Math (/ fleet-size 4)))
|
(.ceil js/Math (/ fleet-size 4)))
|
||||||
|
|
||||||
@ -296,6 +174,66 @@
|
|||||||
has-b-failed? -1)))]
|
has-b-failed? -1)))]
|
||||||
(sort sort-fn mailservers)))
|
(sort sort-fn mailservers)))
|
||||||
|
|
||||||
|
(defn get-mailserver-when-ready
|
||||||
|
"return the mailserver if the mailserver is ready"
|
||||||
|
[{:keys [db]}]
|
||||||
|
(let [mailserver (fetch-current db)
|
||||||
|
mailserver-state (:mailserver/state db)]
|
||||||
|
(when (= :connected mailserver-state)
|
||||||
|
mailserver)))
|
||||||
|
|
||||||
|
(fx/defn handle-successful-request
|
||||||
|
{:events [::request-success]}
|
||||||
|
[{:keys [db]} response-js]
|
||||||
|
{:db (dissoc db :mailserver/current-request)})
|
||||||
|
|
||||||
|
(fx/defn process-next-messages-request
|
||||||
|
{:events [::request-messages]}
|
||||||
|
[{:keys [db now] :as cofx}]
|
||||||
|
(when (and
|
||||||
|
(:messenger/started? db)
|
||||||
|
(mobile-network-utils/syncing-allowed? cofx)
|
||||||
|
(fetch-use-mailservers? cofx)
|
||||||
|
(not (:mailserver/current-request db)))
|
||||||
|
(when-let [mailserver (get-mailserver-when-ready cofx)]
|
||||||
|
{:db (assoc db :mailserver/current-request true)
|
||||||
|
::json-rpc/call [{:method "wakuext_requestAllHistoricMessages"
|
||||||
|
:params []
|
||||||
|
:js-response true
|
||||||
|
:on-success #(do
|
||||||
|
(log/info "fetched historical messages")
|
||||||
|
(re-frame/dispatch [::request-success %]))
|
||||||
|
:on-failure #(log/error "failed retrieve historical messages" %)}]})))
|
||||||
|
|
||||||
|
(fx/defn connected-to-mailserver
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [{:keys [address]} (fetch-current db)]
|
||||||
|
(fx/merge
|
||||||
|
cofx
|
||||||
|
{:db (update-mailserver-state db :connected)
|
||||||
|
:mailserver/update-mailservers [[address] #(re-frame/dispatch [::request-messages])]})))
|
||||||
|
|
||||||
|
(fx/defn connect-to-mailserver
|
||||||
|
"Add mailserver as a peer using `::add-peer` cofx and generate sym-key when
|
||||||
|
it doesn't exists
|
||||||
|
Peer summary will change and we will receive a signal from status go when
|
||||||
|
this is successful
|
||||||
|
A connection-check is made after `connection timeout` is reached and
|
||||||
|
mailserver-state is changed to error if it is not connected by then
|
||||||
|
No attempt is made if mailserver usage is disabled"
|
||||||
|
{:events [:mailserver.ui/reconnect-mailserver-pressed]}
|
||||||
|
[{:keys [db] :as cofx}]
|
||||||
|
(let [{:keys [address]} (fetch-current db)
|
||||||
|
{:keys [peers-summary]} db
|
||||||
|
use-mailservers? (fetch-use-mailservers? cofx)
|
||||||
|
added? (registered-peer? peers-summary address)]
|
||||||
|
(when use-mailservers?
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (dissoc db :mailserver/current-request)}
|
||||||
|
(if added?
|
||||||
|
(connected-to-mailserver)
|
||||||
|
(add-peer))))))
|
||||||
|
|
||||||
(fx/defn set-current-mailserver-with-lowest-latency
|
(fx/defn set-current-mailserver-with-lowest-latency
|
||||||
"Picks a random mailserver amongs the ones with the lowest latency
|
"Picks a random mailserver amongs the ones with the lowest latency
|
||||||
The results with error are ignored
|
The results with error are ignored
|
||||||
@ -329,7 +267,7 @@
|
|||||||
(when (:multiaccount db)
|
(when (:multiaccount db)
|
||||||
(if (:mailserver/current-id db)
|
(if (:mailserver/current-id db)
|
||||||
(let [{:keys [peers-summary peers-count]} db
|
(let [{:keys [peers-summary peers-count]} db
|
||||||
{:keys [address sym-key-id] :as mailserver} (fetch-current db)
|
{:keys [address] :as mailserver} (fetch-current db)
|
||||||
mailserver-was-registered? (registered-peer? previous-summary
|
mailserver-was-registered? (registered-peer? previous-summary
|
||||||
address)
|
address)
|
||||||
mailserver-is-registered? (registered-peer? peers-summary
|
mailserver-is-registered? (registered-peer? peers-summary
|
||||||
@ -340,210 +278,19 @@
|
|||||||
(not mailserver-is-registered?))]
|
(not mailserver-is-registered?))]
|
||||||
(cond
|
(cond
|
||||||
mailserver-added?
|
mailserver-added?
|
||||||
(mark-trusted-peer cofx)
|
(connected-to-mailserver cofx)
|
||||||
mailserver-removed?
|
mailserver-removed?
|
||||||
(connect-to-mailserver cofx)))
|
(connect-to-mailserver cofx)))
|
||||||
;; if there is no current mailserver defined
|
;; if there is no current mailserver defined
|
||||||
;; we set it first
|
;; we set it first
|
||||||
(set-current-mailserver cofx))))
|
(set-current-mailserver cofx))))
|
||||||
|
|
||||||
(defn adjust-request-for-transit-time
|
|
||||||
[from]
|
|
||||||
(let [ttl (:ttl whisper-opts)
|
|
||||||
whisper-tolerance (:whisper-drift-tolerance whisper-opts)
|
|
||||||
adjustment (+ whisper-tolerance ttl)
|
|
||||||
adjusted-from (- (max from adjustment) adjustment)]
|
|
||||||
(log/debug "Adjusting mailserver request" "from:" from
|
|
||||||
"adjusted-from:" adjusted-from)
|
|
||||||
adjusted-from))
|
|
||||||
|
|
||||||
(defn chats->never-synced-public-chats [chats]
|
|
||||||
(into {} (filter (fn [[_ v]] (:might-have-join-time-messages? v)) chats)))
|
|
||||||
|
|
||||||
(defn- assoc-topic-chat [chat chats topic]
|
|
||||||
(assoc chats topic chat))
|
|
||||||
|
|
||||||
(defn- reduce-assoc-topic-chat [db chats-map chat-id chat]
|
|
||||||
(let [assoc-topic-chat (partial assoc-topic-chat chat)
|
|
||||||
topics (topics/topics-for-chat db chat-id)]
|
|
||||||
(reduce assoc-topic-chat chats-map topics)))
|
|
||||||
|
|
||||||
(fx/defn handle-request-success
|
(fx/defn handle-request-success
|
||||||
{:events [:mailserver.callback/request-success]}
|
{:events [:mailserver.callback/request-success]}
|
||||||
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
|
[{{:keys [chats] :as db} :db} {:keys [request-id topics]}]
|
||||||
(when (:mailserver/current-request db)
|
(when (:mailserver/current-request db)
|
||||||
(let [by-topic-never-synced-chats
|
|
||||||
(reduce-kv
|
|
||||||
(partial reduce-assoc-topic-chat db)
|
|
||||||
{}
|
|
||||||
(chats->never-synced-public-chats chats))
|
|
||||||
never-synced-chats-in-this-request
|
|
||||||
(select-keys by-topic-never-synced-chats (vec topics))]
|
|
||||||
(if (seq never-synced-chats-in-this-request)
|
|
||||||
{:db
|
|
||||||
(-> db
|
|
||||||
((fn [db]
|
|
||||||
(reduce
|
|
||||||
(fn [db chat]
|
|
||||||
(assoc-in db [:chats (:chat-id chat)
|
|
||||||
:join-time-mail-request-id] request-id))
|
|
||||||
db
|
|
||||||
(vals never-synced-chats-in-this-request))))
|
|
||||||
(assoc-in [:mailserver/current-request :request-id]
|
|
||||||
request-id))}
|
|
||||||
{:db (assoc-in db [:mailserver/current-request :request-id]
|
{:db (assoc-in db [:mailserver/current-request :request-id]
|
||||||
request-id)}))))
|
request-id)}))
|
||||||
|
|
||||||
(defn request-messages!
|
|
||||||
[{:keys [sym-key-id address]}
|
|
||||||
{:keys [topics cursor to from force-to?] :as request}]
|
|
||||||
;; Add some room to from, unless we break day boundaries so that
|
|
||||||
;; messages that have been received after the last request are also fetched
|
|
||||||
(let [actual-from (adjust-request-for-transit-time from)
|
|
||||||
actual-limit (or (:limit request)
|
|
||||||
@limit)]
|
|
||||||
(log/info "mailserver: request-messages for: "
|
|
||||||
" topics " topics
|
|
||||||
" from " actual-from
|
|
||||||
" force-to? " force-to?
|
|
||||||
" to " to
|
|
||||||
" range " (- to from)
|
|
||||||
" cursor " cursor
|
|
||||||
" limit " actual-limit)
|
|
||||||
(json-rpc/call
|
|
||||||
{:method (json-rpc/call-ext-method "requestMessages")
|
|
||||||
:params [(cond-> {:topics topics
|
|
||||||
:mailServerPeer address
|
|
||||||
:symKeyID sym-key-id
|
|
||||||
:timeout constants/request-timeout
|
|
||||||
:limit actual-limit
|
|
||||||
:cursor cursor
|
|
||||||
:from actual-from}
|
|
||||||
force-to?
|
|
||||||
(assoc :to to))]
|
|
||||||
:on-success (fn [request-id]
|
|
||||||
(log/info "mailserver: messages request success for topic "
|
|
||||||
topics "from" from "to" to)
|
|
||||||
(re-frame/dispatch
|
|
||||||
[:mailserver.callback/request-success
|
|
||||||
{:request-id request-id :topics topics}]))
|
|
||||||
:on-error (fn [error]
|
|
||||||
(log/error "mailserver: messages request error for topic "
|
|
||||||
topics ": " error)
|
|
||||||
(utils/set-timeout
|
|
||||||
#(re-frame/dispatch
|
|
||||||
[:mailserver.callback/resend-request {:request-id nil}])
|
|
||||||
constants/backoff-interval-ms))})))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:mailserver/request-messages
|
|
||||||
(fn [{:keys [mailserver request]}]
|
|
||||||
(request-messages! mailserver request)))
|
|
||||||
|
|
||||||
(defn get-mailserver-when-ready
|
|
||||||
"return the mailserver if the mailserver is ready"
|
|
||||||
[{:keys [db]}]
|
|
||||||
(let [{:keys [sym-key-id] :as mailserver} (fetch-current db)
|
|
||||||
mailserver-state (:mailserver/state db)]
|
|
||||||
(when (and (= :connected mailserver-state)
|
|
||||||
sym-key-id)
|
|
||||||
mailserver)))
|
|
||||||
|
|
||||||
(defn topic->request
|
|
||||||
[default-request-to requests-from requests-to]
|
|
||||||
(fn [[topic {:keys [last-request]}]]
|
|
||||||
(let [force-request-from (get requests-from topic)
|
|
||||||
force-request-to (get requests-to topic)]
|
|
||||||
(when (or force-request-from
|
|
||||||
(> default-request-to last-request))
|
|
||||||
(let [from (or force-request-from
|
|
||||||
(max last-request
|
|
||||||
(- default-request-to constants/max-request-range)))
|
|
||||||
to (or force-request-to default-request-to)]
|
|
||||||
{:gap-topics #{topic}
|
|
||||||
:from from
|
|
||||||
:to to
|
|
||||||
:force-to? (not (nil? force-request-to))})))))
|
|
||||||
|
|
||||||
(defn aggregate-requests
|
|
||||||
[acc {:keys [gap-topics from to force-to? gap chat-id]}]
|
|
||||||
(when from
|
|
||||||
(update acc [from to force-to?]
|
|
||||||
(fn [{:keys [topics]}]
|
|
||||||
{:topics ((fnil clojure.set/union #{}) topics gap-topics)
|
|
||||||
:from from
|
|
||||||
:to to
|
|
||||||
;; To is sent to the mailserver only when force-to? is true,
|
|
||||||
;; also we use to calculate when the last-request was sent.
|
|
||||||
:force-to? force-to?
|
|
||||||
:gap gap
|
|
||||||
:chat-id chat-id}))))
|
|
||||||
|
|
||||||
(defn prepare-messages-requests
|
|
||||||
[{{:keys [:mailserver/requests-from
|
|
||||||
:mailserver/requests-to
|
|
||||||
:mailserver/topics
|
|
||||||
:mailserver/planned-gap-requests]} :db}
|
|
||||||
default-request-to]
|
|
||||||
(transduce
|
|
||||||
(keep (topic->request default-request-to requests-from requests-to))
|
|
||||||
(completing aggregate-requests vals)
|
|
||||||
(reduce
|
|
||||||
aggregate-requests
|
|
||||||
{}
|
|
||||||
(vals planned-gap-requests))
|
|
||||||
topics))
|
|
||||||
|
|
||||||
(fx/defn process-next-messages-request
|
|
||||||
[{:keys [db now] :as cofx}]
|
|
||||||
(when (and
|
|
||||||
(:messenger/started? db)
|
|
||||||
(mobile-network-utils/syncing-allowed? cofx)
|
|
||||||
(fetch-use-mailservers? cofx)
|
|
||||||
(not (:mailserver/current-request db)))
|
|
||||||
(when-let [mailserver (get-mailserver-when-ready cofx)]
|
|
||||||
(let [request-to (or (:mailserver/request-to db)
|
|
||||||
(quot now 1000))
|
|
||||||
requests (prepare-messages-requests cofx request-to)]
|
|
||||||
(log/debug "Mailserver: planned requests " requests)
|
|
||||||
(if-let [request (first requests)]
|
|
||||||
{:db (assoc db
|
|
||||||
:mailserver/pending-requests (count requests)
|
|
||||||
:mailserver/current-request request
|
|
||||||
:mailserver/request-to request-to)
|
|
||||||
:mailserver/request-messages {:mailserver mailserver
|
|
||||||
:request request}}
|
|
||||||
{:db (dissoc db
|
|
||||||
:mailserver/pending-requests
|
|
||||||
:mailserver/request-to
|
|
||||||
:mailserver/requests-from
|
|
||||||
:mailserver/requests-to)})))))
|
|
||||||
|
|
||||||
(fx/defn add-mailserver-trusted
|
|
||||||
"the current mailserver has been trusted
|
|
||||||
update mailserver status to `:connected` and request messages
|
|
||||||
if mailserver is ready"
|
|
||||||
{:events [:mailserver.callback/mark-trusted-peer-success]}
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update-mailserver-state db :connected)}
|
|
||||||
(process-next-messages-request)))
|
|
||||||
|
|
||||||
(fx/defn add-mailserver-sym-key
|
|
||||||
"the current mailserver sym-key has been generated
|
|
||||||
add sym-key to the mailserver in app-db and request messages if
|
|
||||||
mailserver is ready"
|
|
||||||
{:events [:mailserver.callback/generate-mailserver-symkey-success]}
|
|
||||||
[{:keys [db] :as cofx} {:keys [id]} sym-key-id]
|
|
||||||
(let [current-fleet (node/current-fleet-key db)]
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db (-> db
|
|
||||||
(assoc-in [:mailserver/mailservers current-fleet id :sym-key-id]
|
|
||||||
sym-key-id)
|
|
||||||
(update-in [:mailserver/mailservers current-fleet id]
|
|
||||||
dissoc :generating-sym-key?))}
|
|
||||||
(process-next-messages-request))))
|
|
||||||
|
|
||||||
(fx/defn update-use-mailservers
|
(fx/defn update-use-mailservers
|
||||||
{:events [:mailserver.ui/use-history-switch-pressed]}
|
{:events [:mailserver.ui/use-history-switch-pressed]}
|
||||||
@ -606,12 +353,12 @@
|
|||||||
(fx/defn check-connection
|
(fx/defn check-connection
|
||||||
"Check connection checks that the connection is successfully connected,
|
"Check connection checks that the connection is successfully connected,
|
||||||
otherwise it will try to change mailserver and connect again"
|
otherwise it will try to change mailserver and connect again"
|
||||||
{:events [:mailserver/check-connection-timeout :mailserver.callback/mark-trusted-peer-error]}
|
{:events [:mailserver/check-connection-timeout]}
|
||||||
[{:keys [db now] :as cofx}]
|
[{:keys [db now] :as cofx}]
|
||||||
;; check if logged into multiaccount
|
;; check if logged into multiaccount
|
||||||
(when (contains? db :multiaccount)
|
(when (contains? db :multiaccount)
|
||||||
(let [last-connection-attempt (:mailserver/last-connection-attempt db)]
|
(let [last-connection-attempt (:mailserver/last-connection-attempt db)]
|
||||||
(when (and (fetch-use-mailservers? cofx)
|
(if (and (fetch-use-mailservers? cofx)
|
||||||
;; We are not connected
|
;; We are not connected
|
||||||
(not= :connected (:mailserver/state db))
|
(not= :connected (:mailserver/state db))
|
||||||
;; We either never tried to connect to this peer
|
;; We either never tried to connect to this peer
|
||||||
@ -619,282 +366,12 @@
|
|||||||
;; Or 30 seconds have passed and no luck
|
;; Or 30 seconds have passed and no luck
|
||||||
(>= (- now last-connection-attempt) (* constants/connection-timeout 3))))
|
(>= (- now last-connection-attempt) (* constants/connection-timeout 3))))
|
||||||
;; Then we change mailserver
|
;; Then we change mailserver
|
||||||
(change-mailserver cofx)))))
|
(change-mailserver cofx)
|
||||||
|
;; Just make sure it's set
|
||||||
(fx/defn reset-request-to
|
(let [{:keys [address] :as mailserver}
|
||||||
[{:keys [db]}]
|
(fetch-current db)]
|
||||||
{:db (dissoc db :mailserver/request-to)})
|
(when address
|
||||||
|
{:mailserver/update-mailservers [[address]]}))))))
|
||||||
(fx/defn remove-gaps
|
|
||||||
[{:keys [db] :as cofx} chat-id]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update db :mailserver/gaps dissoc chat-id)}
|
|
||||||
(data-store.mailservers/delete-gaps-by-chat-id chat-id)))
|
|
||||||
|
|
||||||
(fx/defn remove-range
|
|
||||||
[{:keys [db]} chat-id]
|
|
||||||
{:db (update db :mailserver/ranges dissoc chat-id)
|
|
||||||
::json-rpc/call
|
|
||||||
[{:method "mailservers_deleteChatRequestRange"
|
|
||||||
:params [chat-id]
|
|
||||||
:on-success #(log/debug "deleted chat request range successfully")
|
|
||||||
:on-failure #(log/error "failed to delete chat request range" %)}]})
|
|
||||||
|
|
||||||
(defn update-mailserver-topic
|
|
||||||
[{:keys [last-request] :as config}
|
|
||||||
{:keys [request-to]}]
|
|
||||||
(cond-> config
|
|
||||||
(> request-to last-request)
|
|
||||||
(assoc :last-request request-to)))
|
|
||||||
|
|
||||||
(defn check-existing-gaps
|
|
||||||
[chat-id chat-gaps request]
|
|
||||||
(let [request-from (:from request)
|
|
||||||
request-to (:to request)]
|
|
||||||
(reduce
|
|
||||||
(fn [acc {:keys [from to id] :as gap}]
|
|
||||||
(cond
|
|
||||||
;; F----T
|
|
||||||
;; RF---RT
|
|
||||||
(< to request-from)
|
|
||||||
acc
|
|
||||||
|
|
||||||
;; F----T
|
|
||||||
;; RF---RT
|
|
||||||
(< request-to from)
|
|
||||||
(reduced acc)
|
|
||||||
|
|
||||||
;; F------T
|
|
||||||
;; RF-----RT
|
|
||||||
(and (<= request-from from)
|
|
||||||
(< from request-to to))
|
|
||||||
(let [updated-gap (assoc gap
|
|
||||||
:from request-to
|
|
||||||
:to to)]
|
|
||||||
(reduced
|
|
||||||
(update acc :updated-gaps assoc id updated-gap)))
|
|
||||||
|
|
||||||
;; F------T
|
|
||||||
;; RF----------RT
|
|
||||||
(and (<= request-from from)
|
|
||||||
(<= to request-to))
|
|
||||||
(update acc :deleted-gaps conj (:id gap))
|
|
||||||
|
|
||||||
;; F---------T
|
|
||||||
;; RF-------RT
|
|
||||||
(and (< from request-from to)
|
|
||||||
(<= to request-to))
|
|
||||||
(let [updated-gap (assoc gap
|
|
||||||
:from from
|
|
||||||
:to request-from)]
|
|
||||||
(update acc :updated-gaps assoc id updated-gap))
|
|
||||||
|
|
||||||
;; F---------T
|
|
||||||
;; RF---RT
|
|
||||||
(and (< from request-from)
|
|
||||||
(< request-to to))
|
|
||||||
(reduced
|
|
||||||
(-> acc
|
|
||||||
(update :deleted-gaps conj (:id gap))
|
|
||||||
(update :new-gaps concat [{:chat-id chat-id
|
|
||||||
:from from
|
|
||||||
:to request-from}
|
|
||||||
{:chat-id chat-id
|
|
||||||
:from request-to
|
|
||||||
:to to}])))
|
|
||||||
|
|
||||||
:else acc))
|
|
||||||
{}
|
|
||||||
(sort-by :from (vals chat-gaps)))))
|
|
||||||
|
|
||||||
(defn check-all-gaps
|
|
||||||
[gaps chat-ids request]
|
|
||||||
(transduce
|
|
||||||
(map (fn [chat-id]
|
|
||||||
(let [chat-gaps (get gaps chat-id)]
|
|
||||||
[chat-id (check-existing-gaps chat-id chat-gaps request)])))
|
|
||||||
(completing
|
|
||||||
(fn [acc [chat-id {:keys [new-gaps updated-gaps deleted-gaps]}]]
|
|
||||||
(cond-> acc
|
|
||||||
(seq new-gaps)
|
|
||||||
(assoc-in [:new-gaps chat-id] new-gaps)
|
|
||||||
|
|
||||||
(seq updated-gaps)
|
|
||||||
(assoc-in [:updated-gaps chat-id] updated-gaps)
|
|
||||||
|
|
||||||
(seq deleted-gaps)
|
|
||||||
(assoc-in [:deleted-gaps chat-id] deleted-gaps))))
|
|
||||||
{}
|
|
||||||
chat-ids))
|
|
||||||
|
|
||||||
(fx/defn update-ranges
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [{:keys [topics from to]}
|
|
||||||
(get db :mailserver/current-request)
|
|
||||||
chat-ids (mapcat
|
|
||||||
:chat-ids
|
|
||||||
(-> (:mailserver/topics db)
|
|
||||||
(select-keys topics)
|
|
||||||
vals))
|
|
||||||
ranges (:mailserver/ranges db)
|
|
||||||
updated-ranges (into
|
|
||||||
{}
|
|
||||||
(keep
|
|
||||||
(fn [chat-id]
|
|
||||||
(let [chat-id (str chat-id)
|
|
||||||
{:keys [lowest-request-from
|
|
||||||
highest-request-to]
|
|
||||||
:as range}
|
|
||||||
(get ranges chat-id)]
|
|
||||||
[chat-id
|
|
||||||
(cond-> (assoc range :chat-id chat-id)
|
|
||||||
(or (nil? highest-request-to)
|
|
||||||
(> to highest-request-to))
|
|
||||||
(assoc :highest-request-to to)
|
|
||||||
|
|
||||||
(or (nil? lowest-request-from)
|
|
||||||
(< from lowest-request-from))
|
|
||||||
(assoc :lowest-request-from from))])))
|
|
||||||
chat-ids)]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update db :mailserver/ranges merge updated-ranges)
|
|
||||||
::json-rpc/call
|
|
||||||
[{:method "mailservers_addChatRequestRanges"
|
|
||||||
:params [(vals updated-ranges)]
|
|
||||||
:on-success #()
|
|
||||||
:on-failure
|
|
||||||
#(log/error "failed to save chat request range" %)}]})))
|
|
||||||
|
|
||||||
(defn prepare-new-gaps [new-gaps ranges {:keys [from to]} chat-ids]
|
|
||||||
(into
|
|
||||||
{}
|
|
||||||
(comp
|
|
||||||
(map (fn [chat-id]
|
|
||||||
(let [gaps (get new-gaps chat-id)
|
|
||||||
{:keys [highest-request-to lowest-request-from]}
|
|
||||||
(get ranges chat-id)]
|
|
||||||
[chat-id (cond-> gaps
|
|
||||||
(and
|
|
||||||
(not (nil? highest-request-to))
|
|
||||||
(< highest-request-to from))
|
|
||||||
(conj {:chat-id chat-id
|
|
||||||
:from highest-request-to
|
|
||||||
:to from})
|
|
||||||
(and
|
|
||||||
(not (nil? lowest-request-from))
|
|
||||||
(< to lowest-request-from))
|
|
||||||
(conj {:chat-id chat-id
|
|
||||||
:from to
|
|
||||||
:to lowest-request-from}))])))
|
|
||||||
(keep (fn [[chat-id gaps]]
|
|
||||||
[chat-id
|
|
||||||
(into {}
|
|
||||||
(map (fn [gap]
|
|
||||||
(let [id (rand/guid)]
|
|
||||||
[id (assoc gap :id id)])))
|
|
||||||
gaps)])))
|
|
||||||
chat-ids))
|
|
||||||
|
|
||||||
(fx/defn update-gaps
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [{:keys [topics] :as request} (get db :mailserver/current-request)
|
|
||||||
chat-ids (into #{}
|
|
||||||
(comp
|
|
||||||
(keep #(get-in db [:mailserver/topics %]))
|
|
||||||
(mapcat :chat-ids)
|
|
||||||
(map str))
|
|
||||||
topics)
|
|
||||||
|
|
||||||
{:keys [updated-gaps new-gaps deleted-gaps]}
|
|
||||||
(check-all-gaps (get db :mailserver/gaps) chat-ids request)
|
|
||||||
|
|
||||||
ranges (:mailserver/ranges db)
|
|
||||||
prepared-new-gaps (prepare-new-gaps new-gaps ranges request chat-ids)]
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db
|
|
||||||
(reduce (fn [db chat-id]
|
|
||||||
(let [chats-deleted-gaps (get deleted-gaps chat-id)
|
|
||||||
chats-updated-gaps (merge (get updated-gaps chat-id)
|
|
||||||
(get prepared-new-gaps chat-id))]
|
|
||||||
(update-in db [:mailserver/gaps chat-id]
|
|
||||||
(fn [chat-gaps]
|
|
||||||
(-> (apply dissoc chat-gaps chats-deleted-gaps)
|
|
||||||
(merge chats-updated-gaps))))))
|
|
||||||
db
|
|
||||||
chat-ids)}
|
|
||||||
(data-store.mailservers/delete-gaps (mapcat val deleted-gaps))
|
|
||||||
(data-store.mailservers/save-gaps
|
|
||||||
(concat (mapcat vals (vals updated-gaps))
|
|
||||||
(mapcat vals (vals prepared-new-gaps)))))))
|
|
||||||
|
|
||||||
(fx/defn update-chats-and-gaps
|
|
||||||
[cofx cursor]
|
|
||||||
(when (or (nil? cursor)
|
|
||||||
(and (string? cursor)
|
|
||||||
(clojure.string/blank? cursor)))
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
(update-gaps)
|
|
||||||
(update-ranges))))
|
|
||||||
|
|
||||||
(defn get-updated-mailserver-topics [db requested-topics from to]
|
|
||||||
(into
|
|
||||||
{}
|
|
||||||
(keep (fn [topic]
|
|
||||||
(when-let [config (get-in db [:mailserver/topics topic])]
|
|
||||||
[topic (update-mailserver-topic config
|
|
||||||
{:request-from from
|
|
||||||
:request-to to})])))
|
|
||||||
requested-topics))
|
|
||||||
|
|
||||||
(fx/defn update-mailserver-topics
|
|
||||||
"TODO: add support for cursors
|
|
||||||
if there is a cursor, do not update `last-request`"
|
|
||||||
[{:keys [db now] :as cofx} {:keys [request-id cursor]}]
|
|
||||||
(when-let [request (get db :mailserver/current-request)]
|
|
||||||
(let [{:keys [from to topics]} request
|
|
||||||
mailserver-topics (get-updated-mailserver-topics db topics from to)]
|
|
||||||
(log/info "mailserver: message request " request-id
|
|
||||||
"completed for mailserver topics" topics "from" from "to" to)
|
|
||||||
(if (empty? mailserver-topics)
|
|
||||||
;; when topics were deleted (filter was removed while request was pending)
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (dissoc db :mailserver/current-request)}
|
|
||||||
(process-next-messages-request))
|
|
||||||
;; If a cursor is returned, add cursor and fire request again
|
|
||||||
(if (seq cursor)
|
|
||||||
(when-let [mailserver (get-mailserver-when-ready cofx)]
|
|
||||||
(let [request-with-cursor (assoc request :cursor cursor)]
|
|
||||||
{:db (assoc db :mailserver/current-request request-with-cursor)
|
|
||||||
:mailserver/request-messages {:mailserver mailserver
|
|
||||||
:request request-with-cursor}}))
|
|
||||||
(let [{:keys [gap chat-id]} request]
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db (-> db
|
|
||||||
(dissoc :mailserver/current-request)
|
|
||||||
(update :mailserver/requests-from
|
|
||||||
#(apply dissoc % topics))
|
|
||||||
(update :mailserver/requests-to
|
|
||||||
#(apply dissoc % topics))
|
|
||||||
(update :mailserver/topics merge mailserver-topics)
|
|
||||||
(update :mailserver/fetching-gaps-in-progress
|
|
||||||
(fn [gaps]
|
|
||||||
(if gap
|
|
||||||
(update gaps chat-id dissoc gap)
|
|
||||||
gaps)))
|
|
||||||
(update :mailserver/planned-gap-requests
|
|
||||||
dissoc gap))
|
|
||||||
::json-rpc/call
|
|
||||||
[{:method "mailservers_addMailserverTopics"
|
|
||||||
:params [(mapv (fn [[topic mailserver-topic]]
|
|
||||||
(assoc mailserver-topic :topic topic)) mailserver-topics)]
|
|
||||||
:on-success
|
|
||||||
#(log/debug "added mailserver-topic successfully")
|
|
||||||
:on-failure
|
|
||||||
#(log/error "failed to add mailserver topic" %)}]}
|
|
||||||
(process-next-messages-request))))))))
|
|
||||||
|
|
||||||
(fx/defn retry-next-messages-request
|
(fx/defn retry-next-messages-request
|
||||||
{:events [:mailserver.ui/retry-request-pressed]}
|
{:events [:mailserver.ui/retry-request-pressed]}
|
||||||
@ -907,55 +384,11 @@
|
|||||||
;; on, rather then keep asking for the same data, say after n amounts of attempts
|
;; on, rather then keep asking for the same data, say after n amounts of attempts
|
||||||
(fx/defn handle-request-error
|
(fx/defn handle-request-error
|
||||||
[{:keys [db]} error]
|
[{:keys [db]} error]
|
||||||
{:mailserver/decrease-limit []
|
{:db (-> db
|
||||||
:db (-> db
|
|
||||||
(assoc :mailserver/request-error error)
|
(assoc :mailserver/request-error error)
|
||||||
(dissoc :mailserver/current-request
|
(dissoc :mailserver/current-request
|
||||||
:mailserver/pending-requests))})
|
:mailserver/pending-requests))})
|
||||||
|
|
||||||
(fx/defn handle-request-completed
|
|
||||||
[{{:keys [chats]} :db :as cofx}
|
|
||||||
{:keys [requestID lastEnvelopeHash cursor errorMessage]}]
|
|
||||||
(when (multiaccounts.model/logged-in? cofx)
|
|
||||||
(if (empty? errorMessage)
|
|
||||||
(let [never-synced-chats-in-request
|
|
||||||
(->> (chats->never-synced-public-chats chats)
|
|
||||||
(filter (fn [[k v]] (= requestID (:join-time-mail-request-id v))))
|
|
||||||
keys)]
|
|
||||||
(if (seq never-synced-chats-in-request)
|
|
||||||
(if (= lastEnvelopeHash
|
|
||||||
"0x0000000000000000000000000000000000000000000000000000000000000000")
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:mailserver/increase-limit []
|
|
||||||
:dispatch-n
|
|
||||||
(map
|
|
||||||
#(identity [:chat.ui/join-time-messages-checked %])
|
|
||||||
never-synced-chats-in-request)}
|
|
||||||
(update-chats-and-gaps cursor)
|
|
||||||
(update-mailserver-topics {:request-id requestID
|
|
||||||
:cursor cursor}))
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:mailserver/increase-limit []
|
|
||||||
:dispatch-later
|
|
||||||
(vec
|
|
||||||
(map
|
|
||||||
#(identity
|
|
||||||
{:ms 1000
|
|
||||||
:dispatch [:chat.ui/join-time-messages-checked %]})
|
|
||||||
never-synced-chats-in-request))}
|
|
||||||
(update-chats-and-gaps cursor)
|
|
||||||
(update-mailserver-topics {:request-id requestID
|
|
||||||
:cursor cursor})))
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:mailserver/increase-limit []}
|
|
||||||
(update-chats-and-gaps cursor)
|
|
||||||
(update-mailserver-topics {:request-id requestID
|
|
||||||
:cursor cursor}))))
|
|
||||||
(handle-request-error cofx errorMessage))))
|
|
||||||
|
|
||||||
(fx/defn show-request-error-popup
|
(fx/defn show-request-error-popup
|
||||||
{:events [:mailserver.ui/request-error-pressed]}
|
{:events [:mailserver.ui/request-error-pressed]}
|
||||||
[{:keys [db]}]
|
[{:keys [db]}]
|
||||||
@ -967,87 +400,11 @@
|
|||||||
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
|
:on-accept #(re-frame/dispatch [:mailserver.ui/retry-request-pressed])
|
||||||
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
|
:confirm-button-text (i18n/label :t/mailserver-request-retry)}}))
|
||||||
|
|
||||||
(fx/defn fill-the-gap
|
|
||||||
[{:keys [db] :as cofx} {:keys [gaps topics chat-id]}]
|
|
||||||
(let [mailserver (get-mailserver-when-ready cofx)
|
|
||||||
requests (into {}
|
|
||||||
(map
|
|
||||||
(fn [{:keys [from to id]}]
|
|
||||||
[id
|
|
||||||
{:from (max from
|
|
||||||
(- to constants/max-request-range))
|
|
||||||
:to to
|
|
||||||
:force-to? true
|
|
||||||
:topics topics
|
|
||||||
:gap-topics topics
|
|
||||||
:chat-id chat-id
|
|
||||||
:gap id}]))
|
|
||||||
gaps)
|
|
||||||
first-request (val (first requests))
|
|
||||||
current-request (:mailserver/current-request db)]
|
|
||||||
(cond-> {:db (-> db
|
|
||||||
(assoc :mailserver/planned-gap-requests requests)
|
|
||||||
(update :mailserver/fetching-gaps-in-progress
|
|
||||||
assoc chat-id requests))}
|
|
||||||
(not current-request)
|
|
||||||
(-> (assoc-in [:db :mailserver/current-request] first-request)
|
|
||||||
(assoc :mailserver/request-messages
|
|
||||||
{:mailserver mailserver
|
|
||||||
:request first-request})))))
|
|
||||||
|
|
||||||
(fx/defn resend-request
|
|
||||||
{:events [:mailserver.callback/resend-request]}
|
|
||||||
[{:keys [db] :as cofx} {:keys [request-id]}]
|
|
||||||
(let [current-request (:mailserver/current-request db)
|
|
||||||
gap-request? (executing-gap-request? db)]
|
|
||||||
;; no inflight request, do nothing
|
|
||||||
(when (and current-request
|
|
||||||
;; the request was never successful
|
|
||||||
(or (nil? request-id)
|
|
||||||
;; we haven't received the request-id yet, but has expired,
|
|
||||||
;; so we retry even though we are not sure it's the current
|
|
||||||
;; request that failed
|
|
||||||
(nil? (:request-id current-request))
|
|
||||||
;; this is the same request that we are currently processing
|
|
||||||
(= request-id (:request-id current-request))))
|
|
||||||
|
|
||||||
(if (<= constants/maximum-number-of-attempts
|
|
||||||
(:attempts current-request))
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (update db :mailserver/current-request dissoc :attempts)}
|
|
||||||
(log-mailserver-failure)
|
|
||||||
(change-mailserver))
|
|
||||||
(let [mailserver (get-mailserver-when-ready cofx)
|
|
||||||
offline? (= :offline (:network-status db))]
|
|
||||||
(cond
|
|
||||||
(and gap-request? offline?)
|
|
||||||
{:db (-> db
|
|
||||||
(dissoc :mailserver/current-request)
|
|
||||||
(update :mailserver/fetching-gaps-in-progress
|
|
||||||
dissoc (:chat-id current-request))
|
|
||||||
(dissoc :mailserver/planned-gap-requests))}
|
|
||||||
|
|
||||||
mailserver
|
|
||||||
(let [{:keys [topics from to cursor limit] :as request}
|
|
||||||
current-request]
|
|
||||||
(log/info "mailserver: message request " request-id
|
|
||||||
"expired for mailserver topic" topics "from" from
|
|
||||||
"to" to "cursor" cursor "limit" (decrease-limit))
|
|
||||||
{:db (update-in db [:mailserver/current-request :attempts] inc)
|
|
||||||
:mailserver/decrease-limit []
|
|
||||||
:mailserver/request-messages
|
|
||||||
{:mailserver mailserver
|
|
||||||
:request (assoc request :limit (decrease-limit))}})
|
|
||||||
|
|
||||||
:else
|
|
||||||
{:mailserver/decrease-limit []}))))))
|
|
||||||
|
|
||||||
(fx/defn initialize-mailserver
|
(fx/defn initialize-mailserver
|
||||||
[cofx]
|
[{:keys [db] :as cofx}]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:mailserver/set-limit constants/default-limit}
|
{:db db}
|
||||||
(set-current-mailserver)
|
(set-current-mailserver)
|
||||||
(reset-request-to)
|
|
||||||
(process-next-messages-request)))
|
(process-next-messages-request)))
|
||||||
|
|
||||||
(def enode-address-regex
|
(def enode-address-regex
|
||||||
@ -1256,33 +613,6 @@
|
|||||||
{})
|
{})
|
||||||
(dismiss-connection-error false))))
|
(dismiss-connection-error false))))
|
||||||
|
|
||||||
(fx/defn load-gaps-fx
|
|
||||||
{:events [:load-gaps]}
|
|
||||||
[{:keys [db] :as cofx} chat-id]
|
|
||||||
(when-not (get-in db [:gaps-loaded? chat-id])
|
|
||||||
(let [success-fn #(re-frame/dispatch [::gaps-loaded %1 %2])]
|
|
||||||
(data-store.mailservers/load-gaps cofx chat-id success-fn))))
|
|
||||||
|
|
||||||
(fx/defn load-gaps
|
|
||||||
{:events [::gaps-loaded]}
|
|
||||||
[{:keys [db now] :as cofx} chat-id gaps]
|
|
||||||
(let [now-s (quot now 1000)
|
|
||||||
outdated-gaps
|
|
||||||
(into []
|
|
||||||
(comp (filter #(< (:to %)
|
|
||||||
(- now-s constants/max-gaps-range)))
|
|
||||||
(map :id))
|
|
||||||
(vals gaps))
|
|
||||||
gaps (apply dissoc gaps outdated-gaps)]
|
|
||||||
(fx/merge
|
|
||||||
cofx
|
|
||||||
{:db
|
|
||||||
(-> db
|
|
||||||
(assoc-in [:gaps-loaded? chat-id] true)
|
|
||||||
(assoc-in [:mailserver/gaps chat-id] gaps))}
|
|
||||||
|
|
||||||
(data-store.mailservers/delete-gaps outdated-gaps))))
|
|
||||||
|
|
||||||
(fx/defn mailserver-ui-add-pressed
|
(fx/defn mailserver-ui-add-pressed
|
||||||
{:events [:mailserver.ui/add-pressed]}
|
{:events [:mailserver.ui/add-pressed]}
|
||||||
[{:keys [db] :as cofx}]
|
[{:keys [db] :as cofx}]
|
||||||
|
@ -1,898 +0,0 @@
|
|||||||
(ns status-im.mailserver.core-test
|
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
|
||||||
[clojure.string :as string]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.mailserver.constants :as constants]
|
|
||||||
[status-im.mailserver.core :as mailserver]
|
|
||||||
[status-im.transport.utils :as utils]
|
|
||||||
[status-im.utils.random :as rand]))
|
|
||||||
|
|
||||||
(def enode "enode://08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404")
|
|
||||||
(def enode2 "enode://12d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404")
|
|
||||||
|
|
||||||
(deftest test-extract-enode-id
|
|
||||||
(testing "Get enode id from enode uri"
|
|
||||||
(is (= "08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b"
|
|
||||||
(utils/extract-enode-id enode))))
|
|
||||||
(testing "Get enode id from mailformed enode uri"
|
|
||||||
(is (= ""
|
|
||||||
(utils/extract-enode-id "08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404"))))
|
|
||||||
(testing "Test empty string"
|
|
||||||
(is (= ""
|
|
||||||
(utils/extract-enode-id ""))))
|
|
||||||
(testing "Test nil"
|
|
||||||
(is (= ""
|
|
||||||
(utils/extract-enode-id nil)))))
|
|
||||||
|
|
||||||
(def peers
|
|
||||||
[{:id "08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b"
|
|
||||||
:enode "enode://08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404"
|
|
||||||
:name "StatusIM/v0.9.9-unstable/linux-amd64/go1.9.2"}
|
|
||||||
{:id "0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f"
|
|
||||||
:enode "enode://0f7c65277f916ff4379fe520b875082a56e587eb3ce1c1567d9ff94206bdb05ba167c52272f20f634cd1ebdec5d9dfeb393018bfde1595d8e64a717c8b46692f@203.136.241.111:40404"
|
|
||||||
:name "Geth/v1.7.2-stable/linux-amd64/go1.9.1"}])
|
|
||||||
|
|
||||||
(deftest change-mailserver
|
|
||||||
(testing "we are offline"
|
|
||||||
(testing "it does not change mailserver"
|
|
||||||
(is (not (mailserver/change-mailserver {:db {:multiaccount {:use-mailservers? true}
|
|
||||||
:peers-count 0}})))))
|
|
||||||
(testing "we are online"
|
|
||||||
(testing "there's a preferred mailserver"
|
|
||||||
(testing "it shows the popup"
|
|
||||||
(is (:ui/show-confirmation (mailserver/change-mailserver
|
|
||||||
{:db {:multiaccount {:fleet :staging
|
|
||||||
:use-mailservers? true
|
|
||||||
:pinned-mailservers {:staging "id"}}
|
|
||||||
:peers-count 1}})))))
|
|
||||||
(testing "there's not a preferred mailserver"
|
|
||||||
(testing "it changes the mailserver"
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(get-in
|
|
||||||
(mailserver/change-mailserver
|
|
||||||
{:db {:mailserver/mailservers {:staging {:a "b"}}
|
|
||||||
:multiaccount {:use-mailservers? true
|
|
||||||
:fleet :staging}
|
|
||||||
:peers-count 1}})
|
|
||||||
[::json-rpc/call 0 :method]))))
|
|
||||||
(testing "it does not show the popup"
|
|
||||||
(is (not (:ui/show-confirmation (mailserver/change-mailserver
|
|
||||||
{:db {:multiaccount {:use-mailservers? true}
|
|
||||||
:peers-count 1}}))))))))
|
|
||||||
|
|
||||||
(deftest test-registered-peer?
|
|
||||||
(testing "Peer is registered"
|
|
||||||
(is (mailserver/registered-peer? peers enode)))
|
|
||||||
(testing "Peer is not peers list"
|
|
||||||
(is (not (mailserver/registered-peer? peers enode2))))
|
|
||||||
(testing "Empty peers"
|
|
||||||
(is (not (mailserver/registered-peer? [] enode))))
|
|
||||||
(testing "Empty peer"
|
|
||||||
(is (not (mailserver/registered-peer? peers ""))))
|
|
||||||
(testing "Nil peer"
|
|
||||||
(is (not (mailserver/registered-peer? peers nil)))))
|
|
||||||
|
|
||||||
(def enode-id "1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40")
|
|
||||||
(def password "password")
|
|
||||||
(def host "167.99.209.61:30504")
|
|
||||||
|
|
||||||
(def valid-enode-address (str "enode://" enode-id "@" host))
|
|
||||||
(def valid-enode-url (str "enode://" enode-id ":" password "@" host))
|
|
||||||
|
|
||||||
(deftest valid-enode-address-test
|
|
||||||
(testing "url without password"
|
|
||||||
(let [address "enode://1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40@167.99.209.61:30504"]
|
|
||||||
(is (mailserver/valid-enode-address? address))))
|
|
||||||
(testing "url with password"
|
|
||||||
(let [address "enode://1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40:somepasswordwith@and:@@167.99.209.61:30504"]
|
|
||||||
(is (not (mailserver/valid-enode-address? address)))))
|
|
||||||
(testing "invalid url"
|
|
||||||
(is (not (mailserver/valid-enode-address? "something not valid")))))
|
|
||||||
|
|
||||||
(deftest valid-enode-url-test
|
|
||||||
(testing "url without password"
|
|
||||||
(let [address "enode://1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40@167.99.209.61:30504"]
|
|
||||||
(is (not (mailserver/valid-enode-url? address)))))
|
|
||||||
(testing "url with password"
|
|
||||||
(let [address "enode://1da276e34126e93babf24ec88aac1a7602b4cbb2e11b0961d0ab5e989ca9c261aa7f7c1c85f15550a5f1e5a5ca2305b53b9280cf5894d5ecf7d257b173136d40:somepasswordwith@and:@@167.99.209.61:30504"]
|
|
||||||
(is (mailserver/valid-enode-url? address))))
|
|
||||||
(testing "invalid url"
|
|
||||||
(is (not (mailserver/valid-enode-url? "something not valid")))))
|
|
||||||
|
|
||||||
(deftest address->mailserver
|
|
||||||
(testing "with password"
|
|
||||||
(let [address "enode://some-id:the-password@206.189.56.154:30504"]
|
|
||||||
(is (= {:address "enode://some-id@206.189.56.154:30504"
|
|
||||||
:password "the-password"
|
|
||||||
:user-defined true}
|
|
||||||
(#'status-im.mailserver.core/address->mailserver address)))))
|
|
||||||
(testing "without password"
|
|
||||||
(let [address "enode://some-id@206.189.56.154:30504"]
|
|
||||||
(is (= {:address "enode://some-id@206.189.56.154:30504"
|
|
||||||
:user-defined true}
|
|
||||||
(#'status-im.mailserver.core/address->mailserver address))))))
|
|
||||||
|
|
||||||
(deftest set-input
|
|
||||||
(testing "it validates names"
|
|
||||||
(testing "correct name"
|
|
||||||
(is (= {:db {:mailserver.edit/mailserver {:name {:value "value"
|
|
||||||
:error false}}}}
|
|
||||||
(mailserver/set-input {:db {}} :name "value"))))
|
|
||||||
(testing "blank name"
|
|
||||||
(is (= {:db {:mailserver.edit/mailserver {:name {:value ""
|
|
||||||
:error true}}}}
|
|
||||||
(mailserver/set-input {:db {}} :name "")))))
|
|
||||||
(testing "it validates enodes url"
|
|
||||||
(testing "correct url"
|
|
||||||
(is (= {:db {:mailserver.edit/mailserver {:url {:value valid-enode-url
|
|
||||||
:error false}}}}
|
|
||||||
(mailserver/set-input {:db {}} :url valid-enode-url))))
|
|
||||||
(testing "broken url"
|
|
||||||
(is (= {:db {:mailserver.edit/mailserver {:url {:value "broken"
|
|
||||||
:error true}}}}
|
|
||||||
(mailserver/set-input {:db {}} :url "broken"))))))
|
|
||||||
|
|
||||||
(deftest edit-mailserver
|
|
||||||
(let [db {:mailserver/mailservers
|
|
||||||
{:eth.staging {"a" {:id "a"
|
|
||||||
:address valid-enode-address
|
|
||||||
:password password
|
|
||||||
:name "name"}}}}
|
|
||||||
cofx {:db db}]
|
|
||||||
(testing "when no id is given"
|
|
||||||
(let [actual (mailserver/edit cofx nil)]
|
|
||||||
(testing "it resets :mailserver/manage"
|
|
||||||
(is (= {:id {:value nil
|
|
||||||
:error false}
|
|
||||||
:url {:value ""
|
|
||||||
:error true}
|
|
||||||
:name {:value ""
|
|
||||||
:error true}}
|
|
||||||
(-> actual :db :mailserver.edit/mailserver))))
|
|
||||||
(testing "it navigates to edit-mailserver view"
|
|
||||||
(is (= [:edit-mailserver nil]
|
|
||||||
(:status-im.navigation/navigate-to actual))))))
|
|
||||||
(testing "when an id is given"
|
|
||||||
(testing "when the mailserver is in the list"
|
|
||||||
(let [actual (mailserver/edit cofx "a")]
|
|
||||||
(testing "it populates the fields with the correct values"
|
|
||||||
(is (= {:id {:value "a"
|
|
||||||
:error false}
|
|
||||||
:url {:value valid-enode-url
|
|
||||||
:error false}
|
|
||||||
:name {:value "name"
|
|
||||||
:error false}}
|
|
||||||
(-> actual :db :mailserver.edit/mailserver))))
|
|
||||||
(testing "it navigates to edit-mailserver view"
|
|
||||||
(is (= [:edit-mailserver nil]
|
|
||||||
(:status-im.navigation/navigate-to actual))))))
|
|
||||||
(testing "when the mailserver is not in the list"
|
|
||||||
(let [actual (mailserver/edit cofx "not-existing")]
|
|
||||||
(testing "it populates the fields with the correct values"
|
|
||||||
(is (= {:id {:value nil
|
|
||||||
:error false}
|
|
||||||
:url {:value ""
|
|
||||||
:error true}
|
|
||||||
:name {:value ""
|
|
||||||
:error true}}
|
|
||||||
(-> actual :db :mailserver.edit/mailserver))))
|
|
||||||
(testing "it navigates to edit-mailserver view"
|
|
||||||
(is (= [:edit-mailserver nil]
|
|
||||||
(:status-im.navigation/navigate-to actual)))))))))
|
|
||||||
|
|
||||||
(deftest connected-mailserver
|
|
||||||
(testing "it returns true when set in mailserver/current-id"
|
|
||||||
(let [db {:mailserver/current-id "a"}]
|
|
||||||
(is (mailserver/connected? db "a"))))
|
|
||||||
(testing "it returns false otherwise"
|
|
||||||
(is (not (mailserver/connected? {} "a")))))
|
|
||||||
|
|
||||||
(deftest fetch-mailserver
|
|
||||||
(testing "it fetches the mailserver from the db"
|
|
||||||
(let [db {:mailserver/mailservers {:eth.staging {"a" {:id "a"
|
|
||||||
:name "old-name"
|
|
||||||
:address "enode://old-id:old-password@url:port"}}}}]
|
|
||||||
(is (mailserver/fetch db "a")))))
|
|
||||||
|
|
||||||
(deftest fetch-current-mailserver
|
|
||||||
(testing "it fetches the mailserver from the db with corresponding id"
|
|
||||||
(let [db {:mailserver/current-id "a"
|
|
||||||
:mailserver/mailservers {:eth.staging {"a" {:id "a"
|
|
||||||
:name "old-name"
|
|
||||||
:address "enode://old-id:old-password@url:port"}}}}]
|
|
||||||
(is (mailserver/fetch-current db)))))
|
|
||||||
|
|
||||||
(deftest set-current-mailserver
|
|
||||||
(let [cofx {:db {:mailserver/mailservers {:eth.staging {"a" {}
|
|
||||||
"b" {}
|
|
||||||
"c" {}
|
|
||||||
"d" {}}}}}]
|
|
||||||
(testing "the user has already a preference"
|
|
||||||
(let [cofx (assoc-in cofx
|
|
||||||
[:db :multiaccount]
|
|
||||||
{:pinned-mailservers {:eth.staging "a"}})]
|
|
||||||
(testing "the mailserver exists"
|
|
||||||
(testing "it sets the preferred mailserver"
|
|
||||||
(is (= "a" (-> (mailserver/set-current-mailserver cofx)
|
|
||||||
:db
|
|
||||||
:mailserver/current-id)))))
|
|
||||||
(testing "the mailserver does not exists"
|
|
||||||
(let [cofx (update-in cofx [:db :mailserver/mailservers :eth.staging] dissoc "a")]
|
|
||||||
(testing "look for fastest mailserver"
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/set-current-mailserver cofx)
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method))))))))
|
|
||||||
(testing "the user has not set an explicit preference"
|
|
||||||
(testing "current-id is not set"
|
|
||||||
(testing "it looks for fastest mailserver"
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/set-current-mailserver cofx)
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method)))))
|
|
||||||
(testing "current-id is set"
|
|
||||||
(testing "it looks for fastest mailserver"
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/set-current-mailserver (assoc-in
|
|
||||||
cofx
|
|
||||||
[:db :mailserver/current-id]
|
|
||||||
"b"))
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method)))
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/set-current-mailserver (assoc-in
|
|
||||||
cofx
|
|
||||||
[:db :mailserver/current-id]
|
|
||||||
"d"))
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method)))
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/set-current-mailserver (assoc-in
|
|
||||||
cofx
|
|
||||||
[:db :mailserver/current-id]
|
|
||||||
"non-existing"))
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method))))))))
|
|
||||||
|
|
||||||
(deftest delete-mailserver
|
|
||||||
(testing "the user is not connected to the mailserver"
|
|
||||||
(let [cofx {:random-id-generator (constantly "random-id")
|
|
||||||
:db {:mailserver/mailservers {:eth.staging {"a" {:id "a"
|
|
||||||
:name "old-name"
|
|
||||||
:user-defined true
|
|
||||||
:address "enode://old-id:old-password@url:port"}}}}}
|
|
||||||
actual (mailserver/delete cofx "a")]
|
|
||||||
(testing "it removes the mailserver from the list"
|
|
||||||
(is (not (mailserver/fetch (:db actual) "a"))))
|
|
||||||
(testing "it stores it in the db"
|
|
||||||
(is (= 1 (count (::json-rpc/call actual)))))))
|
|
||||||
(testing "the mailserver is not user-defined"
|
|
||||||
(let [cofx {:random-id-generator (constantly "random-id")
|
|
||||||
:db {:mailserver/mailservers {:eth.staging {"a" {:id "a"
|
|
||||||
:name "old-name"
|
|
||||||
:address "enode://old-id:old-password@url:port"}}}}}
|
|
||||||
actual (mailserver/delete cofx "a")]
|
|
||||||
(testing "it does not delete the mailserver"
|
|
||||||
(is (= {:dispatch [:navigate-back]} actual)))))
|
|
||||||
(testing "the user is connected to the mailserver"
|
|
||||||
(let [cofx {:random-id-generator (constantly "random-id")
|
|
||||||
:db {:mailserver/mailservers {:eth.staging {"a" {:id "a"
|
|
||||||
:name "old-name"
|
|
||||||
:address "enode://old-id:old-password@url:port"}}}}}
|
|
||||||
actual (mailserver/delete cofx "a")]
|
|
||||||
(testing "it does not remove the mailserver from the list"
|
|
||||||
(is (= {:dispatch [:navigate-back]} actual))))))
|
|
||||||
|
|
||||||
(deftest upsert-mailserver
|
|
||||||
(testing "new mailserver"
|
|
||||||
(let [cofx {:random-id-generator (constantly "random-id")
|
|
||||||
:db {:mailserver.edit/mailserver {:name {:value "test-name"}
|
|
||||||
:url {:value valid-enode-url}}
|
|
||||||
|
|
||||||
:mailserver/mailservers {}}}
|
|
||||||
actual (mailserver/upsert cofx)]
|
|
||||||
|
|
||||||
(testing "it adds the enode to mailserver/mailservers"
|
|
||||||
(is (= {:eth.staging {:randomid {:password password
|
|
||||||
:address valid-enode-address
|
|
||||||
:name "test-name"
|
|
||||||
:id :randomid
|
|
||||||
:user-defined true}}}
|
|
||||||
(get-in actual [:db :mailserver/mailservers]))))
|
|
||||||
(testing "it navigates back"
|
|
||||||
(is (= [:navigate-back]
|
|
||||||
(:dispatch actual))))
|
|
||||||
(testing "it stores it in the db"
|
|
||||||
(is (= 1 (count (::json-rpc/call actual)))))))
|
|
||||||
(testing "existing mailserver"
|
|
||||||
(let [new-enode-url (string/replace valid-enode-url "password" "new-password")
|
|
||||||
cofx {:random-id-generator (constantly "random-id")
|
|
||||||
:db {:mailserver.edit/mailserver {:id {:value :a}
|
|
||||||
:name {:value "new-name"}
|
|
||||||
:url {:value new-enode-url}}
|
|
||||||
|
|
||||||
:mailserver/mailservers {:eth.staging {:a {:id :a
|
|
||||||
:name "old-name"
|
|
||||||
:address valid-enode-address}}}}}
|
|
||||||
actual (mailserver/upsert cofx)]
|
|
||||||
(testing "it navigates back"
|
|
||||||
(is (= [:navigate-back]
|
|
||||||
(:dispatch actual))))
|
|
||||||
(testing "it updates the enode to mailserver/mailservers"
|
|
||||||
(is (= {:eth.staging {:a {:password "new-password"
|
|
||||||
:address valid-enode-address
|
|
||||||
:name "new-name"
|
|
||||||
:id :a
|
|
||||||
:user-defined true}}}
|
|
||||||
(get-in actual [:db :mailserver/mailservers]))))
|
|
||||||
(testing "it stores it in the db"
|
|
||||||
(is (= 1 (count (::json-rpc/call actual))))))))
|
|
||||||
|
|
||||||
(defn cofx-fixtures [sym-key registered-peer?]
|
|
||||||
{:db {:mailserver/state :connected
|
|
||||||
:peers-summary (if registered-peer?
|
|
||||||
[{:id "mailserver-id" :enode "enode://mailserver-id@ip"}]
|
|
||||||
[])
|
|
||||||
:multiaccount {:fleet :eth.staging
|
|
||||||
:use-mailservers? true}
|
|
||||||
:mailserver/current-id "mailserver-a"
|
|
||||||
:mailserver/mailservers {:eth.staging {"mailserver-a" {:sym-key-id sym-key
|
|
||||||
:address "enode://mailserver-id@ip"}}}}})
|
|
||||||
|
|
||||||
(defn peers-summary-change-result [sym-key registered-peer? registered-peer-before?]
|
|
||||||
(mailserver/peers-summary-change (cofx-fixtures sym-key
|
|
||||||
registered-peer?)
|
|
||||||
(if registered-peer-before?
|
|
||||||
[{:id "mailserver-id" :enode "enode://mailserver-id@ip"}]
|
|
||||||
[])))
|
|
||||||
|
|
||||||
(deftest test-resend-request
|
|
||||||
(testing "there's no current request"
|
|
||||||
(is (not (mailserver/resend-request {:db {}} {}))))
|
|
||||||
(testing "there's a current request"
|
|
||||||
(testing "it reached the maximum number of attempts"
|
|
||||||
(testing "it changes mailserver"
|
|
||||||
(is (= "mailservers_ping"
|
|
||||||
(-> (mailserver/resend-request
|
|
||||||
{:db {:multiaccount {:use-mailservers? true}
|
|
||||||
:mailserver/current-request
|
|
||||||
{:attempts constants/maximum-number-of-attempts}}}
|
|
||||||
{})
|
|
||||||
::json-rpc/call
|
|
||||||
first
|
|
||||||
:method)))))
|
|
||||||
(testing "it did not reach the maximum number of attempts"
|
|
||||||
(testing "it reached the maximum number of attempts"
|
|
||||||
(testing "it decrease the limit")
|
|
||||||
(is (= {:mailserver/decrease-limit []} (mailserver/resend-request {:db {:mailserver/current-request
|
|
||||||
{}}}
|
|
||||||
{})))))))
|
|
||||||
|
|
||||||
(deftest test-resend-request-request-id
|
|
||||||
(testing "request-id passed is nil"
|
|
||||||
(testing "it resends the request"
|
|
||||||
(is (mailserver/resend-request {:db {:mailserver/current-request {}}} {}))))
|
|
||||||
(testing "request-id is nil in db"
|
|
||||||
(testing "it resends the request"
|
|
||||||
(is (mailserver/resend-request {:db {:mailserver/current-request {}}}
|
|
||||||
{:request-id "a"}))))
|
|
||||||
(testing "request id matches"
|
|
||||||
(testing "it resends the request"
|
|
||||||
(is (mailserver/resend-request {:db {:mailserver/current-request {:request-id "a"}}}
|
|
||||||
{:request-id "a"}))))
|
|
||||||
(testing "request id does not match"
|
|
||||||
(testing "it does not resend the request"
|
|
||||||
(is (not (mailserver/resend-request {:db {:mailserver/current-request {:request-id "a"}}}
|
|
||||||
{:request-id "b"}))))))
|
|
||||||
|
|
||||||
(def cofx-no-pub-topic
|
|
||||||
{:db
|
|
||||||
{:multiaccount {:public-key "me"}
|
|
||||||
:chats
|
|
||||||
{"chat-id-1" {:is-active true
|
|
||||||
:might-have-join-time-messages? true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-1"}
|
|
||||||
"chat-id-2" {:is-active true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-2"}}}})
|
|
||||||
|
|
||||||
(def cofx-single-pub-topic
|
|
||||||
{:db
|
|
||||||
{:multiaccount {:public-key "me"}
|
|
||||||
:chats
|
|
||||||
{"chat-id-1" {:is-active true
|
|
||||||
:join-time-mail-request-id "a"
|
|
||||||
:might-have-join-time-messages? true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-1"}
|
|
||||||
"chat-id-2" {:is-active true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-2"}}}})
|
|
||||||
|
|
||||||
(def cofx-multiple-pub-topic
|
|
||||||
{:db
|
|
||||||
{:multiaccount {:public-key "me"}
|
|
||||||
:chats
|
|
||||||
{"chat-id-1" {:is-active true
|
|
||||||
:join-time-mail-request-id "a"
|
|
||||||
:might-have-join-time-messages? true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-1"}
|
|
||||||
"chat-id-2" {:is-active true
|
|
||||||
:join-time-mail-request-id "a"
|
|
||||||
:might-have-join-time-messages? true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-2"}
|
|
||||||
"chat-id-3" {:is-active true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-3"}
|
|
||||||
"chat-id-4" {:is-active true
|
|
||||||
:join-time-mail-request-id "a"
|
|
||||||
:might-have-join-time-messages? true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id-4"}}}})
|
|
||||||
|
|
||||||
(def mailserver-completed-event
|
|
||||||
{:requestID "a"
|
|
||||||
:lastEnvelopeHash "0xC0FFEE"
|
|
||||||
:cursor ""
|
|
||||||
:errorMessage ""})
|
|
||||||
|
|
||||||
(def mailserver-completed-event-zero-for-envelope
|
|
||||||
{:requestID "a"
|
|
||||||
:lastEnvelopeHash "0x0000000000000000000000000000000000000000000000000000000000000000"
|
|
||||||
:cursor ""
|
|
||||||
:errorMessage ""})
|
|
||||||
|
|
||||||
(deftest test-public-chat-related-handling-of-request-completed
|
|
||||||
(testing "Request does not include any public chat topic"
|
|
||||||
(testing "It does not dispatch any event"
|
|
||||||
(is (not (or (contains?
|
|
||||||
(mailserver/handle-request-completed cofx-no-pub-topic mailserver-completed-event)
|
|
||||||
:dispatch-n)
|
|
||||||
(contains?
|
|
||||||
(mailserver/handle-request-completed cofx-no-pub-topic mailserver-completed-event)
|
|
||||||
:dispatch-later)))))
|
|
||||||
(testing "It has :mailserver/increase-limit effect"
|
|
||||||
(is (contains? (mailserver/handle-request-completed cofx-no-pub-topic mailserver-completed-event)
|
|
||||||
:mailserver/increase-limit))))
|
|
||||||
(testing "Request includes one public chat topic"
|
|
||||||
(testing "Event has non-zero envelope"
|
|
||||||
(let [handeled-effects (mailserver/handle-request-completed
|
|
||||||
cofx-single-pub-topic
|
|
||||||
mailserver-completed-event)]
|
|
||||||
(testing "It has no :dispatch-n event"
|
|
||||||
(is (not (contains?
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n))))
|
|
||||||
(testing "It has one :dispatch-later event"
|
|
||||||
(is (= 1 (count (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later)))))
|
|
||||||
(testing "The :dispatch-later event is :chat.ui/join-time-messages-checked"
|
|
||||||
(is (= :chat.ui/join-time-messages-checked
|
|
||||||
(-> (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later)
|
|
||||||
first
|
|
||||||
:dispatch
|
|
||||||
first))))
|
|
||||||
(testing "The :dispatch-later event argument is the chat-id/topic that the request included"
|
|
||||||
(is (= "chat-id-1"
|
|
||||||
(-> (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later)
|
|
||||||
first
|
|
||||||
:dispatch
|
|
||||||
second))))
|
|
||||||
(testing "It has :mailserver/increase-limit effect"
|
|
||||||
(is (contains? handeled-effects
|
|
||||||
:mailserver/increase-limit)))))
|
|
||||||
(testing "Event has zero-valued envelope"
|
|
||||||
(let [handeled-effects (mailserver/handle-request-completed
|
|
||||||
cofx-single-pub-topic
|
|
||||||
mailserver-completed-event-zero-for-envelope)]
|
|
||||||
(testing "It has one :dispatch-n event"
|
|
||||||
(is (= 1 (count (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n)))))
|
|
||||||
(testing "It has no :dispatch-later event"
|
|
||||||
(is (not (contains?
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later))))
|
|
||||||
(testing "The :dispatch-n event is :chat.ui/join-time-messages-checked"
|
|
||||||
(is (= :chat.ui/join-time-messages-checked
|
|
||||||
(-> (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n)
|
|
||||||
first
|
|
||||||
first))))
|
|
||||||
(testing "The :dispatch-n event argument is the chat-id/topic that the request included"
|
|
||||||
(is (= "chat-id-1"
|
|
||||||
(-> (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n)
|
|
||||||
first
|
|
||||||
second))))
|
|
||||||
(testing "It has :mailserver/increase-limit effect"
|
|
||||||
(is (contains? handeled-effects
|
|
||||||
:mailserver/increase-limit))))))
|
|
||||||
(testing "Request includes multiple public chat topics (3)"
|
|
||||||
(testing "Event has non-zero envelope"
|
|
||||||
(let [handeled-effects (mailserver/handle-request-completed
|
|
||||||
cofx-multiple-pub-topic
|
|
||||||
mailserver-completed-event)]
|
|
||||||
(testing "It has no :dispatch-n event"
|
|
||||||
(is (not (contains?
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n))))
|
|
||||||
(testing "It has one :dispatch-later event"
|
|
||||||
(is (= 3 (count (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later)))))
|
|
||||||
(testing "It has :mailserver/increase-limit effect"
|
|
||||||
(is (contains? handeled-effects
|
|
||||||
:mailserver/increase-limit)))))
|
|
||||||
(testing "Event has zero-valued envelope"
|
|
||||||
(let [handeled-effects (mailserver/handle-request-completed
|
|
||||||
cofx-multiple-pub-topic
|
|
||||||
mailserver-completed-event-zero-for-envelope)]
|
|
||||||
(testing "It has one :dispatch-n event"
|
|
||||||
(is (= 3 (count (get
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-n)))))
|
|
||||||
(testing "It has no :dispatch-later event"
|
|
||||||
(is (not (contains?
|
|
||||||
handeled-effects
|
|
||||||
:dispatch-later))))
|
|
||||||
(testing "It has :mailserver/increase-limit effect"
|
|
||||||
(is (contains? handeled-effects
|
|
||||||
:mailserver/increase-limit)))))))
|
|
||||||
|
|
||||||
(deftest peers-summary-change
|
|
||||||
(testing "Mailserver added, sym-key doesn't exist"
|
|
||||||
(let [result (peers-summary-change-result false true false)]
|
|
||||||
(is (= (into #{} (keys result))
|
|
||||||
#{:mailserver/mark-trusted-peer :shh/generate-sym-key-from-password :db}))))
|
|
||||||
(testing "Mailserver disconnected, sym-key exists"
|
|
||||||
(let [result (peers-summary-change-result true false true)]
|
|
||||||
(is (= (into #{} (keys result))
|
|
||||||
#{:db :mailserver/add-peer :mailserver/update-mailservers}))
|
|
||||||
(is (= (get-in result [:db :mailserver/state])
|
|
||||||
:connecting))))
|
|
||||||
(testing "Mailserver disconnected, sym-key doesn't exists (unlikely situation in practice)"
|
|
||||||
(let [result (peers-summary-change-result false false true)]
|
|
||||||
(is (= (into #{} (keys result))
|
|
||||||
#{:db :mailserver/add-peer :shh/generate-sym-key-from-password :mailserver/update-mailservers}))
|
|
||||||
(is (= (get-in result [:db :mailserver/state])
|
|
||||||
:connecting))))
|
|
||||||
(testing "Mailserver isn't concerned by peer summary changes"
|
|
||||||
(is (= (into #{} (keys (peers-summary-change-result true true true)))
|
|
||||||
#{}))
|
|
||||||
(is (= (into #{} (keys (peers-summary-change-result true false false)))
|
|
||||||
#{}))))
|
|
||||||
|
|
||||||
(deftest unpin-test
|
|
||||||
(testing "it removes the preference"
|
|
||||||
(let [db {:mailserver/current-id "mailserverid"
|
|
||||||
:mailserver/mailservers
|
|
||||||
{:eth.staging {"mailserverid" {:address "mailserver-address"
|
|
||||||
:password "mailserver-password"}}}
|
|
||||||
:multiaccount
|
|
||||||
{:fleet :eth.staging
|
|
||||||
:pinned-mailservers {:eth.staging "mailserverid"}}}]
|
|
||||||
(is (not (get-in (mailserver/unpin {:db db})
|
|
||||||
[:db :multiaccount :pinned-mailservers :eth.staging]))))))
|
|
||||||
|
|
||||||
(deftest pin-test
|
|
||||||
(testing "it removes the preference"
|
|
||||||
(let [db {:mailserver/current-id "mailserverid"
|
|
||||||
:mailserver/mailservers
|
|
||||||
{:eth.staging {"mailserverid" {:address "mailserver-address"
|
|
||||||
:password "mailserver-password"}}}
|
|
||||||
:multiaccount
|
|
||||||
{:fleet :eth.staging
|
|
||||||
:pinned-mailservers {}}}]
|
|
||||||
(is (= "mailserverid" (get-in (mailserver/pin {:db db})
|
|
||||||
[:db :multiaccount :pinned-mailservers :eth.staging]))))))
|
|
||||||
|
|
||||||
(deftest connect-to-mailserver
|
|
||||||
(let [db {:mailserver/current-id "mailserverid"
|
|
||||||
:mailserver/mailservers
|
|
||||||
{:eth.staging {"mailserverid" {:address "mailserver-address"
|
|
||||||
:password "mailserver-password"}}}
|
|
||||||
:multiaccount
|
|
||||||
{:fleet :eth.staging
|
|
||||||
:pinned-mailservers {:eth.staging "mailserverid"}
|
|
||||||
:use-mailservers? true}}]
|
|
||||||
(testing "it adds the peer"
|
|
||||||
(is (= "mailserver-address"
|
|
||||||
(:mailserver/add-peer (mailserver/connect-to-mailserver {:db db})))))
|
|
||||||
(testing "it generates a sym key if hasn't been generated before"
|
|
||||||
(is (= "mailserver-password"
|
|
||||||
(-> (mailserver/connect-to-mailserver {:db db})
|
|
||||||
:shh/generate-sym-key-from-password
|
|
||||||
:password))))
|
|
||||||
(let [mailserver-with-sym-key-db (assoc-in db
|
|
||||||
[:mailserver/mailservers :eth.staging "mailserverid" :sym-key-id]
|
|
||||||
"somesymkeyid")]
|
|
||||||
(testing "it does not generate a sym key if already present"
|
|
||||||
(is (not (-> (mailserver/connect-to-mailserver {:db mailserver-with-sym-key-db})
|
|
||||||
:shh/generate-sym-key-from-password)))))
|
|
||||||
|
|
||||||
(testing "it returns noops when use-mailservers? is false"
|
|
||||||
(let [no-mailservers-cofx {:db (assoc-in db [:multiaccount :use-mailservers?] false)}]
|
|
||||||
(is (= (mailserver/connect-to-mailserver no-mailservers-cofx)
|
|
||||||
nil))))))
|
|
||||||
|
|
||||||
(deftest check-existing-gaps
|
|
||||||
(testing "no gaps"
|
|
||||||
(is (= {}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
nil
|
|
||||||
{:from 1
|
|
||||||
:to 2}))))
|
|
||||||
(testing "request before gaps"
|
|
||||||
(is (= {}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 1
|
|
||||||
:to 2}))))
|
|
||||||
(testing "request between gaps"
|
|
||||||
(is (= {}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 22
|
|
||||||
:to 28}))))
|
|
||||||
(testing "request between gaps"
|
|
||||||
(is (= {}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 22
|
|
||||||
:to 28}))))
|
|
||||||
(testing "request after gaps"
|
|
||||||
(is (= {}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 70
|
|
||||||
:to 80}))))
|
|
||||||
(testing "request covers all gaps"
|
|
||||||
(is (= {:deleted-gaps [:g3 :g2 :g1]}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 10
|
|
||||||
:to 60}))))
|
|
||||||
(testing "request splits gap in two"
|
|
||||||
(is (= {:deleted-gaps [:g1]
|
|
||||||
:new-gaps [{:chat-id :chat-id :from 10 :to 12}
|
|
||||||
{:chat-id :chat-id :from 18 :to 20}]}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 12
|
|
||||||
:to 18}))))
|
|
||||||
(testing "request partially covers one gap #1"
|
|
||||||
(is (= {:updated-gaps {:g1 {:from 15
|
|
||||||
:to 20
|
|
||||||
:id :g1}}}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 8
|
|
||||||
:to 15}))))
|
|
||||||
(testing "request partially covers one gap #2"
|
|
||||||
(is (= {:updated-gaps {:g1 {:from 10
|
|
||||||
:to 15
|
|
||||||
:id :g1}}}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 15
|
|
||||||
:to 25}))))
|
|
||||||
(testing "request partially covers two gaps #2"
|
|
||||||
(is (= {:updated-gaps {:g1 {:from 10
|
|
||||||
:to 15
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 35
|
|
||||||
:to 40
|
|
||||||
:id :g2}}}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 15
|
|
||||||
:to 35}))))
|
|
||||||
(testing "request covers one gap and two other partially"
|
|
||||||
(is (= {:updated-gaps {:g1 {:from 10
|
|
||||||
:to 15
|
|
||||||
:id :g1}
|
|
||||||
:g3 {:from 55
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
:deleted-gaps [:g2]}
|
|
||||||
(mailserver/check-existing-gaps
|
|
||||||
:chat-id
|
|
||||||
{:g1 {:from 10
|
|
||||||
:to 20
|
|
||||||
:id :g1}
|
|
||||||
:g2 {:from 30
|
|
||||||
:to 40
|
|
||||||
:id :g2}
|
|
||||||
:g3 {:from 50
|
|
||||||
:to 60
|
|
||||||
:id :g3}}
|
|
||||||
{:from 15
|
|
||||||
:to 55})))))
|
|
||||||
|
|
||||||
(defn rand-guid []
|
|
||||||
(let [gap-id (atom 0)]
|
|
||||||
(fn []
|
|
||||||
(swap! gap-id inc)
|
|
||||||
(str "gap" @gap-id))))
|
|
||||||
|
|
||||||
(deftest prepare-new-gaps
|
|
||||||
(testing "prepare-new-gaps"
|
|
||||||
(with-redefs [rand/guid (rand-guid)]
|
|
||||||
(is (= {"chat1" {"gap1" {:id "gap1"
|
|
||||||
:chat-id "chat1"
|
|
||||||
:from 20
|
|
||||||
:to 30}}}
|
|
||||||
(mailserver/prepare-new-gaps
|
|
||||||
nil
|
|
||||||
{"chat1"
|
|
||||||
{:chat-id "chat1"
|
|
||||||
:lowest-request-from 10
|
|
||||||
:highest-request-to 20}}
|
|
||||||
{:from 30
|
|
||||||
:to 50}
|
|
||||||
#{"chat1"})))))
|
|
||||||
(testing "prepare-new-gaps request after known range"
|
|
||||||
(with-redefs [rand/guid (rand-guid)]
|
|
||||||
(is (= {"chat1" {"gap1" {:id "gap1"
|
|
||||||
:chat-id "chat1"
|
|
||||||
:from 12
|
|
||||||
:to 14}
|
|
||||||
"gap2" {:chat-id "chat1"
|
|
||||||
:from 20
|
|
||||||
:to 30
|
|
||||||
:id "gap2"}}}
|
|
||||||
(mailserver/prepare-new-gaps
|
|
||||||
{"chat1" [{:chat-id "chat1"
|
|
||||||
:from 12
|
|
||||||
:to 14}]}
|
|
||||||
{"chat1"
|
|
||||||
{:chat-id "chat1"
|
|
||||||
:lowest-request-from 10
|
|
||||||
:highest-request-to 20}}
|
|
||||||
{:from 30
|
|
||||||
:to 50}
|
|
||||||
#{"chat1"})))))
|
|
||||||
(testing "prepare-new-gaps request before known range"
|
|
||||||
(with-redefs [rand/guid (rand-guid)]
|
|
||||||
(is (= {"chat1" {"gap1" {:chat-id "chat1"
|
|
||||||
:from 12
|
|
||||||
:to 14
|
|
||||||
:id "gap1"}
|
|
||||||
"gap2" {:chat-id "chat1"
|
|
||||||
:from 8
|
|
||||||
:to 10
|
|
||||||
:id "gap2"}}}
|
|
||||||
(mailserver/prepare-new-gaps
|
|
||||||
{"chat1" [{:chat-id "chat1"
|
|
||||||
:from 12
|
|
||||||
:to 14}]}
|
|
||||||
{"chat1"
|
|
||||||
{:chat-id "chat1"
|
|
||||||
:lowest-request-from 10
|
|
||||||
:highest-request-to 20}}
|
|
||||||
{:from 2
|
|
||||||
:to 8}
|
|
||||||
#{"chat1"}))))))
|
|
||||||
|
|
||||||
(deftest sort-mailserver-test
|
|
||||||
(testing "it orders them by whether they have failed first and by rtts"
|
|
||||||
(let [now (inc constants/cooloff-period)
|
|
||||||
mailserver-failures {:a 1
|
|
||||||
:b 0}
|
|
||||||
cofx {:now now
|
|
||||||
:db {:mailserver/failures mailserver-failures}}
|
|
||||||
mailserver-pings [{:address :a :rttMs 2}
|
|
||||||
{:address :b :rttMs 3}
|
|
||||||
{:address :d :rttMs 1}
|
|
||||||
{:address :e :rttMs 4}]
|
|
||||||
expected-order [{:address :d :rttMs 1}
|
|
||||||
{:address :b :rttMs 3}
|
|
||||||
{:address :e :rttMs 4}
|
|
||||||
{:address :a :rttMs 2}]]
|
|
||||||
(is (= expected-order (mailserver/sort-mailservers cofx mailserver-pings))))))
|
|
@ -1,171 +0,0 @@
|
|||||||
(ns ^{:doc "Mailserver events and API"}
|
|
||||||
status-im.mailserver.topics
|
|
||||||
(:require [clojure.set :as clojure.set]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.mailserver.constants :as constants]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defn calculate-last-request [{:keys [negotiated?
|
|
||||||
discovery?]}
|
|
||||||
{:keys [previous-last-request
|
|
||||||
now-s]}]
|
|
||||||
;; New topic, if discovery we don't fetch history
|
|
||||||
(if (and (nil? previous-last-request)
|
|
||||||
(or discovery?
|
|
||||||
negotiated?))
|
|
||||||
(- now-s 10)
|
|
||||||
(max previous-last-request
|
|
||||||
(- now-s constants/max-request-range))))
|
|
||||||
|
|
||||||
(fx/defn store [{:keys [db]} {:keys [topic
|
|
||||||
filter-ids
|
|
||||||
chat-ids] :as mailserver-topic}]
|
|
||||||
(if (or (empty? chat-ids)
|
|
||||||
(empty? filter-ids))
|
|
||||||
{:db (update db :mailserver/topics dissoc topic)}
|
|
||||||
{:db (assoc-in db [:mailserver/topics topic] mailserver-topic)}))
|
|
||||||
|
|
||||||
(fx/defn persist [_ {:keys [chat-ids topic filter-ids]
|
|
||||||
:as mailserver-topic}]
|
|
||||||
(if (or (empty? chat-ids)
|
|
||||||
(empty? filter-ids))
|
|
||||||
{::json-rpc/call [{:method "mailservers_deleteMailserverTopic"
|
|
||||||
:params [topic]
|
|
||||||
:on-success #(log/debug "deleted mailserver topic successfully")
|
|
||||||
:on-failure #(log/error "failed to delete mailserver topic" %)}]}
|
|
||||||
{::json-rpc/call [{:method "mailservers_addMailserverTopic"
|
|
||||||
:params [mailserver-topic]
|
|
||||||
:on-success #(log/debug "added mailserver-topic successfully")
|
|
||||||
:on-failure #(log/error "failed to add mailserver topic" %)}]}))
|
|
||||||
|
|
||||||
(defn new-chat-ids? [previous-mailserver-topic new-mailserver-topic]
|
|
||||||
(seq (clojure.set/difference (:chat-ids new-mailserver-topic)
|
|
||||||
(:chat-ids previous-mailserver-topic))))
|
|
||||||
|
|
||||||
(defn merge-topic
|
|
||||||
"Calculate last-request and merge chat-ids keeping the old ones and new ones"
|
|
||||||
[old-mailserver-topic
|
|
||||||
new-mailserver-topic
|
|
||||||
{:keys [now-s]}]
|
|
||||||
(let [last-request (calculate-last-request
|
|
||||||
new-mailserver-topic
|
|
||||||
{:previous-last-request (:last-request old-mailserver-topic)
|
|
||||||
:now-s now-s})]
|
|
||||||
(-> old-mailserver-topic
|
|
||||||
(assoc
|
|
||||||
:topic (:topic new-mailserver-topic)
|
|
||||||
:discovery? (boolean (:discovery? new-mailserver-topic))
|
|
||||||
:negotiated? (boolean (:negotiated? new-mailserver-topic))
|
|
||||||
:last-request last-request)
|
|
||||||
(update :filter-ids
|
|
||||||
clojure.set/union
|
|
||||||
(set (:filter-ids new-mailserver-topic)))
|
|
||||||
(update :chat-ids
|
|
||||||
clojure.set/union
|
|
||||||
(set (:chat-ids new-mailserver-topic))))))
|
|
||||||
|
|
||||||
(fx/defn update-topic [cofx persist? topic]
|
|
||||||
(fx/merge cofx
|
|
||||||
(store topic)
|
|
||||||
(when persist? (persist topic))))
|
|
||||||
|
|
||||||
(fx/defn upsert
|
|
||||||
"if the topic didn't exist
|
|
||||||
create the topic
|
|
||||||
else if chat-id is not in the topic
|
|
||||||
add the chat-id to the topic and reset last-request
|
|
||||||
there was no filter for the chat and messages for that
|
|
||||||
so the whole history for that topic needs to be re-fetched"
|
|
||||||
[{:keys [db now] :as cofx} new-mailserver-topic]
|
|
||||||
(let [old-mailserver-topic (get-in db [:mailserver/topics (:topic new-mailserver-topic)]
|
|
||||||
{:topic (:topic new-mailserver-topic)
|
|
||||||
:filter-ids #{}
|
|
||||||
:chat-ids #{}})]
|
|
||||||
(let [updated-topic (merge-topic old-mailserver-topic
|
|
||||||
new-mailserver-topic
|
|
||||||
{:now-s (quot now 1000)})]
|
|
||||||
(update-topic cofx
|
|
||||||
true
|
|
||||||
updated-topic))))
|
|
||||||
|
|
||||||
(fx/defn upsert-many [cofx mailserver-topics]
|
|
||||||
(apply fx/merge cofx (map upsert mailserver-topics)))
|
|
||||||
|
|
||||||
(fx/defn update-many [cofx mailserver-topics]
|
|
||||||
(apply fx/merge cofx (map (partial update-topic true) mailserver-topics)))
|
|
||||||
|
|
||||||
(fx/defn delete [{:keys [db] :as cofx} {:keys [filter-id]}]
|
|
||||||
(when-let [matching-topics (filter (fn [{:keys [filter-ids] :as topic}]
|
|
||||||
(if (not filter-ids)
|
|
||||||
(do (log/warn "topic not initialized, removing" topic)
|
|
||||||
true)
|
|
||||||
(filter-ids filter-id)))
|
|
||||||
(vals (:mailserver/topics db)))]
|
|
||||||
(update-many cofx (map #(update % :filter-ids disj filter-id) matching-topics))))
|
|
||||||
|
|
||||||
(fx/defn delete-many
|
|
||||||
"Remove filter-ids from any topics and save"
|
|
||||||
[cofx filters]
|
|
||||||
(apply fx/merge cofx (map delete filters)))
|
|
||||||
|
|
||||||
(defn extract-topics
|
|
||||||
"return all the topics for this chat, including discovery topics if specified"
|
|
||||||
[topics chat-id include-discovery?]
|
|
||||||
(reduce-kv
|
|
||||||
(fn [acc topic {:keys [negotiated?
|
|
||||||
discovery?
|
|
||||||
chat-ids]}]
|
|
||||||
(if (or (and (or discovery?
|
|
||||||
negotiated?)
|
|
||||||
include-discovery?)
|
|
||||||
(chat-ids chat-id))
|
|
||||||
(conj acc topic)
|
|
||||||
acc))
|
|
||||||
#{}
|
|
||||||
topics))
|
|
||||||
|
|
||||||
(defn changed-for-group-chat
|
|
||||||
"Returns all the discovery topics, or those topics that have at least one of the members.
|
|
||||||
Returns those topic that had chat-id but the member is not there anymore"
|
|
||||||
[topics chat-id members]
|
|
||||||
(reduce
|
|
||||||
(fn [acc {:keys [chat-ids] :as topic}]
|
|
||||||
(cond (some chat-ids members)
|
|
||||||
(update acc :modified conj
|
|
||||||
(assoc topic
|
|
||||||
:chat-ids #{chat-id}))
|
|
||||||
(and
|
|
||||||
(chat-ids chat-id)
|
|
||||||
(not-any? chat-ids members))
|
|
||||||
(update acc :removed conj
|
|
||||||
(-> topic
|
|
||||||
(assoc :topic (:topic topic))
|
|
||||||
(update :chat-ids disj chat-id)))
|
|
||||||
:else
|
|
||||||
acc))
|
|
||||||
{:modified [] :removed []}
|
|
||||||
topics))
|
|
||||||
|
|
||||||
(fx/defn upsert-group-chat
|
|
||||||
"Based on the members it will upsert a mailserver topic for any discovery topic
|
|
||||||
and any personal topic that is in members. It will also remove the chat-id from any existing topic if not with a member"
|
|
||||||
[{:keys [db] :as cofx} chat-id members]
|
|
||||||
(let [topics (reduce-kv
|
|
||||||
(fn [acc topic-id topic]
|
|
||||||
(conj acc (assoc topic :topic topic-id)))
|
|
||||||
[]
|
|
||||||
(:mailserver/topics db))
|
|
||||||
{:keys [modified
|
|
||||||
removed]} (changed-for-group-chat
|
|
||||||
topics
|
|
||||||
chat-id
|
|
||||||
members)]
|
|
||||||
(fx/merge cofx
|
|
||||||
(upsert-many modified)
|
|
||||||
(update-many removed))))
|
|
||||||
|
|
||||||
(defn topics-for-chat [db chat-id]
|
|
||||||
(extract-topics (:mailserver/topics db)
|
|
||||||
chat-id
|
|
||||||
(not (get-in (:chats db) [chat-id :public?]))))
|
|
@ -1,157 +0,0 @@
|
|||||||
(ns status-im.mailserver.topics-test
|
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
|
||||||
[status-im.mailserver.constants :as c]
|
|
||||||
[status-im.mailserver.topics :as t]))
|
|
||||||
|
|
||||||
(def now-s 100000)
|
|
||||||
|
|
||||||
(deftest test-merge-topic-basic-functionality
|
|
||||||
(testing "a new topic"
|
|
||||||
(let [old-topic {:chat-ids #{}}
|
|
||||||
new-topic {:topic "a"
|
|
||||||
:chat-ids #{"a"}
|
|
||||||
:filter-ids #{"b" "c"}}
|
|
||||||
expected-topic {:last-request (- now-s c/max-request-range)
|
|
||||||
:topic "a"
|
|
||||||
:filter-ids #{"b" "c"}
|
|
||||||
:discovery? false
|
|
||||||
:negotiated? false
|
|
||||||
:chat-ids #{"a"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s})))))
|
|
||||||
(testing "an already existing topic"
|
|
||||||
(let [old-topic {:filter-ids #{"a" "b"}
|
|
||||||
:chat-ids #{"a" "b"}}
|
|
||||||
new-topic {:topic "a"
|
|
||||||
:filter-ids #{"a" "c"}
|
|
||||||
:chat-ids #{"a" "c"}}
|
|
||||||
expected-topic {:last-request (- now-s c/max-request-range)
|
|
||||||
:topic "a"
|
|
||||||
:discovery? false
|
|
||||||
:negotiated? false
|
|
||||||
:filter-ids #{"a" "b" "c"}
|
|
||||||
:chat-ids #{"a" "b" "c"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s}))))))
|
|
||||||
|
|
||||||
(deftest test-merge-topic
|
|
||||||
(testing "previous last request is nil and not discovery"
|
|
||||||
(let [old-topic {:chat-ids #{}}
|
|
||||||
new-topic {:chat-ids #{"a"}}
|
|
||||||
expected-topic {:last-request (- now-s c/max-request-range)
|
|
||||||
:discovery? false
|
|
||||||
:negotiated? false
|
|
||||||
:topic nil
|
|
||||||
:filter-ids nil
|
|
||||||
:chat-ids #{"a"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s})))))
|
|
||||||
(testing "previous last request is nil and discovery"
|
|
||||||
(let [old-topic {:chat-ids #{}}
|
|
||||||
new-topic {:discovery? true
|
|
||||||
:chat-ids #{"a"}}
|
|
||||||
expected-topic {:last-request (- now-s 10)
|
|
||||||
:discovery? true
|
|
||||||
:negotiated? false
|
|
||||||
:topic nil
|
|
||||||
:filter-ids nil
|
|
||||||
:chat-ids #{"a"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s})))))
|
|
||||||
(testing "previous last request is set to less then max range ago"
|
|
||||||
(let [old-last-request (inc (- now-s c/max-request-range))
|
|
||||||
old-topic {:last-request old-last-request
|
|
||||||
:chat-ids #{}}
|
|
||||||
new-topic {:chat-ids #{"a"}}
|
|
||||||
expected-topic {:last-request old-last-request
|
|
||||||
:discovery? false
|
|
||||||
:negotiated? false
|
|
||||||
:topic nil
|
|
||||||
:filter-ids nil
|
|
||||||
:chat-ids #{"a"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s})))))
|
|
||||||
(testing "previous last request is set to less then max range ago"
|
|
||||||
(let [old-last-request (- now-s (* 2 c/max-request-range))
|
|
||||||
old-topic {:last-request old-last-request
|
|
||||||
:chat-ids #{}}
|
|
||||||
new-topic {:chat-ids #{"a"}}
|
|
||||||
expected-topic {:last-request (- now-s c/max-request-range)
|
|
||||||
:discovery? false
|
|
||||||
:negotiated? false
|
|
||||||
:topic nil
|
|
||||||
:filter-ids nil
|
|
||||||
:chat-ids #{"a"}}]
|
|
||||||
(is (= expected-topic
|
|
||||||
(t/merge-topic old-topic new-topic {:now-s now-s}))))))
|
|
||||||
|
|
||||||
(deftest new-chat-ids?
|
|
||||||
(testing "new-chat-ids?"
|
|
||||||
(is (not (t/new-chat-ids? {:chat-ids #{"a" "b" "c"}}
|
|
||||||
{:chat-ids #{"a"}})))
|
|
||||||
(is (t/new-chat-ids? {:chat-ids #{"a" "b"}}
|
|
||||||
{:chat-ids #{"a" "b" "c"}}))))
|
|
||||||
|
|
||||||
(deftest topics-for-chat
|
|
||||||
(testing "a public chat"
|
|
||||||
(testing "the chat is in multiple topics"
|
|
||||||
(is (= #{"a" "b"}
|
|
||||||
(t/topics-for-chat {:chats {"chat-id-1" {:public? true}}
|
|
||||||
:mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}}
|
|
||||||
"b" {:chat-ids #{"chat-id-1"}}
|
|
||||||
"c" {:discovery? true
|
|
||||||
:chat-ids #{"chat-id-2"}}}}
|
|
||||||
"chat-id-1"))))
|
|
||||||
(testing "the chat is not there"
|
|
||||||
(is (= #{}
|
|
||||||
(t/topics-for-chat {:chats {"chat-id-3" {:public? true}}
|
|
||||||
:mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}}
|
|
||||||
"b" {:chat-ids #{"chat-id-1"}}
|
|
||||||
"c" {:discovery? true
|
|
||||||
:chat-ids #{"chat-id-2"}}}}
|
|
||||||
"chat-id-3")))))
|
|
||||||
(testing "a one to one"
|
|
||||||
(is (= #{"a" "c"}
|
|
||||||
(t/topics-for-chat {:mailserver/topics {"a" {:chat-ids #{"chat-id-1" "chat-id-2"}}
|
|
||||||
"b" {:chat-ids #{"chat-id-1"}}
|
|
||||||
"c" {:discovery? true}}}
|
|
||||||
"chat-id-2")))))
|
|
||||||
|
|
||||||
(deftest upsert-group-chat-test
|
|
||||||
(testing "new group chat"
|
|
||||||
(let [expected-topics {:modified [{:topic "2"
|
|
||||||
:chat-ids #{"chat-id"}}
|
|
||||||
{:topic "4"
|
|
||||||
:chat-ids #{"chat-id"}}]
|
|
||||||
:removed []}]
|
|
||||||
(is (= expected-topics
|
|
||||||
(t/changed-for-group-chat [{:topic "1"
|
|
||||||
:discovery? true
|
|
||||||
:chat-ids #{}}
|
|
||||||
{:topic "2"
|
|
||||||
:chat-ids #{"a"}}
|
|
||||||
{:topic "3"
|
|
||||||
:chat-ids #{"b"}}
|
|
||||||
{:topic "4"
|
|
||||||
:chat-ids #{"c"}}]
|
|
||||||
"chat-id"
|
|
||||||
["a" "c"])))))
|
|
||||||
(testing "existing group chat"
|
|
||||||
(let [expected-topics {:modified [{:topic "2"
|
|
||||||
:chat-ids #{"chat-id"}}
|
|
||||||
{:topic "4"
|
|
||||||
:chat-ids #{"chat-id"}}]
|
|
||||||
:removed [{:topic "3"
|
|
||||||
:chat-ids #{"b"}}]}]
|
|
||||||
(is (= expected-topics
|
|
||||||
(t/changed-for-group-chat [{:topic "1"
|
|
||||||
:discovery? true
|
|
||||||
:chat-ids #{}}
|
|
||||||
{:topic "2"
|
|
||||||
:chat-ids #{"a"}}
|
|
||||||
{:topic "3"
|
|
||||||
:chat-ids #{"chat-id" "b"}}
|
|
||||||
{:topic "4"
|
|
||||||
:chat-ids #{"c"}}]
|
|
||||||
"chat-id"
|
|
||||||
["a" "c"]))))))
|
|
@ -35,7 +35,6 @@
|
|||||||
[status-im.chat.models.link-preview :as link-preview]
|
[status-im.chat.models.link-preview :as link-preview]
|
||||||
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
[status-im.utils.mobile-sync :as utils.mobile-sync]
|
||||||
[status-im.async-storage.core :as async-storage]
|
[status-im.async-storage.core :as async-storage]
|
||||||
[status-im.chat.models :as chat.models]
|
|
||||||
[status-im.notifications-center.core :as notifications-center]))
|
[status-im.notifications-center.core :as notifications-center]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
@ -320,9 +319,8 @@
|
|||||||
:dispatch-later [{:ms 2000 :dispatch [::initialize-wallet accounts nil nil (:recovered multiaccount) true]}]}
|
:dispatch-later [{:ms 2000 :dispatch [::initialize-wallet accounts nil nil (:recovered multiaccount) true]}]}
|
||||||
(finish-keycard-setup)
|
(finish-keycard-setup)
|
||||||
(transport/start-messenger)
|
(transport/start-messenger)
|
||||||
|
(chat.loading/initialize-chats)
|
||||||
(communities/fetch)
|
(communities/fetch)
|
||||||
(chat.models/start-timeline-chat)
|
|
||||||
(chat.models/start-profile-chat (:public-key multiaccount))
|
|
||||||
(multiaccounts/switch-preview-privacy-mode-flag)
|
(multiaccounts/switch-preview-privacy-mode-flag)
|
||||||
(link-preview/request-link-preview-whitelist)
|
(link-preview/request-link-preview-whitelist)
|
||||||
(logging/set-log-level (:log-level multiaccount)))))
|
(logging/set-log-level (:log-level multiaccount)))))
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
[status-im.i18n.i18n :as i18n]
|
[status-im.i18n.i18n :as i18n]
|
||||||
[status-im.mailserver.core :as mailserver]
|
[status-im.mailserver.core :as mailserver]
|
||||||
[status-im.multiaccounts.login.core :as login]
|
[status-im.multiaccounts.login.core :as login]
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.transport.filters.core :as transport.filters]
|
|
||||||
[status-im.transport.message.core :as transport.message]
|
[status-im.transport.message.core :as transport.message]
|
||||||
[status-im.notifications.local :as local-notifications]
|
[status-im.notifications.local :as local-notifications]
|
||||||
[status-im.chat.models.message :as models.message]
|
[status-im.chat.models.message :as models.message]
|
||||||
@ -60,13 +58,9 @@
|
|||||||
"envelope.expired" (transport.message/update-envelopes-status cofx (:ids (js->clj event-js :keywordize-keys true)) :not-sent)
|
"envelope.expired" (transport.message/update-envelopes-status cofx (:ids (js->clj event-js :keywordize-keys true)) :not-sent)
|
||||||
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js :keywordize-keys true)]
|
"message.delivered" (let [{:keys [chatID messageID]} (js->clj event-js :keywordize-keys true)]
|
||||||
(models.message/update-db-message-status cofx chatID messageID :delivered))
|
(models.message/update-db-message-status cofx chatID messageID :delivered))
|
||||||
"mailserver.request.completed" (mailserver/handle-request-completed cofx (js->clj event-js :keywordize-keys true))
|
|
||||||
"mailserver.request.expired" (when (multiaccounts.model/logged-in? cofx)
|
|
||||||
(mailserver/resend-request cofx {:request-id (.-hash event-js)}))
|
|
||||||
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
"discovery.summary" (summary cofx (js->clj event-js :keywordize-keys true))
|
||||||
"subscriptions.data" (ethereum.subscriptions/handle-signal cofx (js->clj event-js :keywordize-keys true))
|
"subscriptions.data" (ethereum.subscriptions/handle-signal cofx (js->clj event-js :keywordize-keys true))
|
||||||
"subscriptions.error" (ethereum.subscriptions/handle-error cofx (js->clj event-js :keywordize-keys true))
|
"subscriptions.error" (ethereum.subscriptions/handle-error cofx (js->clj event-js :keywordize-keys true))
|
||||||
"whisper.filter.added" (transport.filters/handle-negotiated-filter cofx (js->clj event-js :keywordize-keys true))
|
|
||||||
"messages.new" (transport.message/sanitize-messages-and-process-response cofx event-js true)
|
"messages.new" (transport.message/sanitize-messages-and-process-response cofx event-js true)
|
||||||
"wallet" (ethereum.subscriptions/new-wallet-event cofx (js->clj event-js :keywordize-keys true))
|
"wallet" (ethereum.subscriptions/new-wallet-event cofx (js->clj event-js :keywordize-keys true))
|
||||||
"local-notifications" (local-notifications/process cofx (js->clj event-js :keywordize-keys true))
|
"local-notifications" (local-notifications/process cofx (js->clj event-js :keywordize-keys true))
|
||||||
|
@ -136,8 +136,6 @@
|
|||||||
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
|
(reg-root-key-sub :mailserver/pending-requests :mailserver/pending-requests)
|
||||||
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
|
(reg-root-key-sub :mailserver/request-error? :mailserver/request-error)
|
||||||
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
|
(reg-root-key-sub :mailserver/fetching-gaps-in-progress :mailserver/fetching-gaps-in-progress)
|
||||||
(reg-root-key-sub :mailserver/gaps :mailserver/gaps)
|
|
||||||
(reg-root-key-sub :mailserver/ranges :mailserver/ranges)
|
|
||||||
|
|
||||||
;;contacts
|
;;contacts
|
||||||
(reg-root-key-sub ::contacts :contacts/contacts)
|
(reg-root-key-sub ::contacts :contacts/contacts)
|
||||||
@ -763,6 +761,20 @@
|
|||||||
(fn [chats [_ chat-id]]
|
(fn [chats [_ chat-id]]
|
||||||
(get chats chat-id)))
|
(get chats chat-id)))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:chats/synced-from
|
||||||
|
(fn [[_ chat-id] _]
|
||||||
|
(re-frame/subscribe [:chat-by-id chat-id]))
|
||||||
|
(fn [{:keys [synced-from]}]
|
||||||
|
synced-from))
|
||||||
|
|
||||||
|
(re-frame/reg-sub
|
||||||
|
:chats/synced-to-and-from
|
||||||
|
(fn [[_ chat-id] _]
|
||||||
|
(re-frame/subscribe [:chat-by-id chat-id]))
|
||||||
|
(fn [chat]
|
||||||
|
(select-keys chat [:synced-to :synced-from])))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chats/current-raw-chat
|
:chats/current-raw-chat
|
||||||
:<- [::chats]
|
:<- [::chats]
|
||||||
@ -826,7 +838,7 @@
|
|||||||
:chats/current-chat-chat-view
|
:chats/current-chat-chat-view
|
||||||
:<- [:chats/current-chat]
|
:<- [:chats/current-chat]
|
||||||
(fn [current-chat]
|
(fn [current-chat]
|
||||||
(select-keys current-chat [:chat-id :show-input? :group-chat :admins :invitation-admin :public? :chat-type :color :chat-name])))
|
(select-keys current-chat [:chat-id :show-input? :group-chat :admins :invitation-admin :public? :chat-type :color :chat-name :synced-to :synced-from])))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:current-chat/metadata
|
:current-chat/metadata
|
||||||
@ -871,24 +883,6 @@
|
|||||||
current-public-key
|
current-public-key
|
||||||
(get-in reactions [chat-id message-id]))))
|
(get-in reactions [chat-id message-id]))))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
:chats/messages-gaps
|
|
||||||
:<- [:mailserver/gaps]
|
|
||||||
(fn [gaps [_ chat-id]]
|
|
||||||
(sort-by :from (vals (get gaps chat-id)))))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
:mailserver/ranges-by-chat-id
|
|
||||||
:<- [:mailserver/ranges]
|
|
||||||
(fn [ranges [_ chat-id]]
|
|
||||||
(get ranges chat-id)))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
:chats/range
|
|
||||||
:<- [:mailserver/ranges]
|
|
||||||
(fn [ranges [_ chat-id]]
|
|
||||||
(get ranges chat-id)))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:mailserver/current-name
|
:mailserver/current-name
|
||||||
:<- [:mailserver/current-id]
|
:<- [:mailserver/current-id]
|
||||||
@ -915,12 +909,6 @@
|
|||||||
(fn [chats [_ chat-id]]
|
(fn [chats [_ chat-id]]
|
||||||
(get-in chats [chat-id :public?])))
|
(get-in chats [chat-id :public?])))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
|
||||||
:chats/might-have-join-time-messages?
|
|
||||||
:<- [::chats]
|
|
||||||
(fn [chats [_ chat-id]]
|
|
||||||
(get-in chats [chat-id :might-have-join-time-messages?])))
|
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chats/message-list
|
:chats/message-list
|
||||||
:<- [::message-lists]
|
:<- [::message-lists]
|
||||||
@ -948,16 +936,18 @@
|
|||||||
(fn [[_ chat-id] _]
|
(fn [[_ chat-id] _]
|
||||||
[(re-frame/subscribe [:chats/message-list chat-id])
|
[(re-frame/subscribe [:chats/message-list chat-id])
|
||||||
(re-frame/subscribe [:chats/chat-messages chat-id])
|
(re-frame/subscribe [:chats/chat-messages chat-id])
|
||||||
(re-frame/subscribe [:chats/messages-gaps chat-id])
|
(re-frame/subscribe [:chats/loading-messages? chat-id])
|
||||||
(re-frame/subscribe [:chats/range chat-id])
|
(re-frame/subscribe [:chats/synced-from chat-id])])
|
||||||
(re-frame/subscribe [:chats/all-loaded? chat-id])
|
(fn [[message-list messages loading-messages? synced-from] [_ chat-id]]
|
||||||
(re-frame/subscribe [:chats/public? chat-id])])
|
|
||||||
(fn [[message-list messages messages-gaps range all-loaded? public?]]
|
|
||||||
;;TODO (perf)
|
;;TODO (perf)
|
||||||
(-> (models.message-list/->seq message-list)
|
(let [message-list-seq (models.message-list/->seq message-list)]
|
||||||
|
; Don't show gaps if that's the case as we are still loading messages
|
||||||
|
(if (and (empty? message-list-seq) loading-messages?)
|
||||||
|
[]
|
||||||
|
(-> message-list-seq
|
||||||
(chat.db/add-datemarks)
|
(chat.db/add-datemarks)
|
||||||
(hydrate-messages messages)
|
(hydrate-messages messages)
|
||||||
(chat.db/add-gaps messages-gaps range all-loaded? public?))))
|
(chat.db/collapse-gaps chat-id synced-from))))))
|
||||||
|
|
||||||
;;we want to keep data unchanged so react doesn't change component when we leave screen
|
;;we want to keep data unchanged so react doesn't change component when we leave screen
|
||||||
(def memo-chat-messages-stream (atom nil))
|
(def memo-chat-messages-stream (atom nil))
|
||||||
@ -2133,8 +2123,8 @@
|
|||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:chats/fetching-gap-in-progress?
|
:chats/fetching-gap-in-progress?
|
||||||
:<- [:mailserver/fetching-gaps-in-progress]
|
:<- [:mailserver/fetching-gaps-in-progress]
|
||||||
(fn [gaps [_ ids chat-id]]
|
(fn [gaps [_ ids _]]
|
||||||
(seq (select-keys (get gaps chat-id) ids))))
|
(seq (select-keys gaps ids))))
|
||||||
|
|
||||||
(re-frame/reg-sub
|
(re-frame/reg-sub
|
||||||
:mailserver/fetching?
|
:mailserver/fetching?
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
[status-im.utils.fx :as fx]
|
[status-im.utils.fx :as fx]
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.publisher :as publisher]
|
[status-im.utils.publisher :as publisher]
|
||||||
[status-im.transport.filters.core :as transport.filters]
|
|
||||||
status-im.transport.shh
|
status-im.transport.shh
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.universal-links.core :as universal-links]))
|
[status-im.utils.universal-links.core :as universal-links]))
|
||||||
@ -49,27 +48,6 @@
|
|||||||
db
|
db
|
||||||
custom-mailservers))
|
custom-mailservers))
|
||||||
|
|
||||||
(defn add-mailserver-topics
|
|
||||||
[db mailserver-topics]
|
|
||||||
(assoc db
|
|
||||||
:mailserver/topics
|
|
||||||
(reduce (fn [acc {:keys [topic]
|
|
||||||
:as mailserver-topic}]
|
|
||||||
(assoc acc topic
|
|
||||||
(update mailserver-topic :chat-ids
|
|
||||||
#(into #{} %))))
|
|
||||||
{}
|
|
||||||
mailserver-topics)))
|
|
||||||
|
|
||||||
(defn add-mailserver-ranges
|
|
||||||
[db mailserver-ranges]
|
|
||||||
(assoc db
|
|
||||||
:mailserver/ranges
|
|
||||||
(reduce (fn [acc {:keys [chat-id] :as range}]
|
|
||||||
(assoc acc chat-id range))
|
|
||||||
{}
|
|
||||||
mailserver-ranges)))
|
|
||||||
|
|
||||||
(fx/defn start-messenger
|
(fx/defn start-messenger
|
||||||
"We should only start receiving messages/processing topics once all the
|
"We should only start receiving messages/processing topics once all the
|
||||||
initializiation is completed, otherwise we might receive messages/topics
|
initializiation is completed, otherwise we might receive messages/topics
|
||||||
@ -81,18 +59,12 @@
|
|||||||
|
|
||||||
(fx/defn messenger-started
|
(fx/defn messenger-started
|
||||||
{:events [::messenger-started]}
|
{:events [::messenger-started]}
|
||||||
[{:keys [db] :as cofx} {:keys [filters
|
[{:keys [db] :as cofx} {:keys [mailservers] :as response}]
|
||||||
mailserverTopics
|
|
||||||
mailservers
|
|
||||||
mailserverRanges] :as response}]
|
|
||||||
(log/info "Messenger started")
|
(log/info "Messenger started")
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc :messenger/started? true)
|
(assoc :messenger/started? true)
|
||||||
(add-mailserver-ranges mailserverRanges)
|
|
||||||
(add-mailserver-topics mailserverTopics)
|
|
||||||
(add-custom-mailservers mailservers))}
|
(add-custom-mailservers mailservers))}
|
||||||
(transport.filters/handle-loaded-filters filters)
|
|
||||||
(fetch-node-info-fx)
|
(fetch-node-info-fx)
|
||||||
(pairing/init)
|
(pairing/init)
|
||||||
(publisher/start-fx)
|
(publisher/start-fx)
|
||||||
|
@ -1,350 +0,0 @@
|
|||||||
(ns status-im.transport.filters.core
|
|
||||||
"This namespace is used to handle filters loading and unloading from statusgo"
|
|
||||||
(:require [clojure.string :as string]
|
|
||||||
[re-frame.core :as re-frame]
|
|
||||||
[status-im.constants :as constants]
|
|
||||||
[status-im.contact.db :as contact.db]
|
|
||||||
[status-im.ethereum.json-rpc :as json-rpc]
|
|
||||||
[status-im.mailserver.core :as mailserver]
|
|
||||||
[status-im.mailserver.topics :as mailserver.topics]
|
|
||||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defn is-public-key? [k]
|
|
||||||
(and
|
|
||||||
(string? k)
|
|
||||||
(string/starts-with? k "0x")))
|
|
||||||
|
|
||||||
(defn load-filters-rpc [chats on-success on-failure]
|
|
||||||
(json-rpc/call {:method (json-rpc/call-ext-method "loadFilters")
|
|
||||||
:params [chats]
|
|
||||||
:on-success on-success
|
|
||||||
:on-failure on-failure}))
|
|
||||||
|
|
||||||
(defn remove-filters-rpc [chats on-success on-failure]
|
|
||||||
(json-rpc/call {:method (json-rpc/call-ext-method "removeFilters")
|
|
||||||
:params [chats]
|
|
||||||
:on-success on-success
|
|
||||||
:on-failure on-failure}))
|
|
||||||
|
|
||||||
;; fx functions
|
|
||||||
|
|
||||||
(defn load-filter-fx [filters]
|
|
||||||
{:filters/load-filters [[filters]]})
|
|
||||||
|
|
||||||
(defn remove-filter-fx [filters]
|
|
||||||
(when (seq filters)
|
|
||||||
{:filters/remove-filters [filters]}))
|
|
||||||
|
|
||||||
;; dispatches
|
|
||||||
|
|
||||||
(defn filters-added! [filters]
|
|
||||||
(re-frame/dispatch [:filters.callback/filters-added filters]))
|
|
||||||
|
|
||||||
(defn filters-removed! [filters]
|
|
||||||
(re-frame/dispatch [:filters.callback/filters-removed filters]))
|
|
||||||
|
|
||||||
;; Mailserver topics
|
|
||||||
|
|
||||||
(fx/defn upsert-mailserver-topic
|
|
||||||
"Update the topics with the newly created filter"
|
|
||||||
[cofx {:keys [discovery?
|
|
||||||
negotiated?
|
|
||||||
filter-id
|
|
||||||
topic
|
|
||||||
chat-id
|
|
||||||
filter]}]
|
|
||||||
(mailserver.topics/upsert cofx {:topic topic
|
|
||||||
:negotiated? negotiated?
|
|
||||||
:filter-ids #{filter-id}
|
|
||||||
:discovery? discovery?
|
|
||||||
:chat-ids #{chat-id}}))
|
|
||||||
|
|
||||||
;; Every time we load a filter, we want to update group chats where the user is a member, has it might be a negotiated filter, so should be included in the request topics
|
|
||||||
(fx/defn upsert-group-chat-topics
|
|
||||||
"Update topics for each member of the group chat"
|
|
||||||
[{:keys [db] :as cofx}]
|
|
||||||
(let [group-chats (filter (fn [{:keys [chat-type]}]
|
|
||||||
(= chat-type constants/private-group-chat-type))
|
|
||||||
(vals (:chats db)))]
|
|
||||||
(apply fx/merge
|
|
||||||
cofx
|
|
||||||
(map
|
|
||||||
#(mailserver.topics/upsert-group-chat (:chat-id %) (:members-joined %))
|
|
||||||
group-chats))))
|
|
||||||
|
|
||||||
;; Filter db
|
|
||||||
|
|
||||||
|
|
||||||
;; We use two structures for filters:
|
|
||||||
;; filter/filters -> {"filter-id" filter} which is just a map of filters indexed by filte-id
|
|
||||||
;; filter/chat-ids -> which is a set of loaded chat-ids, which is set everytime we load
|
|
||||||
;; a non negotiated filter for a chat.
|
|
||||||
|
|
||||||
(defn loaded?
|
|
||||||
"Given a filter, check if we already loaded it"
|
|
||||||
[db {:keys [filter-id]}]
|
|
||||||
(get-in db [:filter/filters filter-id]))
|
|
||||||
|
|
||||||
(def not-loaded?
|
|
||||||
(complement loaded?))
|
|
||||||
|
|
||||||
(defn chat-loaded?
|
|
||||||
[db chat-id]
|
|
||||||
(get-in db [:filter/chat-ids chat-id]))
|
|
||||||
|
|
||||||
(defn new-filters? [db filters]
|
|
||||||
(some
|
|
||||||
(partial not-loaded? db)
|
|
||||||
filters))
|
|
||||||
|
|
||||||
(fx/defn set-raw-filter
|
|
||||||
"Update filter ids cached and set filter in the db"
|
|
||||||
[{:keys [db]} {:keys [chat-id negotiated? filter-id] :as filter}]
|
|
||||||
{:db (cond-> (assoc-in db [:filter/filters filter-id] filter)
|
|
||||||
;; We only set non negotiated filters as negotiated filters are not to
|
|
||||||
;; be removed
|
|
||||||
(not negotiated?)
|
|
||||||
(update :filter/chat-ids (fnil conj #{}) chat-id))})
|
|
||||||
|
|
||||||
(fx/defn unset-raw-filter
|
|
||||||
"Remove filter from db and from chat-id"
|
|
||||||
[{:keys [db]} {:keys [chat-id filter-id]}]
|
|
||||||
{:db (-> db
|
|
||||||
(update :filter/chat-ids disj chat-id)
|
|
||||||
(update :filter/filters dissoc filter-id))})
|
|
||||||
|
|
||||||
(fx/defn add-filter-to-db
|
|
||||||
"Set the filter in the db and upsert a mailserver topic"
|
|
||||||
[{:keys [db] :as cofx} filter]
|
|
||||||
(when (and (not (loaded? db filter))
|
|
||||||
(not (:ephemeral? filter))
|
|
||||||
(:listen? filter))
|
|
||||||
(fx/merge cofx
|
|
||||||
(set-raw-filter filter)
|
|
||||||
(upsert-mailserver-topic filter))))
|
|
||||||
|
|
||||||
(fx/defn remove-filter-from-db
|
|
||||||
"Remve the filter from the db"
|
|
||||||
[cofx filter]
|
|
||||||
(fx/merge cofx
|
|
||||||
(unset-raw-filter filter)))
|
|
||||||
|
|
||||||
(fx/defn add-filters-to-db [cofx filters]
|
|
||||||
(apply fx/merge cofx (map add-filter-to-db filters)))
|
|
||||||
|
|
||||||
(fx/defn remove-filters-from-db [cofx filters]
|
|
||||||
(apply fx/merge cofx (map remove-filter-from-db filters)))
|
|
||||||
|
|
||||||
(defn non-negotiated-filters-for-chat-id
|
|
||||||
"Returns all the non-negotiated filters matching chat-id"
|
|
||||||
[db chat-id]
|
|
||||||
(filter
|
|
||||||
(fn [{:keys [negotiated?] :as f}]
|
|
||||||
(and (= chat-id
|
|
||||||
(:chat-id f))
|
|
||||||
(not negotiated?)))
|
|
||||||
(vals (:filter/filters db))))
|
|
||||||
|
|
||||||
;; Filter requests
|
|
||||||
|
|
||||||
(defn- ->remove-filter-request
|
|
||||||
[{:keys [id filter-id]}]
|
|
||||||
{:chatId id
|
|
||||||
:filterId filter-id})
|
|
||||||
|
|
||||||
(defn- ->filter-request
|
|
||||||
"Transform input in a filter-request. For a group chat we need a filter-request
|
|
||||||
for each member."
|
|
||||||
[{:keys [chat-id
|
|
||||||
group-chat
|
|
||||||
members-joined
|
|
||||||
timeline?
|
|
||||||
public?]}]
|
|
||||||
(cond
|
|
||||||
;;ignore timeline chats
|
|
||||||
timeline?
|
|
||||||
nil
|
|
||||||
(not group-chat)
|
|
||||||
;; Some legacy one-to-one chats (bots), have not a public key for id, we exclude those
|
|
||||||
(when (is-public-key? chat-id)
|
|
||||||
[{:ChatID chat-id
|
|
||||||
:OneToOne true
|
|
||||||
:Identity (subs chat-id 2)}])
|
|
||||||
public?
|
|
||||||
[{:ChatID chat-id
|
|
||||||
:OneToOne false}]
|
|
||||||
:else
|
|
||||||
(mapcat #(->filter-request {:chat-id %}) members-joined)))
|
|
||||||
|
|
||||||
(defn- chats->filter-requests
|
|
||||||
"Convert a list of active chats to filter requests"
|
|
||||||
[chats]
|
|
||||||
(->> chats
|
|
||||||
(filter :is-active)
|
|
||||||
(mapcat ->filter-request)))
|
|
||||||
|
|
||||||
(defn- contacts->filter-requests
|
|
||||||
"Convert added contacts to filter requests"
|
|
||||||
[contacts]
|
|
||||||
(->> contacts
|
|
||||||
(filter contact.db/added?)
|
|
||||||
(map #(hash-map :chat-id (:public-key %)))
|
|
||||||
(mapcat ->filter-request)))
|
|
||||||
|
|
||||||
;; shh filters
|
|
||||||
|
|
||||||
(defn responses->filters [{:keys [negotiated
|
|
||||||
discovery
|
|
||||||
filterId
|
|
||||||
chatId
|
|
||||||
listen
|
|
||||||
ephemeral
|
|
||||||
topic
|
|
||||||
identity]}]
|
|
||||||
{:chat-id (if (not= identity "") (str "0x" identity) chatId)
|
|
||||||
:id chatId
|
|
||||||
:filter-id filterId
|
|
||||||
:negotiated? negotiated
|
|
||||||
:ephemeral? ephemeral
|
|
||||||
:listen? listen
|
|
||||||
:discovery? discovery
|
|
||||||
:topic topic})
|
|
||||||
|
|
||||||
(defn messenger-started? [db]
|
|
||||||
(:messenger/started? db))
|
|
||||||
|
|
||||||
(fx/defn handle-filters-added
|
|
||||||
"Called every time we load a filter from statusgo, either from explicit call
|
|
||||||
or through signals. It stores the filter in the db and upsert the relevant
|
|
||||||
mailserver topics."
|
|
||||||
{:events [:filters.callback/filters-added]}
|
|
||||||
[{:keys [db] :as cofx} filters]
|
|
||||||
(fx/merge cofx
|
|
||||||
(mailserver/reset-request-to)
|
|
||||||
(add-filters-to-db filters)
|
|
||||||
(upsert-group-chat-topics)
|
|
||||||
(when (new-filters? db filters)
|
|
||||||
(mailserver/process-next-messages-request))))
|
|
||||||
|
|
||||||
(fx/defn handle-filters [cofx filters]
|
|
||||||
(handle-filters-added cofx (map responses->filters filters)))
|
|
||||||
|
|
||||||
(fx/defn handle-loaded-filter [cofx filter]
|
|
||||||
(when (and (not (:ephemeral? filter))
|
|
||||||
(:listen? filter))
|
|
||||||
(set-raw-filter cofx filter)))
|
|
||||||
|
|
||||||
(fx/defn handle-loaded-filters [cofx filters]
|
|
||||||
(let [processed-filters (map responses->filters filters)]
|
|
||||||
(apply fx/merge cofx (map handle-loaded-filter processed-filters))))
|
|
||||||
|
|
||||||
(fx/defn handle-filters-removed
|
|
||||||
"Called when we remove a filter from status-go, it will update the mailserver
|
|
||||||
topics"
|
|
||||||
{:events [:filters.callback/filters-removed]}
|
|
||||||
[cofx filters]
|
|
||||||
(fx/merge cofx
|
|
||||||
(remove-filters-from-db filters)
|
|
||||||
(mailserver.topics/delete-many filters)
|
|
||||||
(mailserver/process-next-messages-request)))
|
|
||||||
|
|
||||||
;; Public functions
|
|
||||||
|
|
||||||
(fx/defn handle-negotiated-filter
|
|
||||||
"Check if it's a new filter, if so create an shh filter and process it"
|
|
||||||
[{:keys [db] :as cofx} {:keys [filters]}]
|
|
||||||
(let [processed-filters (map #(responses->filters (assoc % :negotiated true)) filters)
|
|
||||||
new-filters (filter
|
|
||||||
(partial not-loaded? db)
|
|
||||||
processed-filters)]
|
|
||||||
(when (seq new-filters)
|
|
||||||
{:filters/add-raw-filters
|
|
||||||
{:filters new-filters}})))
|
|
||||||
|
|
||||||
;; Load functions: utility function to load filters
|
|
||||||
|
|
||||||
(fx/defn load-chat
|
|
||||||
"Check if a filter already exists for that chat, otherw load the filter"
|
|
||||||
[{:keys [db] :as cofx} chat-id]
|
|
||||||
(when (and (messenger-started? db)
|
|
||||||
(not (chat-loaded? db chat-id)))
|
|
||||||
(let [chat (get-in db [:chats chat-id])]
|
|
||||||
(load-filter-fx (->filter-request chat)))))
|
|
||||||
|
|
||||||
(fx/defn load-chats
|
|
||||||
"Check if a filter already exists for that chat, otherw load the filter"
|
|
||||||
[{:keys [db] :as cofx} chats]
|
|
||||||
(let [chats (filter #(chat-loaded? db (:chat-id %)) chats)]
|
|
||||||
(when (and (messenger-started? db) (seq chats))
|
|
||||||
(load-filter-fx (chats->filter-requests chats)))))
|
|
||||||
|
|
||||||
(fx/defn load-contact
|
|
||||||
"Check if we already have a filter for that contact, otherwise load the filter
|
|
||||||
if the contact has been added"
|
|
||||||
[{:keys [db] :as cofx} contact]
|
|
||||||
(when-not (chat-loaded? db (:public-key contact))
|
|
||||||
(load-filter-fx (contacts->filter-requests [contact]))))
|
|
||||||
|
|
||||||
(fx/defn load-member
|
|
||||||
"Check if we already have a filter for that member, otherwise load the filter, regardless of whether is in our contacts"
|
|
||||||
[{:keys [db] :as cofx} public-key]
|
|
||||||
(when-not (chat-loaded? db public-key)
|
|
||||||
(load-filter-fx (->filter-request {:chat-id public-key}))))
|
|
||||||
|
|
||||||
(fx/defn load-members
|
|
||||||
"Load multiple members"
|
|
||||||
[cofx members]
|
|
||||||
(apply fx/merge cofx (map load-member members)))
|
|
||||||
|
|
||||||
(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} chat-id]
|
|
||||||
(let [my-public-key (multiaccounts.model/current-public-key cofx)
|
|
||||||
one-to-one? (not (get-in db [:chats chat-id :group-chat]))
|
|
||||||
public? (get-in db [:chats chat-id :public?])
|
|
||||||
active-group-chats (filter (fn [{:keys [is-active members members-joined]}]
|
|
||||||
(and is-active
|
|
||||||
(contains? members-joined my-public-key)
|
|
||||||
(contains? members chat-id)))
|
|
||||||
(vals (:chats db)))]
|
|
||||||
(when (or public?
|
|
||||||
(and one-to-one?
|
|
||||||
(not (contact.db/active? db chat-id))
|
|
||||||
(not= my-public-key chat-id)
|
|
||||||
(not (get-in db [:chats chat-id :is-active]))
|
|
||||||
(empty? active-group-chats)))
|
|
||||||
(fx/merge cofx
|
|
||||||
;; we exclude the negotiated filters as those are not to be removed
|
|
||||||
;; otherwise we might miss messages
|
|
||||||
(remove-filter-fx
|
|
||||||
(non-negotiated-filters-for-chat-id db chat-id))))))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:filters/add-raw-filters
|
|
||||||
(fn [{:keys [filters]}]
|
|
||||||
(log/debug "PERF" :filters/add-raw-filters)
|
|
||||||
(filters-added! filters)))
|
|
||||||
|
|
||||||
;; Here we stop first polling and then we hit status-go, otherwise it would throw
|
|
||||||
;; an error trying to poll from a delete filter. If we fail to remove the filter though
|
|
||||||
;; we should recreate it.
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:filters/remove-filters
|
|
||||||
(fn [[filters]]
|
|
||||||
(log/debug "removing filters" filters)
|
|
||||||
(remove-filters-rpc
|
|
||||||
(map ->remove-filter-request filters)
|
|
||||||
#(filters-removed! filters)
|
|
||||||
#(log/error "remove-filters: failed error" %))))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:filters/load-filters
|
|
||||||
(fn [raw-filters]
|
|
||||||
(let [all-filters (mapcat first raw-filters)]
|
|
||||||
(load-filters-rpc
|
|
||||||
all-filters
|
|
||||||
#(filters-added! (map responses->filters %))
|
|
||||||
#(log/error "load-filters: failed error" %)))))
|
|
@ -1,158 +0,0 @@
|
|||||||
(ns status-im.transport.filters.core-test
|
|
||||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
|
||||||
[status-im.utils.fx :as fx]
|
|
||||||
[status-im.mailserver.topics :as mailserver.topics]
|
|
||||||
[status-im.transport.filters.core :as transport.filters]))
|
|
||||||
|
|
||||||
(def me "me")
|
|
||||||
(def member-1 "member-1")
|
|
||||||
(def member-2 "member-2")
|
|
||||||
(def chat-id "chat-id")
|
|
||||||
|
|
||||||
(deftest stop-listening
|
|
||||||
(testing "the user is in our contacts"
|
|
||||||
(testing "it does not remove filters"
|
|
||||||
(is (not (transport.filters/stop-listening
|
|
||||||
{:db {:contacts/contacts
|
|
||||||
{chat-id {:system-tags #{:contact/added}}}}}
|
|
||||||
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 filters"
|
|
||||||
(let [fx (transport.filters/stop-listening {:db {:filter/filters
|
|
||||||
{"a" {:chat-id chat-id :filter-id "a"}
|
|
||||||
"b" {:chat-id chat-id :negotiated? true}}}}
|
|
||||||
chat-id)]
|
|
||||||
(is fx)
|
|
||||||
(is (= fx {:filters/remove-filters [[{:chat-id chat-id :filter-id "a"}]]})))))
|
|
||||||
(testing "the user is still in some group chats"
|
|
||||||
(testing "we joined, and group chat is active it does not remove filters"
|
|
||||||
(let [fx (transport.filters/stop-listening {:db {:multiaccount {:public-key me}
|
|
||||||
:chats
|
|
||||||
{chat-id {:is-active true
|
|
||||||
:members-joined #{me}
|
|
||||||
:members #{member-1}}}
|
|
||||||
:filter/filters
|
|
||||||
{member-1 {}}}}
|
|
||||||
member-1)]
|
|
||||||
(is (not fx))))
|
|
||||||
(testing "we didn't join, it removes transport"
|
|
||||||
(let [fx (transport.filters/stop-listening {:db {:multiaccount {:public-key me}
|
|
||||||
:chats
|
|
||||||
{chat-id {:is-active true
|
|
||||||
:members-joined #{member-1}
|
|
||||||
:members #{member-1}}}
|
|
||||||
:filter/filters
|
|
||||||
{member-1 {:chat-id member-1 :filter-id "a"}}}}
|
|
||||||
member-1)]
|
|
||||||
(is fx)
|
|
||||||
(is (= fx {:filters/remove-filters [[{:chat-id member-1 :filter-id "a"}]]})))))
|
|
||||||
(testing "we have a 1-to-1 chat with the user"
|
|
||||||
(testing "it does not remove filter"
|
|
||||||
(let [fx (transport.filters/stop-listening {:db {:chats
|
|
||||||
{member-1 {:is-active true}}}}
|
|
||||||
member-1)]
|
|
||||||
(is (not fx)))))))
|
|
||||||
|
|
||||||
(deftest chats->filter-requests
|
|
||||||
(testing "a single one to one chat"
|
|
||||||
(is (= [{:ChatID "0xchat-id"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id"}]
|
|
||||||
(#'status-im.transport.filters.core/chats->filter-requests [{:is-active true
|
|
||||||
:group-chat false
|
|
||||||
:chat-id "0xchat-id"}]))))
|
|
||||||
(testing "a malformed one to one chat"
|
|
||||||
(is (= []
|
|
||||||
(#'status-im.transport.filters.core/chats->filter-requests [{:is-active true
|
|
||||||
:group-chat false
|
|
||||||
:chat-id "malformed"}]))))
|
|
||||||
(testing "a single public chat"
|
|
||||||
(is (= [{:ChatID "chat-id"
|
|
||||||
:OneToOne false}]
|
|
||||||
(#'status-im.transport.filters.core/chats->filter-requests [{:is-active true
|
|
||||||
:group-chat true
|
|
||||||
:public? true
|
|
||||||
:chat-id "chat-id"}]))))
|
|
||||||
(testing "a single group chat"
|
|
||||||
(is (= [{:ChatID "0xchat-id-2"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-2"}
|
|
||||||
{:ChatID "0xchat-id-1"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-1"}]
|
|
||||||
(#'status-im.transport.filters.core/chats->filter-requests [{:is-active true
|
|
||||||
:group-chat true
|
|
||||||
:members-joined #{"0xchat-id-1" "0xchat-id-2"}
|
|
||||||
:chat-id "chat-id"}])))))
|
|
||||||
|
|
||||||
(deftest contacts->filters
|
|
||||||
(testing "converting contacts to filters"
|
|
||||||
(is (= [{:ChatID "0xchat-id-2"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-2"}]
|
|
||||||
(#'status-im.transport.filters.core/contacts->filter-requests [{:system-tags #{}
|
|
||||||
:public-key "0xchat-id-1"}
|
|
||||||
{:system-tags #{:contact/added}
|
|
||||||
:public-key "0xchat-id-2"}])))))
|
|
||||||
|
|
||||||
(deftest load-member
|
|
||||||
(testing "it returns fx for a member"
|
|
||||||
(is (= {:filters/load-filters [[[{:ChatID "0xchat-id-2"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-2"}]]]}
|
|
||||||
(transport.filters/load-member {:db {}} "0xchat-id-2"))))
|
|
||||||
(testing "merging fx"
|
|
||||||
(is (=
|
|
||||||
{:db {}
|
|
||||||
:filters/load-filters [[[{:ChatID "0xchat-id-1"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-1"}]]
|
|
||||||
[[{:ChatID "0xchat-id-2"
|
|
||||||
:OneToOne true
|
|
||||||
:Identity "chat-id-2"}]]]}
|
|
||||||
(apply fx/merge {:db {}}
|
|
||||||
(map transport.filters/load-member ["0xchat-id-1" "0xchat-id-2"]))))))
|
|
||||||
|
|
||||||
(deftest add-filter-to-db
|
|
||||||
(with-redefs [mailserver.topics/upsert (fn [{:keys [db]} r] {:db (assoc db :upsert r)})]
|
|
||||||
(let [expected {:db {:filter/chat-ids #{"chat-id"}
|
|
||||||
:filter/filters {"filter-id" {:filter-id "filter-id"
|
|
||||||
:discovery? false
|
|
||||||
:listen? true
|
|
||||||
:chat-id "chat-id"
|
|
||||||
:negotiated? false
|
|
||||||
:topic "topic"}}
|
|
||||||
:upsert {:topic "topic"
|
|
||||||
:negotiated? false
|
|
||||||
:discovery? false
|
|
||||||
:chat-ids #{"chat-id"}
|
|
||||||
:filter-ids #{"filter-id"}}}}]
|
|
||||||
(is (= expected
|
|
||||||
(transport.filters/add-filter-to-db {:db {}} {:filter-id "filter-id"
|
|
||||||
:discovery? false
|
|
||||||
:chat-id "chat-id"
|
|
||||||
:negotiated? false
|
|
||||||
:listen? true
|
|
||||||
:topic "topic"}))))))
|
|
||||||
|
|
||||||
(deftest add-filter-to-db-not-listen
|
|
||||||
(with-redefs [mailserver.topics/upsert (fn [{:keys [db]} r] {:db (assoc db :upsert r)})]
|
|
||||||
(is (not (transport.filters/add-filter-to-db {:db {}} {:filter-id "filter-id"
|
|
||||||
:discovery? false
|
|
||||||
:chat-id "chat-id"
|
|
||||||
:negotiated? false
|
|
||||||
:topic "topic"})))))
|
|
||||||
|
|
||||||
(deftest new-filters?
|
|
||||||
(testing "new-filters?"
|
|
||||||
(let [db {:filter/filters {"a" {}
|
|
||||||
"b" {}
|
|
||||||
"c" {}}}]
|
|
||||||
(is (not (transport.filters/new-filters? db [{:filter-id "a"}
|
|
||||||
{:filter-id "b"}
|
|
||||||
{:filter-id "c"}])))
|
|
||||||
(is (not (transport.filters/new-filters? db [{:filter-id "a"}])))
|
|
||||||
(is (transport.filters/new-filters? db [{:filter-id "d"}]))
|
|
||||||
(is (transport.filters/new-filters? db [{:filter-id "a"}
|
|
||||||
{:filter-id "d"}])))))
|
|
@ -6,7 +6,6 @@
|
|||||||
[status-im.contact.core :as models.contact]
|
[status-im.contact.core :as models.contact]
|
||||||
[status-im.communities.core :as models.communities]
|
[status-im.communities.core :as models.communities]
|
||||||
[status-im.pairing.core :as models.pairing]
|
[status-im.pairing.core :as models.pairing]
|
||||||
[status-im.transport.filters.core :as models.filters]
|
|
||||||
[status-im.data-store.reactions :as data-store.reactions]
|
[status-im.data-store.reactions :as data-store.reactions]
|
||||||
[status-im.data-store.contacts :as data-store.contacts]
|
[status-im.data-store.contacts :as data-store.contacts]
|
||||||
[status-im.data-store.chats :as data-store.chats]
|
[status-im.data-store.chats :as data-store.chats]
|
||||||
@ -36,8 +35,6 @@
|
|||||||
^js installations (.-installations response-js)
|
^js installations (.-installations response-js)
|
||||||
^js messages (.-messages response-js)
|
^js messages (.-messages response-js)
|
||||||
^js emoji-reactions (.-emojiReactions response-js)
|
^js emoji-reactions (.-emojiReactions response-js)
|
||||||
^js filters (.-filters response-js)
|
|
||||||
^js removed-filters (.-removedFilters response-js)
|
|
||||||
^js invitations (.-invitations response-js)
|
^js invitations (.-invitations response-js)
|
||||||
^js removed-chats (.-removedChats response-js)
|
^js removed-chats (.-removedChats response-js)
|
||||||
^js activity-notifications (.-activityCenterNotifications response-js)
|
^js activity-notifications (.-activityCenterNotifications response-js)
|
||||||
@ -113,20 +110,7 @@
|
|||||||
(js-delete response-js "invitations")
|
(js-delete response-js "invitations")
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(process-next response-js sync-handler)
|
(process-next response-js sync-handler)
|
||||||
(models.group/handle-invitations (map data-store.invitations/<-rpc invitations))))
|
(models.group/handle-invitations (map data-store.invitations/<-rpc invitations)))))))
|
||||||
(seq filters)
|
|
||||||
(let [filters (types/js->clj filters)]
|
|
||||||
(js-delete response-js "filters")
|
|
||||||
(fx/merge cofx
|
|
||||||
(process-next response-js sync-handler)
|
|
||||||
(models.filters/handle-filters filters)))
|
|
||||||
|
|
||||||
(seq removed-filters)
|
|
||||||
(let [removed-filters (types/js->clj removed-filters)]
|
|
||||||
(js-delete response-js "removedFilters")
|
|
||||||
(fx/merge cofx
|
|
||||||
(process-next response-js sync-handler)
|
|
||||||
(models.filters/handle-filters-removed filters))))))
|
|
||||||
|
|
||||||
(defn group-by-and-update-unviewed-counts
|
(defn group-by-and-update-unviewed-counts
|
||||||
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
|
"group messages by current chat, profile updates, transactions and update unviewed counters in db for not curent chats"
|
||||||
@ -188,9 +172,7 @@
|
|||||||
[{:ms 100 :dispatch [:process-statuses statuses]}])
|
[{:ms 100 :dispatch [:process-statuses statuses]}])
|
||||||
(when (seq transactions)
|
(when (seq transactions)
|
||||||
(for [transaction-hash transactions]
|
(for [transaction-hash transactions]
|
||||||
{:ms 100 :dispatch [:watch-tx transaction-hash]}))
|
{:ms 100 :dispatch [:watch-tx transaction-hash]})))}
|
||||||
(when (seq chats)
|
|
||||||
[{:ms 100 :dispatch [:chat/join-times-messages-checked chats]}]))}
|
|
||||||
(process-response response-js process-async))))
|
(process-response response-js process-async))))
|
||||||
|
|
||||||
(fx/defn remove-hash
|
(fx/defn remove-hash
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
[status-im.ui.components.invite.views :as invite]
|
[status-im.ui.components.invite.views :as invite]
|
||||||
[status-im.ethereum.ens :as ens]
|
[status-im.ethereum.ens :as ens]
|
||||||
[quo.platform :as platform]
|
[quo.platform :as platform]
|
||||||
[status-im.transport.filters.core :as filters]
|
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
[status-im.ui.components.keyboard-avoid-presentation :as kb-presentation]
|
||||||
[status-im.ui.components.animation :as animation]
|
[status-im.ui.components.animation :as animation]
|
||||||
@ -82,8 +81,13 @@
|
|||||||
(filter (partial search-contacts lower-filter-text) contacts)
|
(filter (partial search-contacts lower-filter-text) contacts)
|
||||||
contacts)))
|
contacts)))
|
||||||
|
|
||||||
|
(defn is-public-key? [k]
|
||||||
|
(and
|
||||||
|
(string? k)
|
||||||
|
(string/starts-with? k "0x")))
|
||||||
|
|
||||||
(defn is-valid-username? [username]
|
(defn is-valid-username? [username]
|
||||||
(let [is-chat-key? (and (filters/is-public-key? username)
|
(let [is-chat-key? (and (is-public-key? username)
|
||||||
(= (count username) 132))
|
(= (count username) 132))
|
||||||
is-ens? (ens/valid-eth-name-prefix? username)]
|
is-ens? (ens/valid-eth-name-prefix? username)]
|
||||||
(or is-chat-key? is-ens?)))
|
(or is-chat-key? is-ens?)))
|
||||||
|
@ -83,9 +83,9 @@
|
|||||||
:size :small
|
:size :small
|
||||||
:color colors/gray}]])
|
:color colors/gray}]])
|
||||||
|
|
||||||
(defn calculate-quiet-time [highest-request-to
|
(defn calculate-quiet-time [synced-to
|
||||||
lowest-request-from]
|
synced-from]
|
||||||
(let [quiet-hours (quot (- highest-request-to lowest-request-from)
|
(let [quiet-hours (quot (- synced-to synced-from)
|
||||||
(* 60 60))]
|
(* 60 60))]
|
||||||
(if (<= quiet-hours 24)
|
(if (<= quiet-hours 24)
|
||||||
(i18n/label :t/quiet-hours
|
(i18n/label :t/quiet-hours
|
||||||
@ -94,22 +94,22 @@
|
|||||||
{:quiet-days (quot quiet-hours 24)}))))
|
{:quiet-days (quot quiet-hours 24)}))))
|
||||||
|
|
||||||
(defview no-messages-community-chat-description-container [chat-id]
|
(defview no-messages-community-chat-description-container [chat-id]
|
||||||
(letsubs [{:keys [highest-request-to lowest-request-from]}
|
(letsubs [{:keys [synced-to synced-from]}
|
||||||
[:mailserver/ranges-by-chat-id chat-id]]
|
[:chats/synced-to-and-from chat-id]]
|
||||||
[react/text {:style (merge style/intro-header-description
|
[react/text {:style (merge style/intro-header-description
|
||||||
{:margin-bottom 36})}
|
{:margin-bottom 36})}
|
||||||
(let [quiet-time (calculate-quiet-time highest-request-to
|
(let [quiet-time (calculate-quiet-time synced-to
|
||||||
lowest-request-from)]
|
synced-from)]
|
||||||
(i18n/label :t/empty-chat-description-community
|
(i18n/label :t/empty-chat-description-community
|
||||||
{:quiet-hours quiet-time}))]))
|
{:quiet-hours quiet-time}))]))
|
||||||
|
|
||||||
(defview no-messages-private-group-chat-description-container [chat-id]
|
(defview no-messages-private-group-chat-description-container [chat-id]
|
||||||
(letsubs [{:keys [highest-request-to lowest-request-from]}
|
(letsubs [{:keys [synced-to synced-from]}
|
||||||
[:mailserver/ranges-by-chat-id chat-id]]
|
[:chats/synced-to-and-from chat-id]]
|
||||||
[react/nested-text {:style (merge style/intro-header-description
|
[react/nested-text {:style (merge style/intro-header-description
|
||||||
{:margin-bottom 36})}
|
{:margin-bottom 36})}
|
||||||
(let [quiet-time (calculate-quiet-time highest-request-to
|
(let [quiet-time (calculate-quiet-time synced-to
|
||||||
lowest-request-from)]
|
synced-from)]
|
||||||
(i18n/label :t/empty-chat-description-public
|
(i18n/label :t/empty-chat-description-public
|
||||||
{:quiet-hours quiet-time}))
|
{:quiet-hours quiet-time}))
|
||||||
[{:style {:color colors/blue}
|
[{:style {:color colors/blue}
|
||||||
|
@ -7,47 +7,33 @@
|
|||||||
[status-im.ui.screens.chat.styles.input.gap :as style]))
|
[status-im.ui.screens.chat.styles.input.gap :as style]))
|
||||||
|
|
||||||
(defn on-press
|
(defn on-press
|
||||||
[ids first-gap? idx list-ref chat-id]
|
[chat-id gap-ids]
|
||||||
(fn []
|
(fn []
|
||||||
(when (and list-ref @list-ref)
|
(re-frame/dispatch [:chat.ui/fill-gaps chat-id gap-ids])))
|
||||||
(.scrollToIndex ^js @list-ref
|
|
||||||
#js {:index (max 0 (dec idx))
|
|
||||||
:viewOffset 20
|
|
||||||
:viewPosition 0.5}))
|
|
||||||
(if first-gap?
|
|
||||||
(re-frame/dispatch [:chat.ui/fetch-more chat-id])
|
|
||||||
(re-frame/dispatch [:chat.ui/fill-gaps ids chat-id]))))
|
|
||||||
|
|
||||||
(views/defview gap
|
(views/defview gap
|
||||||
[{:keys [gaps first-gap?]} idx list-ref timeline chat-id]
|
[{:keys [gap-ids chat-id gap-parameters]}]
|
||||||
(views/letsubs [range [:chats/range chat-id]
|
(views/letsubs [in-progress? [:chats/fetching-gap-in-progress?
|
||||||
{:keys [might-have-join-time-messages?]} [:chat-by-id chat-id]
|
gap-ids
|
||||||
in-progress? [:chats/fetching-gap-in-progress?
|
|
||||||
(if first-gap?
|
|
||||||
[:first-gap]
|
|
||||||
(:ids gaps))
|
|
||||||
chat-id]
|
chat-id]
|
||||||
connected? [:mailserver/connected?]]
|
connected? [:mailserver/connected?]
|
||||||
(let [ids (:ids gaps)]
|
first-gap? (= gap-ids #{:first-gap})]
|
||||||
(when-not (and first-gap? might-have-join-time-messages?)
|
|
||||||
[react/view {:style (style/gap-container)}
|
[react/view {:style (style/gap-container)}
|
||||||
[react/touchable-highlight
|
[react/touchable-highlight
|
||||||
{:on-press (when (and connected? (not in-progress?))
|
{:on-press (when (and connected? (not in-progress?))
|
||||||
(on-press ids first-gap? idx list-ref chat-id))
|
(on-press chat-id gap-ids))
|
||||||
:style style/touchable}
|
:style style/touchable}
|
||||||
[react/view {:style style/label-container}
|
[react/view {:style style/label-container}
|
||||||
(if in-progress?
|
(if in-progress?
|
||||||
[react/activity-indicator]
|
[react/activity-indicator]
|
||||||
[react/nested-text
|
[react/nested-text
|
||||||
{:style (style/gap-text connected?)}
|
{:style (style/gap-text connected?)}
|
||||||
(i18n/label (if first-gap?
|
(i18n/label (if first-gap? :t/load-more-messages :t/fetch-messages))
|
||||||
(if timeline :t/load-more-timeline :t/load-more-messages)
|
|
||||||
(if timeline :t/fetch-timeline :t/fetch-messages)))
|
|
||||||
(when first-gap?
|
(when first-gap?
|
||||||
[{:style style/date}
|
[{:style style/date}
|
||||||
(let [date (datetime/timestamp->long-date
|
(let [date (datetime/timestamp->long-date
|
||||||
(* 1000 (:lowest-request-from range)))]
|
(* 1000 (:from gap-parameters)))]
|
||||||
(str
|
(str
|
||||||
"\n"
|
"\n"
|
||||||
(i18n/label :t/load-messages-before
|
(i18n/label :t/load-messages-before
|
||||||
{:date date})))])])]]]))))
|
{:date date})))])])]]]))
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
[status-im.ui.screens.chat.message.command :as message.command]
|
[status-im.ui.screens.chat.message.command :as message.command]
|
||||||
[status-im.ui.screens.chat.photos :as photos]
|
[status-im.ui.screens.chat.photos :as photos]
|
||||||
[status-im.ui.screens.chat.sheets :as sheets]
|
[status-im.ui.screens.chat.sheets :as sheets]
|
||||||
|
[status-im.ui.screens.chat.message.gap :as message.gap]
|
||||||
[status-im.ui.screens.chat.styles.message.message :as style]
|
[status-im.ui.screens.chat.styles.message.message :as style]
|
||||||
[status-im.ui.screens.chat.utils :as chat.utils]
|
[status-im.ui.screens.chat.utils :as chat.utils]
|
||||||
[status-im.utils.contenthash :as contenthash]
|
[status-im.utils.contenthash :as contenthash]
|
||||||
@ -316,6 +317,10 @@
|
|||||||
[message]
|
[message]
|
||||||
[message.command/command-content message-content-wrapper message])
|
[message.command/command-content message-content-wrapper message])
|
||||||
|
|
||||||
|
(defmethod ->message constants/content-type-gap
|
||||||
|
[message]
|
||||||
|
[message.gap/gap message])
|
||||||
|
|
||||||
(defmethod ->message constants/content-type-system-text [{:keys [content] :as message}]
|
(defmethod ->message constants/content-type-system-text [{:keys [content] :as message}]
|
||||||
[react/view {:accessibility-label :chat-item}
|
[react/view {:accessibility-label :chat-item}
|
||||||
[react/view (style/system-message-body message)
|
[react/view (style/system-message-body message)
|
||||||
|
@ -123,6 +123,7 @@
|
|||||||
(defn chat-intro-header-container
|
(defn chat-intro-header-container
|
||||||
[{:keys [group-chat invitation-admin
|
[{:keys [group-chat invitation-admin
|
||||||
chat-type
|
chat-type
|
||||||
|
synced-to
|
||||||
color chat-id chat-name
|
color chat-id chat-name
|
||||||
public?]}
|
public?]}
|
||||||
no-messages]
|
no-messages]
|
||||||
@ -139,7 +140,7 @@
|
|||||||
:chat-name chat-name
|
:chat-name chat-name
|
||||||
:public? public?
|
:public? public?
|
||||||
:color color
|
:color color
|
||||||
:loading-messages? @(re-frame/subscribe [:chats/might-have-join-time-messages? chat-id])
|
:loading-messages? (not (pos? synced-to))
|
||||||
:no-messages? no-messages}]
|
:no-messages? no-messages}]
|
||||||
(if group-chat
|
(if group-chat
|
||||||
[chat-intro opts]
|
[chat-intro opts]
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
(ns status-im.utils.prices
|
(ns status-im.utils.prices
|
||||||
(:require [clojure.string :as string]
|
(:require [clojure.string :as string]
|
||||||
[status-im.utils.http :as http]
|
[status-im.utils.http :as http]
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]))
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
;; Responsible for interacting with Cryptocompare API to get current prices for
|
;; Responsible for interacting with Cryptocompare API to get current prices for
|
||||||
;; currencies and tokens.
|
;; currencies and tokens.
|
||||||
@ -39,10 +38,6 @@
|
|||||||
:last-day (:OPEN24HOUR entry)}}))}))))
|
:last-day (:OPEN24HOUR entry)}}))}))))
|
||||||
|
|
||||||
(defn get-prices [from to mainnet? on-success on-error]
|
(defn get-prices [from to mainnet? on-success on-error]
|
||||||
(log/debug "[prices] get-prices"
|
|
||||||
"from" from
|
|
||||||
"to" to
|
|
||||||
"mainnet?" mainnet?)
|
|
||||||
(http/get
|
(http/get
|
||||||
(gen-price-url from to)
|
(gen-price-url from to)
|
||||||
(fn [resp] (on-success (format-price-resp resp mainnet?)))
|
(fn [resp] (on-success (format-price-resp resp mainnet?)))
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
|
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
|
||||||
"owner": "status-im",
|
"owner": "status-im",
|
||||||
"repo": "status-go",
|
"repo": "status-go",
|
||||||
"version": "v0.77.1",
|
"version": "v0.79.0",
|
||||||
"commit-sha1": "6a930ed0c601aca3dd13c9d4dedf3ea2d444848f",
|
"commit-sha1": "d50fee6bb2e392351a5bce6187725ab80c7420eb",
|
||||||
"src-sha256": "0jz4696xm99cy4dxi3dfd0b4rj5pqrsfj92zsfyxilgzjkwyzf78"
|
"src-sha256": "0zx0dr3p5vvr3rbnq0gkvdgzkyj15i41yrlc95c3152mwgkh3bzf"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user