Multiple messages gaps per chat

This commit is contained in:
Roman Volosovskyi 2019-04-16 22:09:18 +03:00
parent 60225995b7
commit c98f547349
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
23 changed files with 869 additions and 437 deletions

View File

@ -58,15 +58,6 @@
(get-in db [:transport/chats current-chat-id :topic]) (get-in db [:transport/chats current-chat-id :topic])
(topic/public-key->discovery-topic-hash public-key)))) (topic/public-key->discovery-topic-hash public-key))))
(defn messages-gap
[mailserver-topics topic]
(let [{:keys [gap-from gap-to]}
(get mailserver-topics topic)]
{:from gap-from
:to gap-to
:exists? (and gap-from gap-to
(> gap-to gap-from))}))
(defn sort-message-groups (defn sort-message-groups
"Sorts message groups according to timestamp of first message in group" "Sorts message groups according to timestamp of first message in group"
[message-groups messages] [message-groups messages]
@ -113,41 +104,54 @@
(assoc-in [:content :response-to] quote)))))) (assoc-in [:content :response-to] quote))))))
(defn check-gap (defn check-gap
[{:keys [exists? from]} previous-message next-message gap-added?] [gaps previous-message next-message]
(let [previous-timestamp (:whisper-timestamp previous-message) (let [previous-timestamp (:whisper-timestamp previous-message)
next-whisper-timestamp (:whisper-timestamp next-message) next-whisper-timestamp (:whisper-timestamp next-message)
next-timestamp (quot (:timestamp next-message) 1000) next-timestamp (quot (:timestamp next-message) 1000)
ignore-next-message? (> (js/Math.abs ignore-next-message? (> (js/Math.abs
(- next-whisper-timestamp next-timestamp)) (- next-whisper-timestamp next-timestamp))
120)] 120)]
(and (not gap-added?) (reduce
(or (and exists? previous-timestamp next-whisper-timestamp (fn [acc {:keys [from id]}]
(if (and next-message
(not ignore-next-message?) (not ignore-next-message?)
(< previous-timestamp from next-whisper-timestamp)) (or
(and exists? (nil? next-message)))))) (and (nil? previous-timestamp)
(< from next-whisper-timestamp))
(< previous-timestamp from 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 gap] (defn add-gap [messages gaps]
(conj messages (conj messages
{:type :gap {:type :gap
:value (str (:from gap))})) :value (clojure.string/join (:ids gaps))
:gaps gaps}))
(defn messages-with-datemarks-and-statuses (defn messages-with-datemarks-and-statuses
"Converts message groups into sequence of messages interspersed with datemarks, "Converts message groups into sequence of messages interspersed with datemarks,
with correct user statuses associated into message" with correct user statuses associated into message"
[message-groups messages message-statuses referenced-messages messages-gap] [message-groups messages message-statuses referenced-messages messages-gaps]
(transduce (transduce
(comp (comp
(mapcat add-datemark) (mapcat add-datemark)
(map (transform-message messages message-statuses referenced-messages))) (map (transform-message messages message-statuses referenced-messages)))
(completing (completing
(fn [{:keys [messages datemark-reference previous-message gap-added?]} (fn [{:keys [messages datemark-reference previous-message gaps]}
message] message]
(let [new-datemark? (datemark? message) (let [new-datemark? (datemark? message)
add-gap? (check-gap messages-gap previous-message message gap-added?)] {:keys [gaps-number gap]}
(check-gap gaps previous-message message)
add-gap? (pos? gaps-number)]
{:messages (cond-> messages {:messages (cond-> messages
add-gap? add-gap?
(add-gap messages-gap) (add-gap gap)
:always :always
(conj (conj
@ -160,14 +164,16 @@
:datemark-reference (if new-datemark? :datemark-reference (if new-datemark?
message message
datemark-reference) datemark-reference)
:gap-added? (or gap-added? add-gap?)})) :gaps (if add-gap?
(fn [{:keys [messages previous-message gap-added?]}] (drop gaps-number gaps)
(let [add-gap? (check-gap messages-gap previous-message nil gap-added?)] gaps)}))
(fn [{:keys [messages gaps]}]
(cond-> messages (cond-> messages
add-gap? (seq gaps)
(add-gap messages-gap))))) (add-gap {:ids (map :id gaps)}))))
{:messages (list) {:messages (list)
:previous-message nil} :previous-message nil
:gaps messages-gaps}
message-groups)) message-groups))
(defn- set-previous-message-info [stream] (defn- set-previous-message-info [stream]

View File

@ -19,7 +19,9 @@
[status-im.utils.gfycat.core :as gfycat] [status-im.utils.gfycat.core :as gfycat]
[status-im.utils.platform :as platform] [status-im.utils.platform :as platform]
[status-im.utils.priority-map :refer [empty-message-map]] [status-im.utils.priority-map :refer [empty-message-map]]
[status-im.utils.utils :as utils])) [status-im.utils.utils :as utils]
[status-im.mailserver.core :as mailserver]
[status-im.transport.partitioned-topic :as transport.topic]))
(defn- get-chat [cofx chat-id] (defn- get-chat [cofx chat-id]
(get-in cofx [:db :chats chat-id])) (get-in cofx [:db :chats chat-id]))
@ -163,6 +165,10 @@
(fx/merge cofx (fx/merge cofx
#(when (public-chat? % chat-id) #(when (public-chat? % chat-id)
(transport.chat/unsubscribe-from-chat % chat-id)) (transport.chat/unsubscribe-from-chat % chat-id))
#(when (group-chat? % chat-id)
(mailserver/remove-chat-from-mailserver-topic % chat-id))
(mailserver/remove-gaps chat-id)
(mailserver/remove-range chat-id)
(deactivate-chat chat-id) (deactivate-chat chat-id)
(clear-history chat-id) (clear-history chat-id)
#(when (one-to-one-chat? % chat-id) #(when (one-to-one-chat? % chat-id)
@ -242,13 +248,12 @@
(fx/defn preload-chat-data (fx/defn preload-chat-data
"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"
[{:keys [db] :as cofx} chat-id] [{:keys [db] :as cofx} chat-id]
(let [chat (get-in db [:chats chat-id])]
(fx/merge cofx (fx/merge cofx
{:db (-> (assoc db :current-chat-id chat-id) {:db (-> (assoc db :current-chat-id chat-id)
(set-chat-ui-props {:validation-messages nil}))} (set-chat-ui-props {:validation-messages nil}))}
(contact-code/listen-to-chat chat-id) (contact-code/listen-to-chat chat-id)
(when platform/desktop? (when platform/desktop?
(mark-messages-seen chat-id))))) (mark-messages-seen 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"

View File

@ -6,7 +6,8 @@
[status-im.data-store.user-statuses :as user-statuses-store] [status-im.data-store.user-statuses :as user-statuses-store]
[status-im.utils.datetime :as time] [status-im.utils.datetime :as time]
[status-im.utils.fx :as fx] [status-im.utils.fx :as fx]
[status-im.utils.priority-map :refer [empty-message-map]])) [status-im.utils.priority-map :refer [empty-message-map]]
[status-im.mailserver.core :as mailserver]))
(def index-messages (partial into empty-message-map (def index-messages (partial into empty-message-map
(map (juxt :message-id identity)))) (map (juxt :message-id identity))))
@ -114,5 +115,6 @@
(chat-model/update-chats-unviewed-messages-count (chat-model/update-chats-unviewed-messages-count
{:chat-id current-chat-id {:chat-id current-chat-id
:new-loaded-unviewed-messages-ids loaded-unviewed-messages}) :new-loaded-unviewed-messages-ids loaded-unviewed-messages})
(mailserver/load-gaps current-chat-id)
(group-chat-messages current-chat-id new-messages) (group-chat-messages current-chat-id new-messages)
(chat-model/mark-messages-seen current-chat-id))))) (chat-model/mark-messages-seen current-chat-id)))))

View File

@ -468,6 +468,7 @@
message-data (-> message message-data (-> message
(assoc :from (accounts.db/current-public-key cofx) (assoc :from (accounts.db/current-public-key cofx)
:timestamp now :timestamp now
:whisper-timestamp (quot now 1000)
:clock-value (utils.clocks/send :clock-value (utils.clocks/send
last-clock-value)) last-clock-value))
(add-message-type chat))] (add-message-type chat))]

View File

@ -172,11 +172,11 @@
(chat.db/topic-by-current-chat db))) (chat.db/topic-by-current-chat db)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/messages-gap :chats/messages-gaps
:<- [:get-in [:mailserver/topics]] :<- [:get-in [:mailserver/gaps]]
:<- [:chats/current-chat-topic] :<- [:chats/current-chat-id]
(fn [[mailserver-topics topic]] (fn [[gaps chat-id]]
(chat.db/messages-gap mailserver-topics topic))) (sort-by :from (vals (get gaps chat-id)))))
(re-frame/reg-sub (re-frame/reg-sub
:chats/current-chat-messages-stream :chats/current-chat-messages-stream
@ -184,18 +184,18 @@
:<- [:chats/current-chat-message-groups] :<- [:chats/current-chat-message-groups]
:<- [:chats/current-chat-message-statuses] :<- [:chats/current-chat-message-statuses]
:<- [:chats/current-chat-referenced-messages] :<- [:chats/current-chat-referenced-messages]
:<- [:chats/messages-gap] :<- [:chats/messages-gaps]
(fn [[messages message-groups message-statuses referenced-messages messages-gap]] (fn [[messages message-groups message-statuses referenced-messages messages-gaps]]
(-> (chat.db/sort-message-groups message-groups messages) (-> (chat.db/sort-message-groups message-groups messages)
(chat.db/messages-with-datemarks-and-statuses messages message-statuses referenced-messages messages-gap) (chat.db/messages-with-datemarks-and-statuses messages message-statuses referenced-messages messages-gaps)
chat.db/messages-stream))) chat.db/messages-stream)))
(re-frame/reg-sub (re-frame/reg-sub
:chats/fetching-gap-in-progress? :chats/fetching-gap-in-progress?
(fn [db] (fn [db [_ ids]]
(let [chat-id (:current-chat-id db) (let [chat-id (:current-chat-id db)
gaps (:mailserver/fetching-gaps-in-progress db)] gaps (:mailserver/fetching-gaps-in-progress db)]
(contains? gaps chat-id)))) (seq (select-keys (get gaps chat-id) ids)))))
(re-frame/reg-sub (re-frame/reg-sub
:chats/current-chat-intro-status :chats/current-chat-intro-status

View File

@ -21,7 +21,8 @@
[status-im.transport.partitioned-topic :as transport.topic] [status-im.transport.partitioned-topic :as transport.topic]
[status-im.utils.config :as config] [status-im.utils.config :as config]
[status-im.chat.models.loading :as chat.models.loading] [status-im.chat.models.loading :as chat.models.loading]
[status-im.chat.models.message :as chat.models.message])) [status-im.chat.models.message :as chat.models.message]
[status-im.mailserver.core :as mailserver]))
(fx/defn load-contacts (fx/defn load-contacts
[{:keys [db all-contacts]}] [{:keys [db all-contacts]}]
@ -74,7 +75,12 @@
(fx/merge cofx (fx/merge cofx
{:db (assoc-in db [:contacts/new-identity] "")} {:db (assoc-in db [:contacts/new-identity] "")}
(upsert-contact contact) (upsert-contact contact)
(send-contact-request contact))))) (mailserver/upsert-mailserver-topic
{:chat-ids [public-key]
:topic transport.topic/discovery-topic-hash
:fetch? false})
(send-contact-request contact)
(mailserver/process-next-messages-request)))))
(fx/defn add-contacts-filter [{:keys [db]} public-key action] (fx/defn add-contacts-filter [{:keys [db]} public-key action]
(when (not= (get-in db [:account/account :public-key]) public-key) (when (not= (get-in db [:account/account :public-key]) public-key)

View File

@ -10,7 +10,8 @@
[status-im.transport.message.public-chat :as transport.public-chat] [status-im.transport.message.public-chat :as transport.public-chat]
[status-im.data-store.accounts :as data-store.accounts] [status-im.data-store.accounts :as data-store.accounts]
[status-im.transport.chat.core :as transport.chat] [status-im.transport.chat.core :as transport.chat]
[status-im.accounts.db :as accounts.db])) [status-im.accounts.db :as accounts.db]
[status-im.mailserver.core :as mailserver]))
(defn topic [pk] (defn topic [pk]
(str pk "-contact-code")) (str pk "-contact-code"))
@ -46,15 +47,17 @@
(and is-active (and is-active
(contains? members-joined my-public-key) (contains? members-joined my-public-key)
(contains? members their-public-key))) (contains? members their-public-key)))
(vals (:chats db)))] (vals (:chats db)))
their-topic (topic their-public-key)]
(when (and (not (contact.db/active? db their-public-key)) (when (and (not (contact.db/active? db their-public-key))
(not= my-public-key their-public-key) (not= my-public-key their-public-key)
(not (get-in db [:chats their-public-key :is-active])) (not (get-in db [:chats their-public-key :is-active]))
(empty? active-group-chats)) (empty? active-group-chats))
(fx/merge (fx/merge
cofx cofx
(transport.chat/unsubscribe-from-chat (topic their-public-key)))))) (mailserver/remove-gaps their-topic)
(mailserver/remove-range their-topic)
(transport.chat/unsubscribe-from-chat their-topic)))))
;; Publish contact code every 12hrs ;; Publish contact code every 12hrs
(def publish-contact-code-interval (* 12 60 60 1000)) (def publish-contact-code-interval (* 12 60 60 1000))

View File

@ -64,3 +64,57 @@
(let [mailserver-topic (core/single (let [mailserver-topic (core/single
(core/get-by-field realm :mailserver-topic :topic topic))] (core/get-by-field realm :mailserver-topic :topic topic))]
(core/delete realm mailserver-topic)))) (core/delete realm mailserver-topic))))
(defn save-chat-requests-range
[chat-requests-range]
(fn [realm]
(core/create realm :chat-requests-range chat-requests-range true)))
(re-frame/reg-cofx
:data-store/all-chat-requests-ranges
(fn [cofx _]
(assoc cofx
:data-store/all-chat-requests-ranges
(reduce (fn [acc {:keys [chat-id] :as range}]
(assoc acc chat-id range))
{}
(-> @core/account-realm
(core/get-all :chat-requests-range)
(core/all-clj :chat-requests-range))))))
(re-frame/reg-cofx
:data-store/all-gaps
(fn [cofx _]
(assoc cofx
:data-store/all-gaps
(fn [chat-id]
(reduce (fn [acc {:keys [id] :as gap}]
(assoc acc id gap))
{}
(-> @core/account-realm
(core/get-by-field :mailserver-requests-gap :chat-id chat-id)
(core/all-clj :mailserver-requests-gap)))))))
(defn save-mailserver-requests-gap
[gap]
(fn [realm]
(core/create realm :mailserver-requests-gap gap true)))
(defn delete-mailserver-requests-gaps
[ids]
(fn [realm]
(doseq [id ids]
(core/delete
realm
(core/get-by-field realm :mailserver-requests-gap :id id)))))
(defn delete-all-gaps-by-chat
[chat-id]
(fn [realm]
(core/delete realm
(core/get-by-field realm :mailserver-requests-gap :chat-id chat-id))))
(defn delete-range
[chat-id]
(fn [realm]
(core/delete realm
(core/get-by-field realm :chat-requests-range :chat-id chat-id))))

View File

@ -0,0 +1,9 @@
(ns status-im.data-store.realm.schemas.account.chat-requests-range)
(def v1 {:name :chat-requests-range
:primaryKey :chat-id
:properties {:chat-id :string
:lowest-request-from {:type :int
:optional true}
:highest-request-to {:type :int
:optional true}}})

View File

@ -15,7 +15,9 @@
[status-im.data-store.realm.schemas.account.membership-update :as membership-update] [status-im.data-store.realm.schemas.account.membership-update :as membership-update]
[status-im.data-store.realm.schemas.account.installation :as installation] [status-im.data-store.realm.schemas.account.installation :as installation]
[status-im.data-store.realm.schemas.account.contact-recovery :as contact-recovery] [status-im.data-store.realm.schemas.account.contact-recovery :as contact-recovery]
[status-im.data-store.realm.schemas.account.migrations :as migrations])) [status-im.data-store.realm.schemas.account.mailserver-requests-gap :as mailserver-requests-gap]
[status-im.data-store.realm.schemas.account.migrations :as migrations]
[status-im.data-store.realm.schemas.account.chat-requests-range :as chat-requests-range]))
(def v1 [chat/v1 (def v1 [chat/v1
transport/v1 transport/v1
@ -476,6 +478,23 @@
contact-device-info/v1 contact-device-info/v1
contact-recovery/v1]) contact-recovery/v1])
(def v42 [chat/v14
chat-requests-range/v1
transport/v8
contact/v7
message/v10
mailserver/v11
mailserver-topic/v2
user-status/v2
membership-update/v1
installation/v3
local-storage/v1
browser/v8
dapp-permissions/v9
contact-device-info/v1
contact-recovery/v1
mailserver-requests-gap/v1])
;; put schemas ordered by version ;; put schemas ordered by version
(def schemas [{:schema v1 (def schemas [{:schema v1
:schemaVersion 1 :schemaVersion 1
@ -599,4 +618,7 @@
:migration migrations/v40} :migration migrations/v40}
{:schema v41 {:schema v41
:schemaVersion 41 :schemaVersion 41
:migration (constantly nil)}]) :migration (constantly nil)}
{:schema v42
:schemaVersion 42
:migration migrations/v42}])

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.account.mailserver-requests-gap)
(def v1 {:name :mailserver-requests-gap
:primaryKey :id
:properties {:id :string
:chat-id {:type :string
:indexed true}
:from {:type :int
:indexed true}
:to :int}})

View File

@ -16,3 +16,6 @@
[:properties :gap-to] [:properties :gap-to]
{:type :int {:type :int
:optional true}))) :optional true})))
(def v3
(update v2 :properties dissoc :gap-to :gap-from))

View File

@ -389,3 +389,31 @@
(or (true? pending?) (or (true? pending?)
(zero? last-updated)) (conj ":contact/request-received"))] (zero? last-updated)) (conj ":contact/request-received"))]
(aset new-contact "system-tags" (clj->js system-tags)))))) (aset new-contact "system-tags" (clj->js system-tags))))))
(defn private-chats-ids [chats]
(set
(keep
(fn [i]
(let [chat (aget chats i)]
(when-not (aget chat "public?")
(aget chat "chat-id"))))
(range (.-length chats)))))
(def one-day (* 24 60 60))
(def discovery-topic-hash "0xf8946aac")
(defn v42
"Add all private chats to :discovery mailserver topic"
[old-realm new-realm]
(log/debug "migrating v40 account database")
(let [mailserver-topic (-> (.objects new-realm "mailserver-topic")
(.filtered (str "topic=\"" discovery-topic-hash "\""))
(aget 0))
old-chat-ids (edn/read-string (aget mailserver-topic "chat-ids"))
new-chats-ids (private-chats-ids (.objects old-realm "chat"))
all-chat-ids (clojure.set/union old-chat-ids new-chats-ids)
chat-ids-str (pr-str all-chat-ids)]
(when mailserver-topic
(aset mailserver-topic "chat-ids" chat-ids-str))))

View File

@ -121,6 +121,7 @@
(accounts.login/login) (accounts.login/login)
(node/initialize (get-in db [:accounts/login :address]))) (node/initialize (get-in db [:accounts/login :address])))
(init/initialize-account address) (init/initialize-account address)
(mailserver/initialize-ranges)
(chat-loading/initialize-chats {:to 10})))) (chat-loading/initialize-chats {:to 10}))))
(handlers/register-handler-fx (handlers/register-handler-fx
@ -130,7 +131,8 @@
(re-frame/inject-cofx :data-store/get-all-installations) (re-frame/inject-cofx :data-store/get-all-installations)
(re-frame/inject-cofx :data-store/all-browsers) (re-frame/inject-cofx :data-store/all-browsers)
(re-frame/inject-cofx :data-store/all-dapp-permissions) (re-frame/inject-cofx :data-store/all-dapp-permissions)
(re-frame/inject-cofx :data-store/all-chats)] (re-frame/inject-cofx :data-store/all-chats)
(re-frame/inject-cofx :data-store/all-chat-requests-ranges)]
account-change-success) account-change-success)
(handlers/register-handler-fx (handlers/register-handler-fx
@ -723,20 +725,38 @@
:chat.ui/fetch-history-pressed :chat.ui/fetch-history-pressed
(fn [{:keys [now] :as cofx} [_ chat-id]] (fn [{:keys [now] :as cofx} [_ chat-id]]
(mailserver/fetch-history cofx chat-id (mailserver/fetch-history cofx chat-id
{:from (- (quot now 1000) (* 24 3600))}))) {:from (- (quot now 1000) mailserver/one-day)})))
(handlers/register-handler-fx (handlers/register-handler-fx
:chat.ui/fill-the-gap :chat.ui/fetch-history-pressed48-60
(fn [{:keys [db] :as cofx}] (fn [{:keys [now] :as cofx} [_ chat-id]]
(let [mailserver-topics (:mailserver/topics db) (let [now (quot now 1000)]
chat-id (:current-chat-id db) (mailserver/fetch-history cofx chat-id
{:from (- now (* 2.5 mailserver/one-day))
:to (- now (* 2 mailserver/one-day))}))))
(handlers/register-handler-fx
:chat.ui/fetch-history-pressed84-96
(fn [{:keys [now] :as cofx} [_ chat-id]]
(let [now (quot now 1000)]
(mailserver/fetch-history cofx chat-id
{:from (- now (* 4 mailserver/one-day))
:to (- now (* 3.5 mailserver/one-day))}))))
(handlers/register-handler-fx
:chat.ui/fill-gaps
(fn [{:keys [db] :as cofx} [_ gap-ids]]
(let [chat-id (:current-chat-id db)
topic (chat.db/topic-by-current-chat db) topic (chat.db/topic-by-current-chat db)
gap (chat.db/messages-gap mailserver-topics topic)] gaps (keep
(fn [id]
(get-in db [:mailserver/gaps chat-id id]))
gap-ids)]
(mailserver/fill-the-gap (mailserver/fill-the-gap
cofx cofx
(assoc gap {:gaps gaps
:topic topic :topic topic
:chat-id chat-id))))) :chat-id chat-id}))))
(handlers/register-handler-fx (handlers/register-handler-fx
:chat.ui/remove-chat-pressed :chat.ui/remove-chat-pressed
@ -777,7 +797,8 @@
:chat.ui/load-more-messages :chat.ui/load-more-messages
[(re-frame/inject-cofx :data-store/get-messages) [(re-frame/inject-cofx :data-store/get-messages)
(re-frame/inject-cofx :data-store/get-user-statuses) (re-frame/inject-cofx :data-store/get-user-statuses)
(re-frame/inject-cofx :data-store/get-referenced-messages)] (re-frame/inject-cofx :data-store/get-referenced-messages)
(re-frame/inject-cofx :data-store/all-gaps)]
(fn [cofx _] (fn [cofx _]
(chat.loading/load-more-messages cofx))) (chat.loading/load-more-messages cofx)))

View File

@ -12,14 +12,13 @@
[status-im.group-chats.db :as group-chats.db] [status-im.group-chats.db :as group-chats.db]
[status-im.i18n :as i18n] [status-im.i18n :as i18n]
[status-im.native-module.core :as native-module] [status-im.native-module.core :as native-module]
[status-im.transport.chat.core :as transport.chat]
[status-im.transport.message.group-chat :as message.group-chat] [status-im.transport.message.group-chat :as message.group-chat]
[status-im.transport.message.protocol :as protocol] [status-im.transport.message.protocol :as protocol]
[status-im.transport.message.public-chat :as transport.public-chat]
[status-im.transport.partitioned-topic :as transport.topic] [status-im.transport.partitioned-topic :as transport.topic]
[status-im.utils.clocks :as utils.clocks] [status-im.utils.clocks :as utils.clocks]
[status-im.utils.config :as config] [status-im.utils.fx :as fx]
[status-im.utils.fx :as fx])) [status-im.mailserver.core :as mailserver]
[taoensso.timbre :as log]))
;; Description of the flow: ;; Description of the flow:
;; the flow is complicated a bit by 2 asynchronous call to status-go, which might make the logic a bit more opaque. ;; the flow is complicated a bit by 2 asynchronous call to status-go, which might make the logic a bit more opaque.
@ -213,10 +212,17 @@
events [create-event events [create-event
(members-added-event clock-value selected-contacts)]] (members-added-event clock-value selected-contacts)]]
(fx/merge
cofx
{:group-chats/sign-membership {:chat-id chat-id {:group-chats/sign-membership {:chat-id chat-id
:from my-public-key :from my-public-key
:events events} :events events}
:db (assoc db :group/selected-contacts #{})})) :db (assoc db :group/selected-contacts #{})}
(mailserver/upsert-mailserver-topic
{:chat-ids [chat-id]
:topic transport.topic/discovery-topic-hash
:fetch? false})
(mailserver/process-next-messages-request))))
(fx/defn remove-member (fx/defn remove-member
"Format group update message and sign membership" "Format group update message and sign membership"
@ -236,7 +242,7 @@
(fx/defn join-chat (fx/defn join-chat
"Format group update message and sign membership" "Format group update message and sign membership"
[{:keys [db] :as cofx} chat-id] [cofx chat-id]
(let [my-public-key (accounts.db/current-public-key cofx) (let [my-public-key (accounts.db/current-public-key cofx)
last-clock-value (get-last-clock-value cofx chat-id) last-clock-value (get-last-clock-value cofx chat-id)
chat (get-in cofx [:db :chats chat-id]) chat (get-in cofx [:db :chats chat-id])
@ -244,9 +250,16 @@
(when (valid-event? chat (assoc event (when (valid-event? chat (assoc event
:from :from
my-public-key)) my-public-key))
(fx/merge
cofx
{:group-chats/sign-membership {:chat-id chat-id {:group-chats/sign-membership {:chat-id chat-id
:from my-public-key :from my-public-key
:events [event]}}))) :events [event]}}
(mailserver/upsert-mailserver-topic
{:chat-ids [chat-id]
:topic transport.topic/discovery-topic-hash
:fetch false})
(mailserver/process-next-messages-request)))))
(fx/defn make-admin (fx/defn make-admin
"Format group update with make admin message and sign membership" "Format group update with make admin message and sign membership"

View File

@ -18,7 +18,8 @@
[status-im.accounts.update.core :as accounts.update] [status-im.accounts.update.core :as accounts.update]
[status-im.ui.screens.navigation :as navigation] [status-im.ui.screens.navigation :as navigation]
[status-im.transport.partitioned-topic :as transport.topic] [status-im.transport.partitioned-topic :as transport.topic]
[status-im.ui.screens.mobile-network-settings.utils :as mobile-network-utils])) [status-im.ui.screens.mobile-network-settings.utils :as mobile-network-utils]
[status-im.utils.random :as rand]))
;; How do mailserver work ? ;; How do mailserver work ?
;; ;;
@ -35,6 +36,7 @@
(def one-day (* 24 3600)) (def one-day (* 24 3600))
(def seven-days (* 7 one-day)) (def seven-days (* 7 one-day))
(def max-gaps-range (* 30 one-day))
(def max-request-range one-day) (def max-request-range one-day)
(def maximum-number-of-attempts 2) (def maximum-number-of-attempts 2)
(def request-timeout 30) (def request-timeout 30)
@ -249,7 +251,8 @@
(fx/merge cofx (fx/merge cofx
{:db (cond-> (dissoc db :mailserver/current-request) {:db (cond-> (dissoc db :mailserver/current-request)
gap-request? gap-request?
(assoc :mailserver/fetching-gaps-in-progress {}))} (-> (assoc :mailserver/fetching-gaps-in-progress {})
(dissoc :mailserver/planned-gap-requests)))}
(if added? (if added?
(mark-trusted-peer) (mark-trusted-peer)
(add-peer))))) (add-peer)))))
@ -371,7 +374,8 @@
:force-to? (not (nil? force-request-to))}))))) :force-to? (not (nil? force-request-to))})))))
(defn aggregate-requests (defn aggregate-requests
[acc {:keys [topic from to force-to?]}] [acc {:keys [topic from to force-to? gap chat-id]}]
(when from
(update acc [from to force-to?] (update acc [from to force-to?]
(fn [{:keys [topics]}] (fn [{:keys [topics]}]
{:topics ((fnil conj #{}) topics topic) {:topics ((fnil conj #{}) topics topic)
@ -379,17 +383,23 @@
:to to :to to
;; To is sent to the mailserver only when force-to? is true, ;; To is sent to the mailserver only when force-to? is true,
;; also we use to calculate when the last-request was sent. ;; also we use to calculate when the last-request was sent.
:force-to? force-to?}))) :force-to? force-to?
:gap gap
:chat-id chat-id}))))
(defn prepare-messages-requests (defn prepare-messages-requests
[{{:keys [:mailserver/requests-from [{{:keys [:mailserver/requests-from
:mailserver/requests-to :mailserver/requests-to
:mailserver/topics]} :db} :mailserver/topics
:mailserver/planned-gap-requests]} :db}
default-request-to] default-request-to]
(transduce (transduce
(keep (topic->request default-request-to requests-from requests-to)) (keep (topic->request default-request-to requests-from requests-to))
(completing aggregate-requests vals) (completing aggregate-requests vals)
(reduce
aggregate-requests
{} {}
(vals planned-gap-requests))
topics)) topics))
(fx/defn process-next-messages-request (fx/defn process-next-messages-request
@ -504,8 +514,11 @@
"if the chat is the only chat of the mailserver topic delete the mailserver topic "if the chat is the only chat of the mailserver topic delete the mailserver topic
and process-next-messages-requests again to remove pending request for that topic and process-next-messages-requests again to remove pending request for that topic
otherwise remove the chat-id of the chat from the mailserver topic and save" otherwise remove the chat-id of the chat from the mailserver topic and save"
[{:keys [db now] :as cofx} chat-id] [{:keys [db] :as cofx} chat-id]
(let [topic (get-in db [:transport/chats chat-id :topic]) (let [{:keys [public?] :as chat} (get-in db [:chats chat-id])
topic (if (and chat (not public?))
transport.topic/discovery-topic-hash
(get-in db [:transport/chats chat-id :topic]))
{:keys [chat-ids] :as mailserver-topic} (update (get-in db [:mailserver/topics topic]) {:keys [chat-ids] :as mailserver-topic} (update (get-in db [:mailserver/topics topic])
:chat-ids :chat-ids
disj chat-id)] disj chat-id)]
@ -519,97 +532,220 @@
{:topic topic {:topic topic
:mailserver-topic mailserver-topic})]}))) :mailserver-topic mailserver-topic})]})))
(defn calculate-gap (fx/defn remove-gaps
[{:keys [gap-from [{:keys [db]} chat-id]
gap-to {:db (update db :mailserver/gaps dissoc chat-id)
last-request] :as config} :data-store/tx [(data-store.mailservers/delete-all-gaps-by-chat chat-id)]})
{:keys [request-from
request-to]}] (fx/defn remove-range
(merge config [{:keys [db]} chat-id]
{:db (update db :mailserver/ranges dissoc chat-id)
:data-store/tx [(data-store.mailservers/delete-range chat-id)]})
(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 (cond
(nil? gap-from)
{:gap-from request-to
:gap-to request-to
:last-request request-to}
;;------GF GT--------LRT F---T
(> request-from last-request)
{:gap-from last-request
:gap-to request-from
:last-request request-to}
;;------GF GT--------LRT
;; F----------T
(and (>= last-request request-from gap-to)
(> request-to last-request))
{:last-request request-to}
;;------GF GT--------LRT
;; F----T ;; F----T
(and (>= last-request request-from gap-to) ;; RF---RT
(>= last-request request-to gap-to)) (< to request-from)
config acc
;;------GF GT--------LRT ;; F----T
;; F-------T ;; RF---RT
(and (> gap-to request-from gap-from) (< request-to from)
(>= last-request request-to gap-to)) (reduced acc)
{:gap-to request-from}
;;------GF GT--------LRT
;; F-T
(and (> gap-to request-from gap-from)
(> gap-to request-to gap-from))
config
;;------GF GT--------LRT
;; F------T ;; F------T
(and (>= gap-from request-from) ;; RF-----RT
(> gap-to request-to gap-from)) (and (<= request-from from)
{:gap-from request-to} (< from request-to to))
(let [updated-gap (assoc gap
:from request-to
:to to)]
(reduced
(update acc :updated-gaps assoc id updated-gap)))
;;---------GF=GT=LRT ;; F------T
;; F---T ;; RF----------RT
(and (>= gap-from request-from) (and (<= request-from from)
(>= gap-from request-to) (<= to request-to))
(= gap-from last-request)) (update acc :deleted-gaps conj (:id gap))
{:gap-from request-to}
;;------GF GT--------LRT ;; F---------T
;; F---T ;; RF-------RT
(and (>= gap-from request-from) (and (< from request-from to)
(>= gap-from request-to)) (<= to request-to))
config (let [updated-gap (assoc gap
:from from
:to request-from)]
(update acc :updated-gaps assoc id updated-gap))
;;------GF GT--------LRT ;; F---------T
;; F-------------T ;; RF---RT
(and (>= gap-from request-from) (and (< from request-from)
(>= last-request request-to gap-to)) (< request-to to))
{:gap-from last-request (reduced
:gap-to last-request (-> acc
:last-request last-request} (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}])))
;;------GF GT--------LRT :else acc))
;; F------------------------T {}
(and (>= gap-from request-from) (sort-by :from (vals chat-gaps)))))
(>= request-to last-request))
{:gap-from request-to
:gap-to request-to
:last-request request-to}
;;------GF GT--------LRT (defn check-all-gaps
;; F-----------------T [gaps chat-ids request]
(and (> gap-to request-from gap-from) (transduce
(>= request-to last-request)) (map (fn [chat-id]
{:gap-to request-from (let [chat-gaps (get gaps chat-id)]
:last-request request-to}))) [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)
:data-store/tx (map data-store.mailservers/save-chat-requests-range
(vals updated-ranges))})))
(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]}]
(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)]
{: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/tx
(conj
(map
data-store.mailservers/save-mailserver-requests-gap
(concat (mapcat vals (vals updated-gaps))
(mapcat vals (vals prepared-new-gaps))))
(data-store.mailservers/delete-mailserver-requests-gaps
(mapcat val deleted-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] (defn get-updated-mailserver-topics [db requested-topics from to]
(into (into
{} {}
(keep (fn [topic] (keep (fn [topic]
(when-let [config (get-in db [:mailserver/topics topic])] (when-let [config (get-in db [:mailserver/topics topic])]
[topic (calculate-gap config [topic (update-mailserver-topic config
{:request-from from {:request-from from
:request-to to})]))) :request-to to})])))
requested-topics)) requested-topics))
@ -636,6 +772,7 @@
:mailserver/request-messages {:web3 (:web3 db) :mailserver/request-messages {:web3 (:web3 db)
:mailserver mailserver :mailserver mailserver
:request request-with-cursor}})) :request request-with-cursor}}))
(let [{:keys [gap chat-id]} request]
(fx/merge cofx (fx/merge cofx
{:db (-> db {:db (-> db
(dissoc :mailserver/current-request) (dissoc :mailserver/current-request)
@ -646,15 +783,17 @@
(update :mailserver/topics merge mailserver-topics) (update :mailserver/topics merge mailserver-topics)
(update :mailserver/fetching-gaps-in-progress (update :mailserver/fetching-gaps-in-progress
(fn [gaps] (fn [gaps]
(if (executing-gap-request? db) (if gap
(dissoc gaps (:chat-id request)) (update gaps chat-id dissoc gap)
gaps)))) gaps)))
(update :mailserver/planned-gap-requests
dissoc gap))
:data-store/tx (mapv (fn [[topic mailserver-topic]] :data-store/tx (mapv (fn [[topic mailserver-topic]]
(data-store.mailservers/save-mailserver-topic-tx (data-store.mailservers/save-mailserver-topic-tx
{:topic topic {:topic topic
:mailserver-topic mailserver-topic})) :mailserver-topic mailserver-topic}))
mailserver-topics)} mailserver-topics)}
(process-next-messages-request))))))) (process-next-messages-request))))))))
(fx/defn retry-next-messages-request (fx/defn retry-next-messages-request
[{:keys [db] :as cofx}] [{:keys [db] :as cofx}]
@ -689,6 +828,7 @@
:dispatch-n (map :dispatch-n (map
#(identity [:chat.ui/join-time-messages-checked %]) #(identity [:chat.ui/join-time-messages-checked %])
never-synced-chats-in-request)} never-synced-chats-in-request)}
(update-chats-and-gaps cursor)
(update-mailserver-topics {:request-id requestID (update-mailserver-topics {:request-id requestID
:cursor cursor})) :cursor cursor}))
(fx/merge (fx/merge
@ -700,11 +840,13 @@
{:ms 1000 {:ms 1000
:dispatch [:chat.ui/join-time-messages-checked %]}) :dispatch [:chat.ui/join-time-messages-checked %]})
never-synced-chats-in-request))} never-synced-chats-in-request))}
(update-chats-and-gaps cursor)
(update-mailserver-topics {:request-id requestID (update-mailserver-topics {:request-id requestID
:cursor cursor}))) :cursor cursor})))
(fx/merge (fx/merge
cofx cofx
{:mailserver/increase-limit []} {:mailserver/increase-limit []}
(update-chats-and-gaps cursor)
(update-mailserver-topics {:request-id requestID (update-mailserver-topics {:request-id requestID
:cursor cursor})))) :cursor cursor}))))
(handle-request-error cofx errorMessage)))) (handle-request-error cofx errorMessage))))
@ -725,24 +867,29 @@
add the chat-id to the topic and reset last-request add the chat-id to the topic and reset last-request
there was no filter for the chat and messages for that there was no filter for the chat and messages for that
so the whole history for that topic needs to be re-fetched" so the whole history for that topic needs to be re-fetched"
[{:keys [db now] :as cofx} {:keys [topic chat-id]}] [{:keys [db now] :as cofx} {:keys [topic chat-ids fetch?]
(let [{:keys [chat-ids] :as current-mailserver-topic} :or {fetch? true}}]
(get-in db [:mailserver/topics topic] {:chat-ids #{}})] (let [current-mailserver-topic (get-in db [:mailserver/topics topic]
(when-not (contains? chat-ids chat-id) {:chat-ids #{}})
existing-ids (:chat-ids current-mailserver-topic)
chat-id (first chat-ids)]
(when-not (every? (partial contains? existing-ids) chat-ids)
(let [{:keys [new-account? public-key]} (:account/account db) (let [{:keys [new-account? public-key]} (:account/account db)
now-s (quot now 1000) now-s (quot now 1000)
last-request (if (and new-account? last-request (if (or
(not fetch?)
(and new-account?
(or (= chat-id :discovery-topic) (or (= chat-id :discovery-topic)
(and (and
(string? chat-id) (string? chat-id)
(string/starts-with? (string/starts-with?
chat-id chat-id
public-key)))) public-key)))))
(- now-s 10) (- now-s 10)
(- now-s max-request-range)) (- now-s max-request-range))
mailserver-topic (-> current-mailserver-topic mailserver-topic (-> current-mailserver-topic
(assoc :last-request last-request) (assoc :last-request last-request)
(update :chat-ids conj chat-id))] (update :chat-ids clojure.set/union (set chat-ids)))]
(fx/merge cofx (fx/merge cofx
{:db (assoc-in db [:mailserver/topics topic] mailserver-topic) {:db (assoc-in db [:mailserver/topics topic] mailserver-topic)
:data-store/tx [(data-store.mailservers/save-mailserver-topic-tx :data-store/tx [(data-store.mailservers/save-mailserver-topic-tx
@ -751,7 +898,6 @@
(fx/defn fetch-history (fx/defn fetch-history
[{:keys [db] :as cofx} chat-id {:keys [from to]}] [{:keys [db] :as cofx} chat-id {:keys [from to]}]
(log/debug "fetch-history" "chat-id:" chat-id "from-timestamp:" from) (log/debug "fetch-history" "chat-id:" chat-id "from-timestamp:" from)
(let [public-key (accounts.db/current-public-key cofx) (let [public-key (accounts.db/current-public-key cofx)
topic (or (get-in db [:transport/chats chat-id :topic]) topic (or (get-in db [:transport/chats chat-id :topic])
@ -764,28 +910,33 @@
(process-next-messages-request)))) (process-next-messages-request))))
(fx/defn fill-the-gap (fx/defn fill-the-gap
[{:keys [db] :as cofx} {:keys [exists? from to topic chat-id]}] [{:keys [db] :as cofx} {:keys [gaps topic chat-id]}]
(let [mailserver (get-mailserver-when-ready cofx) (let [mailserver (get-mailserver-when-ready cofx)
request {:from from requests (into {}
(map
(fn [{:keys [from to id]}]
[id
{:from (max from
(- to max-request-range))
:to to :to to
:force-to? true :force-to? true
:topics [topic] :topics [topic]
:chat-id chat-id}] :topic topic
(when exists? :chat-id chat-id
{:db :gap id}]))
(-> db gaps)
(assoc first-request (val (first requests))
:mailserver/pending-requests 1 current-request (:mailserver/current-request db)]
:mailserver/current-request request (cond-> {:db (-> db
:mailserver/request-to to) (assoc :mailserver/planned-gap-requests requests)
(update :mailserver/fetching-gaps-in-progress (update :mailserver/fetching-gaps-in-progress
assoc chat-id request)) assoc chat-id requests))}
(not current-request)
:mailserver/request-messages (-> (assoc-in [:db :mailserver/current-request] first-request)
(assoc :mailserver/request-messages
{:web3 (:web3 db) {:web3 (:web3 db)
:mailserver mailserver :mailserver mailserver
:request request}}))) :request first-request})))))
(fx/defn resend-request (fx/defn resend-request
[{:keys [db] :as cofx} {:keys [request-id]}] [{:keys [db] :as cofx} {:keys [request-id]}]
@ -814,7 +965,8 @@
{:db (-> db {:db (-> db
(dissoc :mailserver/current-request) (dissoc :mailserver/current-request)
(update :mailserver/fetching-gaps-in-progress (update :mailserver/fetching-gaps-in-progress
dissoc (:chat-id current-request)))} dissoc (:chat-id current-request))
(dissoc :mailserver/planned-gap-requests))}
mailserver mailserver
(let [{:keys [topics from to cursor limit] :as request} current-request (let [{:keys [topics from to cursor limit] :as request} current-request
@ -981,3 +1133,25 @@
(fx/merge cofx (fx/merge cofx
(accounts.update/update-settings (assoc-in settings [:mailserver current-fleet] mailserver-id) (accounts.update/update-settings (assoc-in settings [:mailserver current-fleet] mailserver-id)
{})))) {}))))
(fx/defn initialize-ranges
[{:keys [:data-store/all-chat-requests-ranges db]}]
{:db (assoc db :mailserver/ranges all-chat-requests-ranges)})
(fx/defn load-gaps
[{:keys [db now :data-store/all-gaps]} chat-id]
(when-not (get-in db [:chats chat-id :gaps-loaded?])
(let [now-s (quot now 1000)
gaps (all-gaps chat-id)
outdated-gaps (into [] (comp (filter #(< (:to %)
(- now-s max-gaps-range)))
(map :id))
(vals gaps))
gaps (apply dissoc gaps outdated-gaps)]
{:db
(-> db
(assoc-in [:chats chat-id :gaps-loaded?] true)
(assoc-in [:mailserver/gaps chat-id] gaps))
:data-store/tx
[(data-store.mailservers/delete-mailserver-requests-gaps
outdated-gaps)]})))

View File

@ -15,6 +15,4 @@
(fx/defn unsubscribe-from-chat (fx/defn unsubscribe-from-chat
"Unsubscribe from chat on transport layer" "Unsubscribe from chat on transport layer"
[cofx chat-id] [cofx chat-id]
(fx/merge cofx (remove-transport-chat cofx chat-id))
(mailserver/remove-chat-from-mailserver-topic chat-id)
(remove-transport-chat chat-id)))

View File

@ -85,7 +85,7 @@
(fn [{:keys [topic chat-id filter]}] (fn [{:keys [topic chat-id filter]}]
[(add-filter chat-id filter) [(add-filter chat-id filter)
(mailserver/upsert-mailserver-topic {:topic topic (mailserver/upsert-mailserver-topic {:topic topic
:chat-id chat-id})]) :chat-ids [chat-id]})])
filters)] filters)]
(apply fx/merge cofx (apply fx/merge cofx
{:db (dissoc db :filters/after-adding-discovery-filter)} {:db (dissoc db :filters/after-adding-discovery-filter)}

View File

@ -26,6 +26,14 @@
{:label (i18n/label :t/fetch-history) {:label (i18n/label :t/fetch-history)
:action #(re-frame/dispatch [:chat.ui/fetch-history-pressed chat-id])}) :action #(re-frame/dispatch [:chat.ui/fetch-history-pressed chat-id])})
(defn fetch-history48-60 [chat-id]
{:label "Fetch 48-60h"
:action #(re-frame/dispatch [:chat.ui/fetch-history-pressed48-60 chat-id])})
(defn fetch-history84-96 [chat-id]
{:label "Fetch 84-96h"
:action #(re-frame/dispatch [:chat.ui/fetch-history-pressed84-96 chat-id])})
(defn- delete-chat [chat-id group?] (defn- delete-chat [chat-id group?]
{:label (i18n/label :t/delete-chat) {:label (i18n/label :t/delete-chat)
:action #(re-frame/dispatch [(if group? :action #(re-frame/dispatch [(if group?
@ -37,18 +45,24 @@
[(view-profile chat-id) [(view-profile chat-id)
(clear-history) (clear-history)
(fetch-history chat-id) (fetch-history chat-id)
#_(fetch-history48-60 chat-id)
#_(fetch-history84-96 chat-id)
(delete-chat chat-id false)]) (delete-chat chat-id false)])
(defn- group-chat-actions [chat-id] (defn- group-chat-actions [chat-id]
[(group-info chat-id) [(group-info chat-id)
(clear-history) (clear-history)
(fetch-history chat-id) (fetch-history chat-id)
#_(fetch-history48-60 chat-id)
#_(fetch-history84-96 chat-id)
(delete-chat chat-id true)]) (delete-chat chat-id true)])
(defn- public-chat-actions [chat-id] (defn- public-chat-actions [chat-id]
[(share-chat chat-id) [(share-chat chat-id)
(clear-history) (clear-history)
(fetch-history chat-id) (fetch-history chat-id)
#_(fetch-history48-60 chat-id)
#_(fetch-history84-96 chat-id)
(delete-chat chat-id false)]) (delete-chat chat-id false)])
(defn actions [group-chat? chat-id public?] (defn actions [group-chat? chat-id public?]

View File

@ -70,8 +70,8 @@
[{{:keys [value]} :row}] [{{:keys [value]} :row}]
[message-datemark/chat-datemark-mobile value]) [message-datemark/chat-datemark-mobile value])
(defview gap [] (defview gap [{:keys [ids]}]
(letsubs [in-progress? [:chats/fetching-gap-in-progress?] (letsubs [in-progress? [:chats/fetching-gap-in-progress? ids]
connected? [:mailserver/connected?]] connected? [:mailserver/connected?]]
[react/view {:align-self :stretch [react/view {:align-self :stretch
:margin-top 24 :margin-top 24
@ -85,7 +85,7 @@
:background-color :white} :background-color :white}
[react/touchable-highlight [react/touchable-highlight
{:on-press (when (and connected? (not in-progress?)) {:on-press (when (and connected? (not in-progress?))
#(re-frame/dispatch [:chat.ui/fill-the-gap]))} #(re-frame/dispatch [:chat.ui/fill-gaps ids]))}
[react/view {:flex 1 [react/view {:flex 1
:align-items :center :align-items :center
:justify-content :center} :justify-content :center}
@ -98,8 +98,8 @@
(i18n/label :t/fetch-messages)])]]])) (i18n/label :t/fetch-messages)])]]]))
(defmethod message-row :gap (defmethod message-row :gap
[_] [{:keys [row]}]
[gap]) [gap (:gaps row)])
(defmethod message-row :default (defmethod message-row :default
[{:keys [group-chat current-public-key modal? row]}] [{:keys [group-chat current-public-key modal? row]}]

View File

@ -218,7 +218,8 @@
:whisper-timestamp 30 :whisper-timestamp 30
:timestamp 30} :timestamp 30}
{:type :gap {:type :gap
:value "25"} :value ":gapid1"
:gaps {:ids [:gapid1]}}
{:whisper-timestamp 20 {:whisper-timestamp 20
:timestamp 20 :timestamp 20
:content nil :content nil
@ -266,12 +267,14 @@
:timestamp 40}} :timestamp 40}}
nil nil
nil nil
{:from 25 [{:from 25
:exists? true})))) :to 30
:id :gapid1}]))))
(testing "simple case with gap after all messages" (testing "simple case with gap after all messages"
(is (= (is (=
'({:type :gap '({:type :gap
:value "100"} :value ":gapid1"
:gaps {:ids (:gapid1)}}
{:whisper-timestamp 40 {:whisper-timestamp 40
:timestamp 40 :timestamp 40
:content nil :content nil
@ -335,5 +338,6 @@
:timestamp 40}} :timestamp 40}}
nil nil
nil nil
{:from 100 [{:from 100
:exists? true}))))) :to 110
:id :gapid1}])))))

View File

@ -168,7 +168,7 @@
(testing "it adds the relevant transactions for realm" (testing "it adds the relevant transactions for realm"
(let [actual (chat/remove-chat cofx chat-id)] (let [actual (chat/remove-chat cofx chat-id)]
(is (:data-store/tx actual)) (is (:data-store/tx actual))
(is (= 5 (count (:data-store/tx actual)))))))) (is (= 8 (count (:data-store/tx actual))))))))
(deftest multi-user-chat? (deftest multi-user-chat?
(let [chat-id "1"] (let [chat-id "1"]

View File

@ -1,7 +1,8 @@
(ns status-im.test.mailserver.core (ns status-im.test.mailserver.core
(:require [cljs.test :refer-macros [deftest is testing]] (:require [cljs.test :refer-macros [deftest is testing]]
[status-im.transport.utils :as utils] [status-im.transport.utils :as utils]
[status-im.mailserver.core :as mailserver])) [status-im.mailserver.core :as mailserver]
[status-im.utils.random :as rand]))
(def enode "enode://08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404") (def enode "enode://08d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404")
(def enode2 "enode://12d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404") (def enode2 "enode://12d8eb6177b187049f6c97ed3f6c74fbbefb94c7ad10bafcaf4b65ce89c314dcfee0a8bc4e7a5b824dfa08b45b360cc78f34f0aff981f8386caa07652d2e601b@163.172.177.138:40404")
@ -628,186 +629,244 @@
:shh/generate-sym-key-from-password :shh/generate-sym-key-from-password
first))))))) first)))))))
(deftest calculate-gap (deftest check-existing-gaps
(testing "new topic" (let []
(is (= {:gap-from 10 (testing "no gaps"
:gap-to 10 (is (= {}
:last-request 10} (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}))))))
(mailserver/calculate-gap (defn rand-guid []
{:gap-from nil (let [gap-id (atom 0)]
:gap-to nil (fn []
:last-request nil} (swap! gap-id inc)
{:request-from 5 (str "gap" @gap-id))))
:request-to 10}))))
(testing "calculate-gap#1"
(is (= {:gap-from 3
:gap-to 4
:last-request 5}
(mailserver/calculate-gap (deftest prepare-new-gaps
{:gap-from 1 (testing "prepare-new-gaps"
:gap-to 2 (with-redefs [rand/guid (rand-guid)]
:last-request 3} (is (= {"chat1" {"gap1" {:id "gap1"
{:request-from 4 :chat-id "chat1"
:request-to 5})))) :from 20
(testing "calculate-gap#2" :to 30}}}
(is (= {:gap-from 1 (mailserver/prepare-new-gaps
:gap-to 2 nil
:last-request 5} {"chat1"
(mailserver/calculate-gap {:chat-id "chat1"
{:gap-from 1 :lowest-request-from 10
:gap-to 2 :highest-request-to 20}}
:last-request 4} {:from 30
{:request-from 3 :to 50}
:request-to 5})))) #{"chat1"})))))
(testing "calculate-gap#2-1" (testing "prepare-new-gaps request after known range"
(is (= {:gap-from 1 (with-redefs [rand/guid (rand-guid)]
:gap-to 2 (is (= {"chat1" {"gap1" {:id "gap1"
:last-request 4} :chat-id "chat1"
(mailserver/calculate-gap :from 12
{:gap-from 1 :to 14}
:gap-to 2 "gap2" {:chat-id "chat1"
:last-request 3} :from 20
{:request-from 3 :to 30
:request-to 4})))) :id "gap2"}}}
(testing "calculate-gap#3" (mailserver/prepare-new-gaps
(is (= {:gap-from 1 {"chat1" [{:chat-id "chat1"
:gap-to 2 :from 12
:last-request 5} :to 14}]}
(mailserver/calculate-gap {"chat1"
{:gap-from 1 {:chat-id "chat1"
:gap-to 2 :lowest-request-from 10
:last-request 5} :highest-request-to 20}}
{:request-from 3 {:from 30
:request-to 4})))) :to 50}
(testing "calculate-gap#3-1" #{"chat1"})))))
(is (= {:gap-from 1 (testing "prepare-new-gaps request before known range"
:gap-to 2 (with-redefs [rand/guid (rand-guid)]
:last-request 3} (is (= {"chat1" {"gap1" {:chat-id "chat1"
(mailserver/calculate-gap :from 12
{:gap-from 1 :to 14
:gap-to 2 :id "gap1"}
:last-request 3} "gap2" {:chat-id "chat1"
{:request-from 2 :from 8
:request-to 3})))) :to 10
(testing "calculate-gap#4" :id "gap2"}}}
(is (= {:gap-from 1 (mailserver/prepare-new-gaps
:gap-to 2 {"chat1" [{:chat-id "chat1"
:last-request 5} :from 12
(mailserver/calculate-gap :to 14}]}
{:gap-from 1 {"chat1"
:gap-to 2 {:chat-id "chat1"
:last-request 5} :lowest-request-from 10
{:request-from 3 :highest-request-to 20}}
:request-to 4})))) {:from 2
(testing "calculate-gap#5" :to 8}
(is (= {:gap-from 1 #{"chat1"}))))))
:gap-to 4
:last-request 5}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 4
:last-request 5}
{:request-from 2
:request-to 3}))))
(testing "calculate-gap#6"
(is (= {:gap-from 2
:gap-to 3
:last-request 4}
(mailserver/calculate-gap
{:gap-from 2
:gap-to 3
:last-request 4}
{:request-from 1
:request-to 2}))))
(testing "calculate-gap#6-1"
(is (= {:gap-from 1
:gap-to 4
:last-request 5}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 4
:last-request 5}
{:request-from 2
:request-to 3}))))
(testing "calculate-gap#0"
(is (= {:gap-from 2
:gap-to 3
:last-request 3}
(mailserver/calculate-gap
{:gap-from 3
:gap-to 3
:last-request 3}
{:request-from 1
:request-to 2}))))
(testing "calculate-gap#7"
(is (= {:gap-from 3
:gap-to 4
:last-request 5}
(mailserver/calculate-gap
{:gap-from 3
:gap-to 4
:last-request 5}
{:request-from 1
:request-to 2}))))
(testing "calculate-gap#8"
(is (= {:gap-from 5
:gap-to 5
:last-request 5}
(mailserver/calculate-gap
{:gap-from 2
:gap-to 3
:last-request 5}
{:request-from 1
:request-to 4}))))
(testing "calculate-gap#8-1"
(is (= {:gap-from 3
:gap-to 3
:last-request 3}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 2
:last-request 3}
{:request-from 1
:request-to 2}))))
(testing "calculate-gap#9"
(is (= {:gap-from 5
:gap-to 5
:last-request 5}
(mailserver/calculate-gap
{:gap-from 2
:gap-to 3
:last-request 4}
{:request-from 1
:request-to 5}))))
(testing "calculate-gap#9-1"
(is (= {:gap-from 3
:gap-to 3
:last-request 3}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 2
:last-request 3}
{:request-from 1
:request-to 3}))))
(testing "calculate-gap#10"
(is (= {:gap-from 1
:gap-to 2
:last-request 5}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 3
:last-request 4}
{:request-from 2
:request-to 5}))))
(testing "calculate-gap#10-1"
(is (= {:gap-from 1
:gap-to 2
:last-request 3}
(mailserver/calculate-gap
{:gap-from 1
:gap-to 2
:last-request 3}
{:request-from 2
:request-to 3})))))