[slow sign in] Denorlmalize last message

The last messages of the chats are necessary to properly show the chat
list, which is shown right after signing in. Before this commit, the
last message was retrieved as one of 20 last messages fetched for each
chat.

Implementation:
- `:last-message-content` and `:last-message-type` fields were added to
  `chat` entity
- both fields are updated when messages are received/sent
- loading of the last 20 messages for each chat was removed as
  initialization step
This commit is contained in:
Roman Volosovskyi 2018-12-09 17:55:28 +02:00
parent 07e8f6908d
commit c440b7a3a7
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
14 changed files with 129 additions and 98 deletions

View File

@ -66,42 +66,15 @@
message-id)))
statuses))
(fx/defn load-chats-messages
[{:keys [db get-stored-messages get-stored-user-statuses get-referenced-messages]
:as cofx}]
(let [chats (:chats db)
public-key (accounts.db/current-public-key cofx)]
(fx/merge
cofx
{:db (assoc
db :chats
(reduce
(fn [chats chat-id]
(let [{:keys [messages]} (get-stored-messages chat-id)
chat-messages (index-messages messages)
message-ids (keys chat-messages)
statuses (get-stored-user-statuses chat-id message-ids)
unviewed-messages-ids (get-unviewed-messages-ids statuses public-key)]
(update
chats
chat-id
assoc
:messages chat-messages
:message-statuses statuses
:loaded-unviewed-messages-ids unviewed-messages-ids
:referenced-messages (into {}
(get-referenced-messages
(get-referenced-ids chat-messages))))))
chats
(keys chats)))}
(group-messages))))
(fx/defn initialize-chats
"Initialize all persisted chats on startup"
[{:keys [db default-dapps all-stored-chats] :as cofx}]
(let [chats (reduce (fn [acc {:keys [chat-id] :as chat}]
(assoc acc chat-id chat))
(assoc acc chat-id
(assoc chat
:messages-initialized? false
:referenced-messages {}
:messages empty-message-map)))
{}
all-stored-chats)]
(fx/merge cofx
@ -154,6 +127,7 @@
loaded-unviewed-messages (get-unviewed-messages-ids new-statuses public-key)]
(fx/merge cofx
{:db (-> db
(assoc-in [:chats current-chat-id :messages-initialized?] true)
(update-in [:chats current-chat-id :messages] merge indexed-messages)
(update-in [:chats current-chat-id :message-statuses] merge new-statuses)
(update-in [:chats current-chat-id :referenced-messages]

View File

@ -266,6 +266,26 @@
(= from current-public-key))
messages))))))
(defn- update-last-message [all-chats chat-id]
(let [{:keys [messages message-groups]}
(get all-chats chat-id)
{:keys [content message-type]}
(->> (chat.db/sort-message-groups message-groups messages)
first
second
last
:message-id
(get messages))]
(chat-model/upsert-chat
{:chat-id chat-id
:last-message-content content
:last-message-type message-type})))
(fx/defn update-last-messages
[{:keys [db] :as cofx} chat-ids]
(apply fx/merge cofx
(map (partial update-last-message (:chats db)) chat-ids)))
(fx/defn receive-many
[{:keys [now] :as cofx} messages]
(let [valid-messages (keep #(when-let [chat-id (extract-chat-id cofx %)]
@ -293,7 +313,8 @@
messages-fx-fns
groups-fx-fns
(when platform/desktop?
[(chat-model/update-dock-badge-label)])))))
[(chat-model/update-dock-badge-label)])
[(update-last-messages chat-ids)]))))
(defn system-message [{:keys [now] :as cofx} {:keys [clock-value chat-id content from]}]
(let [{:keys [last-clock-value]} (get-in cofx [:db :chats chat-id])
@ -347,8 +368,11 @@
:raw-payload-hash (transport.utils/sha3 raw-payload))]
(fx/merge cofx
(chat-model/upsert-chat {:chat-id chat-id
:timestamp now})
(chat-model/upsert-chat
{:chat-id chat-id
:timestamp now
:last-message-content (:content message)
:last-message-type (:message-type message)})
(add-message false message-with-id true)
(add-own-status chat-id message-id :sending)
(send chat-id message-id wrapped-record))))

View File

@ -221,18 +221,6 @@
(when (= id (:public-key account))
(:photo-path account)))))
(re-frame/reg-sub
:chats/last-message
(fn [[_ chat-id]]
(re-frame/subscribe [:chats/chat chat-id]))
(fn [{:keys [messages message-groups]}]
(->> (chat.db/sort-message-groups message-groups messages)
first
second
last
:message-id
(get messages))))
(re-frame/reg-sub
:chats/unread-messages-number
:<- [:chats/active-chats]

View File

@ -1,10 +1,12 @@
(ns status-im.data-store.chats
(:require [goog.object :as object]
[cljs.core.async :as async]
[re-frame.core :as re-frame]
[status-im.utils.ethereum.core :as utils.ethereum]
[status-im.utils.clocks :as utils.clocks]
[status-im.data-store.realm.core :as core]))
[status-im.data-store.realm.core :as core]
[status-im.data-store.messages :as messages]
[status-im.utils.core :as utils]
[cljs.tools.reader.edn :as edn]))
(defn remove-empty-vals
"Remove key/value when empty seq or nil"
@ -60,7 +62,9 @@
(update :tags #(into #{} %))
(update :membership-updates (partial unmarshal-membership-updates chat-id))
;; We cap the clock value to a safe value in case the db has been polluted
(assoc :last-clock-value (get-last-clock-value chat-id))))
(assoc :last-clock-value (get-last-clock-value chat-id))
(update :last-message-type keyword)
(update :last-message-content edn/read-string)))
(re-frame/reg-cofx
:data-store/all-chats
@ -73,12 +77,14 @@
(defn save-chat-tx
"Returns tx function for saving chat"
[{:keys [chat-id] :as chat}]
[chat]
(fn [realm]
(core/create
realm
:chat
(update chat :membership-updates marshal-membership-updates)
(-> chat
(update :membership-updates marshal-membership-updates)
(utils/update-if-present :last-message-content messages/prepare-content))
true)))
;; Only used in debug mode

View File

@ -66,7 +66,7 @@
(fn [cofx _]
(assoc cofx :get-referenced-messages get-references-by-ids)))
(defn- prepare-content [content]
(defn prepare-content [content]
(if (string? content)
content
(pr-str content)))

View File

@ -223,3 +223,10 @@
:tags {:type "string[]"}
:unviewed-messages-count {:type :int
:default 0}}})
(def v10
(update v9 :properties merge
{:last-message-content {:type :string
:optional true}
:last-message-type {:type :string
:optional true}}))

View File

@ -291,6 +291,19 @@
browser/v8
dapp-permissions/v9])
(def v28 [chat/v10
transport/v7
contact/v3
message/v9
mailserver/v11
mailserver-topic/v1
user-status/v2
membership-update/v1
installation/v2
local-storage/v1
browser/v8
dapp-permissions/v9])
;; put schemas ordered by version
(def schemas [{:schema v1
:schemaVersion 1
@ -372,4 +385,7 @@
:migration migrations/v26}
{:schema v27
:schemaVersion 27
:migration migrations/v27}])
:migration migrations/v27}
{:schema v28
:schemaVersion 28
:migration migrations/v28}])

View File

@ -298,3 +298,21 @@
(doseq [status @statuses-to-be-deleted]
(.delete new-realm status))))
(defn get-last-message [realm chat-id]
(->
(.objects realm "message")
(.filtered (str "chat-id=\"" chat-id "\""))
(.sorted "timestamp" true)
(aget 0)))
(defn v28 [old-realm new-realm]
(let [chats (.objects new-realm "chat")]
(dotimes [i (.-length chats)]
(let [chat (aget chats i)
chat-id (aget chat "chat-id")]
(when-let [last-message (get-last-message new-realm chat-id)]
(let [content (aget last-message "content")
message-type (aget last-message "message-type")]
(aset chat "last-message-content" content)
(aset chat "last-message-type" message-type)))))))

View File

@ -91,14 +91,6 @@
(fn [cofx [_ encryption-key error]]
(init/handle-init-store-error cofx encryption-key)))
(handlers/register-handler-fx
:load-chats-messages
[(re-frame/inject-cofx :data-store/get-messages)
(re-frame/inject-cofx :data-store/get-referenced-messages)
(re-frame/inject-cofx :data-store/get-user-statuses)]
(fn [cofx]
(chat-loading/load-chats-messages cofx)))
(handlers/register-handler-fx
:init-chats
[(re-frame/inject-cofx :web3/get-web3)

View File

@ -114,13 +114,18 @@
[react/text {:style style/empty-chat-text-name} (:name contact)]]
(i18n/label :t/empty-chat-description))]])))
(defview messages-view [group-chat modal?]
(defview messages-view [chat group-chat modal?]
(letsubs [messages [:chats/current-chat-messages-stream]
chat [:chats/current-chat]
current-public-key [:account/public-key]]
{:component-did-mount #(re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true
:input-focused? false}])}
(if (empty? messages)
{:component-did-mount
(fn [args]
(when-not (:messages-initialized? (second (.-argv (.-props args))))
(re-frame/dispatch [:chat.ui/load-more-messages]))
(re-frame/dispatch [:chat.ui/set-chat-ui-props
{:messages-focused? true
:input-focused? false}]))}
(if (and (empty? messages)
(:messages-initialized? chat))
[empty-chat-container chat]
[list/flat-list {:data messages
:key-fn #(or (:message-id %) (:value %))
@ -134,6 +139,10 @@
:enableEmptySections true
:keyboardShouldPersistTaps :handled}])))
(defview messages-view-wrapper [group-chat modal?]
(letsubs [chat [:chats/current-chat]]
[messages-view chat group-chat modal?]))
(defview chat-root [modal?]
(letsubs [{:keys [group-chat public?]} [:chats/current-chat]
show-bottom-info? [:chats/current-chat-ui-prop :show-bottom-info?]
@ -151,7 +160,7 @@
[chat-toolbar public? modal?]
(if (or (= :chat current-view) modal?)
[messages-view-animation
[messages-view group-chat modal?]]
[messages-view-wrapper group-chat modal?]]
[react/view style/message-view-preview])
[input/container]
(when show-bottom-info?

View File

@ -19,13 +19,18 @@
[status-im.ui.components.action-button.action-button :as action-button]
[status-im.utils.config :as config]))
(views/defview chat-list-item-inner-view [{:keys [chat-id name group-chat color public? public-key] :as chat-item}]
(views/defview chat-list-item-inner-view [{:keys [chat-id name group-chat
color public? public-key
last-message-content
last-message-type]
:as chat-item}]
(views/letsubs [photo-path [:contacts/chat-photo chat-id]
unviewed-messages-count [:chats/unviewed-messages-count chat-id]
chat-name [:chats/chat-name chat-id]
current-chat-id [:chats/current-chat-id]
{:keys [content] :as last-message} [:chats/last-message chat-id]]
(let [name (or chat-name
current-chat-id [:chats/current-chat-id]]
(let [last-message {:content last-message-content
:message-type last-message-type}
name (or chat-name
(gfycat/generate-gfy public-key))
[unviewed-messages-label large?] [(utils/unread-messages-count unviewed-messages-count) true]
current? (= current-chat-id chat-id)]
@ -52,7 +57,7 @@
:style styles/chat-last-message}
(if (= constants/content-type-command (:content-type last-message))
[chat-item/command-short-preview last-message]
(or (:text content)
(or (:text last-message-content)
(i18n/label :no-messages-yet)))]]
[react/view {:style styles/timestamp}
[chat-item/message-timestamp (:timestamp last-message)]
@ -140,14 +145,7 @@
(fn [this]
(let [[_ loading?] (.. this -props -argv)]
(when loading?
(re-frame/dispatch [:init-chats]))))
:component-did-update
(fn [this [_ old-loading?]]
(let [[_ loading?] (.. this -props -argv)]
(when (and (false? loading?)
(true? old-loading?))
(re-frame/dispatch [:load-chats-messages]))))}
(re-frame/dispatch [:init-chats]))))}
[react/view {:style styles/chat-list-view}
[react/view {:style styles/chat-list-header}
[search-input search-filter]

View File

@ -100,14 +100,7 @@
(when loading?
(utils/set-timeout
#(re-frame/dispatch [:init-chats])
100))))
:component-did-update
(fn [this [_ old-loading?]]
(let [[_ loading?] (.. this -props -argv)]
(when (and (false? loading?)
(true? old-loading?))
(re-frame/dispatch [:load-chats-messages]))))}
100))))}
[react/view styles/container
[toolbar show-welcome? (and network-initialized? (not rpc-network?)) sync-state latest-block-number]
(cond show-welcome?

View File

@ -88,9 +88,10 @@
(defview home-list-chat-item-inner-view [{:keys [chat-id name color online
group-chat public?
public-key
timestamp]}]
(letsubs [last-message [:chats/last-message chat-id]
chat-name [:chats/chat-name chat-id]]
timestamp
last-message-content
last-message-type]}]
(letsubs [chat-name [:chats/chat-name chat-id]]
(let [truncated-chat-name (utils/truncate-str chat-name 30)]
[react/touchable-highlight {:on-press #(re-frame/dispatch [:chat.ui/navigate-to-chat chat-id])}
[react/view styles/chat-container
@ -100,10 +101,10 @@
[react/view styles/item-upper-container
[chat-list-item-name truncated-chat-name group-chat public? public-key]
[react/view styles/message-status-container
[message-timestamp (or (:timestamp last-message)
timestamp)]]]
[message-timestamp timestamp]]]
[react/view styles/item-lower-container
[message-content-text last-message]
[message-content-text {:content last-message-content
:content-type last-message-type}]
[unviewed-indicator chat-id]]]]])))
(defn home-list-browser-item-inner-view [{:keys [dapp url name browser-id] :as browser}]

View File

@ -10,9 +10,14 @@
:admins #{4}
:contacts #{2}
:tags #{}
:membership-updates []}
(chats/normalize-chat {:admins [4]
:contacts [2]})))))
:membership-updates []
:last-message-type :message-type
:last-message-content {:foo "bar"}}
(chats/normalize-chat
{:admins [4]
:contacts [2]
:last-message-type "message-type"
:last-message-content "{:foo \"bar\"}"})))))
(testing "membership-updates"
(with-redefs [chats/get-last-clock-value (constantly 42)]
(let [raw-events {"1" {:id "1" :type "members-added" :clock-value 10 :members [1 2] :signature "a" :from "id-1"}