Correct ordering of messages (#224)
This commit is contained in:
parent
2c72274025
commit
ff32691fea
|
@ -35,7 +35,8 @@
|
|||
status-im.chat.handlers.receive-message
|
||||
[cljs.core.async :as a]
|
||||
status-im.chat.handlers.webview-bridge
|
||||
status-im.chat.handlers.wallet-chat))
|
||||
status-im.chat.handlers.wallet-chat
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(register-handler :set-chat-ui-props
|
||||
(fn [db [_ ui-element value]]
|
||||
|
@ -289,20 +290,22 @@
|
|||
load-messages!
|
||||
init-chat))))
|
||||
|
||||
(defn prepare-chat
|
||||
[{:keys [contacts] :as db} [_ contact-id options]]
|
||||
(let [name (get-in contacts [contact-id :name])
|
||||
chat (merge {:chat-id contact-id
|
||||
:name (or name (generate-gfy))
|
||||
:color default-chat-color
|
||||
:group-chat false
|
||||
:is-active true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
:contacts [{:identity contact-id}]
|
||||
:dapp-url nil
|
||||
:dapp-hash nil}
|
||||
options)]
|
||||
(assoc db :new-chat chat)))
|
||||
(defn prepare-chat [{:keys [contacts]} chat-id chat]
|
||||
(let [name (get-in contacts [chat-id :name])]
|
||||
(merge {:chat-id chat-id
|
||||
:name (or name (generate-gfy))
|
||||
:color default-chat-color
|
||||
:group-chat false
|
||||
:is-active true
|
||||
:timestamp (.getTime (js/Date.))
|
||||
:contacts [{:identity chat-id}]
|
||||
:dapp-url nil
|
||||
:dapp-hash nil}
|
||||
chat)))
|
||||
|
||||
(defn add-new-chat
|
||||
[db [_ chat-id chat]]
|
||||
(assoc db :new-chat (prepare-chat db chat-id chat)))
|
||||
|
||||
(defn add-chat [{:keys [new-chat] :as db} [_ chat-id]]
|
||||
(-> db
|
||||
|
@ -318,7 +321,7 @@
|
|||
(dispatch [(or navigation-type :navigate-to) :chat chat-id]))
|
||||
|
||||
(register-handler ::start-chat!
|
||||
(-> prepare-chat
|
||||
(-> add-new-chat
|
||||
((enrich add-chat))
|
||||
((after save-new-chat!))
|
||||
((after open-chat!))))
|
||||
|
@ -331,10 +334,30 @@
|
|||
(dispatch [::start-chat! contact-id options navigation-type])))))
|
||||
|
||||
(register-handler :add-chat
|
||||
(-> prepare-chat
|
||||
(-> add-new-chat
|
||||
((enrich add-chat))
|
||||
((after save-new-chat!))))
|
||||
|
||||
(defn update-chat!
|
||||
[_ [_ chat]]
|
||||
(chats/save chat))
|
||||
|
||||
(register-handler :update-chat!
|
||||
(-> (fn [db [_ {:keys [chat-id] :as chat}]]
|
||||
(if (get-in db [:chats chat-id])
|
||||
(update-in db [:chats chat-id] merge chat)
|
||||
db))
|
||||
((after update-chat!))))
|
||||
|
||||
(register-handler :upsert-chat!
|
||||
(fn [db [_ {:keys [chat-id clock-value] :as opts}]]
|
||||
(let [chat (if (chats/exists? chat-id)
|
||||
(let [{old-clock-value :clock-value :as chat} (chats/get-by-id chat-id)]
|
||||
(assoc chat :clock-value (+ (max old-clock-value clock-value)) 1))
|
||||
(prepare-chat db chat-id opts))]
|
||||
(chats/save chat)
|
||||
(update-in db [:chats chat-id] merge chat))))
|
||||
|
||||
(register-handler :switch-command-suggestions!
|
||||
(u/side-effect!
|
||||
(fn [db]
|
||||
|
@ -453,17 +476,6 @@
|
|||
(fn [db [_ chat-id mode]]
|
||||
(assoc-in db [:kb-mode chat-id] mode)))
|
||||
|
||||
(defn update-chat!
|
||||
[_ [_ chat]]
|
||||
(chats/save chat))
|
||||
|
||||
(register-handler :update-chat!
|
||||
(-> (fn [db [_ {:keys [chat-id] :as chat}]]
|
||||
(if (get-in db [:chats chat-id])
|
||||
(update-in db [:chats chat-id] merge chat)
|
||||
db))
|
||||
((after update-chat!))))
|
||||
|
||||
(register-handler :check-autorun
|
||||
(u/side-effect!
|
||||
(fn [{:keys [current-chat-id] :as db}]
|
||||
|
@ -474,3 +486,10 @@
|
|||
(a/<! (a/timeout 100))
|
||||
(dispatch [:set-chat-command (keyword autorun)])
|
||||
(dispatch [:animate-command-suggestions])))))))
|
||||
|
||||
(register-handler :inc-clock
|
||||
(u/side-effect!
|
||||
(fn [_ [_ chat-id]]
|
||||
(let [chat (-> (chats/get-by-id chat-id)
|
||||
(update :clock-value inc))]
|
||||
(dispatch [:update-chat! chat])))))
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
[status-im.utils.random :as random]
|
||||
[status-im.constants :refer [content-type-command-request]]
|
||||
[cljs.reader :refer [read-string]]
|
||||
[status-im.data-store.chats :as chats]))
|
||||
[status-im.data-store.chats :as chats]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn check-preview [{:keys [content] :as message}]
|
||||
(if-let [preview (:preview content)]
|
||||
|
@ -25,12 +26,17 @@
|
|||
(:public-key (accounts current-account-id)))
|
||||
|
||||
(defn receive-message
|
||||
[db [_ {:keys [from group-id chat-id message-id timestamp] :as message}]]
|
||||
(let [same-message (messages/get-by-id message-id)
|
||||
[db [_ {:keys [from group-id chat-id message-id timestamp clock-value] :as message :or {clock-value 0}}]]
|
||||
(let [same-message (messages/get-by-id message-id)
|
||||
current-identity (get-current-identity db)
|
||||
chat-id' (or group-id chat-id from)
|
||||
exists? (chats/exists? chat-id')
|
||||
active? (chats/is-active? chat-id')]
|
||||
chat-id' (or group-id chat-id from)
|
||||
exists? (chats/exists? chat-id')
|
||||
active? (chats/is-active? chat-id')
|
||||
clock-value (if (= clock-value 0)
|
||||
(-> (chats/get-by-id chat-id')
|
||||
(get :clock-value)
|
||||
(inc))
|
||||
clock-value)]
|
||||
(when (and (not same-message)
|
||||
(not= from current-identity)
|
||||
(or (not exists?) active?))
|
||||
|
@ -40,10 +46,12 @@
|
|||
(cu/check-author-direction previous-message)
|
||||
(check-preview))
|
||||
:chat-id chat-id'
|
||||
:timestamp (or timestamp (random/timestamp)))]
|
||||
:timestamp (or timestamp (random/timestamp))
|
||||
:clock-value clock-value)]
|
||||
(store-message message')
|
||||
(when-not exists?
|
||||
(dispatch [:add-chat chat-id' (when group-chat? {:group-chat true})]))
|
||||
(dispatch [:upsert-chat! {:chat-id chat-id'
|
||||
:group-chat group-chat?
|
||||
:clock-value clock-value}])
|
||||
(dispatch [::add-message message'])
|
||||
(when (= (:content-type message') content-type-command-request)
|
||||
(dispatch [:add-request chat-id' message']))
|
||||
|
@ -53,9 +61,9 @@
|
|||
(u/side-effect!
|
||||
(fn [_ [_ {:keys [from to payload]}]]
|
||||
(dispatch [:received-message (merge payload
|
||||
{:from from
|
||||
:to to
|
||||
:chat-id from})]))))
|
||||
{:from from
|
||||
:to to
|
||||
:chat-id from})]))))
|
||||
|
||||
(register-handler :received-message
|
||||
(u/side-effect! receive-message))
|
||||
|
|
|
@ -13,10 +13,11 @@
|
|||
default-number-of-messages]]
|
||||
[status-im.utils.datetime :as datetime]
|
||||
[status-im.protocol.core :as protocol]
|
||||
[taoensso.timbre :refer-macros [debug]]))
|
||||
[taoensso.timbre :refer-macros [debug]]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn prepare-command
|
||||
[identity chat-id
|
||||
[identity chat-id clock-value
|
||||
{:keys [id preview preview-string params command to-message handler-data]}]
|
||||
(let [content {:command (command :name)
|
||||
:params params}]
|
||||
|
@ -32,7 +33,8 @@
|
|||
:rendered-preview preview
|
||||
:to-message to-message
|
||||
:type (:type command)
|
||||
:has-handler (:has-handler command)}))
|
||||
:has-handler (:has-handler command)
|
||||
:clock-value (inc clock-value)}))
|
||||
|
||||
(register-handler :send-chat-message
|
||||
(u/side-effect!
|
||||
|
@ -76,8 +78,9 @@
|
|||
(u/side-effect!
|
||||
(fn [{:keys [current-public-key] :as db}
|
||||
[_ {:keys [chat-id staged-command handler-data] :as params}]]
|
||||
(let [command' (->> (assoc staged-command :handler-data handler-data)
|
||||
(prepare-command current-public-key chat-id)
|
||||
(let [{:keys [clock-value]} (get-in db [:chats chat-id])
|
||||
command' (->> (assoc staged-command :handler-data handler-data)
|
||||
(prepare-command current-public-key chat-id clock-value)
|
||||
(cu/check-author-direction db chat-id))]
|
||||
(dispatch [:clear-command chat-id (:id staged-command)])
|
||||
(dispatch [::send-command! (assoc params :command command')])))))
|
||||
|
@ -144,7 +147,7 @@
|
|||
(register-handler ::prepare-message
|
||||
(u/side-effect!
|
||||
(fn [db [_ {:keys [chat-id identity message] :as params}]]
|
||||
(let [{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
(let [{:keys [group-chat clock-value]} (get-in db [:chats chat-id])
|
||||
message' (cu/check-author-direction
|
||||
db chat-id
|
||||
{:message-id (random/id)
|
||||
|
@ -153,7 +156,8 @@
|
|||
:from identity
|
||||
:content-type text-content-type
|
||||
:outgoing true
|
||||
:timestamp (time/now-ms)})
|
||||
:timestamp (time/now-ms)
|
||||
:clock-value (inc clock-value)})
|
||||
message'' (if group-chat
|
||||
(assoc message' :group-id chat-id :message-type :group-user-message)
|
||||
(assoc message' :to chat-id :message-type :user-message))
|
||||
|
@ -179,7 +183,7 @@
|
|||
chat-id :chat-id}]]
|
||||
(when (and message (cu/not-console? chat-id))
|
||||
(let [message' (select-keys message [:from :message-id])
|
||||
payload (select-keys message [:timestamp :content :content-type])
|
||||
payload (select-keys message [:timestamp :content :content-type :clock-value])
|
||||
options {:web3 web3
|
||||
:message (assoc message' :payload payload)}]
|
||||
(if (= message-type :group-user-message)
|
||||
|
@ -189,26 +193,29 @@
|
|||
:keypair {:public public-key
|
||||
:private private-key})))
|
||||
(protocol/send-message! (assoc-in options
|
||||
[:message :to] (:to message)))))))))
|
||||
[:message :to] (:to message))))
|
||||
(dispatch [:inc-clock chat-id]))))))
|
||||
|
||||
(register-handler ::send-command-protocol!
|
||||
(u/side-effect!
|
||||
(fn [{:keys [web3 current-public-key chats] :as db} [_ {:keys [chat-id command]}]]
|
||||
(let [{:keys [content message-id]} command]
|
||||
(let [{:keys [content message-id clock-value]} command]
|
||||
(when (cu/not-console? chat-id)
|
||||
(let [{:keys [public-key private-key]} (chats chat-id)
|
||||
{:keys [group-chat]} (get-in db [:chats chat-id])
|
||||
payload {:content content
|
||||
:content-type content-type-command
|
||||
:timestamp (datetime/now-ms)}
|
||||
:timestamp (datetime/now-ms)
|
||||
:clock-value clock-value}
|
||||
options {:web3 web3
|
||||
:message {:from current-public-key
|
||||
:message-id message-id
|
||||
:payload payload}}]
|
||||
:message {:from current-public-key
|
||||
:message-id message-id
|
||||
:payload payload}}]
|
||||
(if group-chat
|
||||
(protocol/send-group-message! (assoc options
|
||||
:group-id chat-id
|
||||
:keypair {:public public-key
|
||||
:private private-key}))
|
||||
(protocol/send-message! (assoc-in options
|
||||
[:message :to] chat-id)))))))))
|
||||
[:message :to] chat-id)))
|
||||
(dispatch [:inc-clock chat-id])))))))
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
[status-im.components.sync-state.offline :refer [offline-view]]
|
||||
[status-im.constants :refer [content-type-status]]
|
||||
[reagent.core :as r]
|
||||
[cljs-time.core :as t]))
|
||||
[cljs-time.core :as t]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn contacts-by-identity [contacts]
|
||||
(->> contacts
|
||||
|
@ -120,6 +121,7 @@
|
|||
(concat all-messages [status-message])
|
||||
all-messages)
|
||||
messages (->> all-messages
|
||||
(sort-by :clock-value >)
|
||||
(map #(assoc % :datemark (time/day-relative (:timestamp %))))
|
||||
(group-by :datemark)
|
||||
(map (fn [[k v]] [v {:type :datemark :value k}]))
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
[status-im.chat.styles.plain-message :as st-message]
|
||||
[status-im.chat.styles.response :as st-response]
|
||||
[reagent.core :as r]
|
||||
[clojure.string :as str]))
|
||||
[clojure.string :as str]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn send-button [{:keys [on-press accessibility-label]}]
|
||||
[touchable-highlight {:on-press on-press
|
||||
|
@ -57,13 +58,13 @@
|
|||
:default-value (or input-message "")}
|
||||
input-options)])
|
||||
|
||||
(defview command-input [input-options command]
|
||||
(defview command-input [input-options {:keys [fullscreen] :as command}]
|
||||
[input-command [:get-chat-command-content]
|
||||
icon-width [:command-icon-width]
|
||||
disable? [:get :disable-input]]
|
||||
[text-input (merge
|
||||
(command-input-options command icon-width disable?)
|
||||
{:auto-focus false
|
||||
{:auto-focus (not fullscreen)
|
||||
:blur-on-submit false
|
||||
:accessibility-label :input
|
||||
:on-focus #(dispatch [:set :focused true])
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
(defn chat-list-item-inner-view [{:keys [chat-id name color last-message
|
||||
online group-chat contacts] :as chat}]
|
||||
(let [last-message (or (first (:messages chat))
|
||||
(let [last-message (or (first (sort-by :clock-value > (:messages chat)))
|
||||
last-message)
|
||||
name (or name (generate-gfy))]
|
||||
[view st/chat-container
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
(defn get-last-message
|
||||
[chat-id]
|
||||
(-> (realm/get-by-field @realm/account-realm :message :chat-id chat-id)
|
||||
(realm/sorted :timestamp :desc)
|
||||
(realm/sorted :clock-value :desc)
|
||||
(realm/single-cljs)))
|
||||
|
||||
(defn get-unviewed
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.data-store.realm.schemas.account.core
|
||||
(:require [status-im.data-store.realm.schemas.account.v1.core :as v1]
|
||||
[status-im.data-store.realm.schemas.account.v2.core :as v2]))
|
||||
[status-im.data-store.realm.schemas.account.v2.core :as v2]
|
||||
[status-im.data-store.realm.schemas.account.v3.core :as v3]))
|
||||
|
||||
; put schemas ordered by version
|
||||
(def schemas [{:schema v1/schema
|
||||
|
@ -8,4 +9,7 @@
|
|||
:migration v1/migration}
|
||||
{:schema v2/schema
|
||||
:schemaVersion 2
|
||||
:migration v2/migration}])
|
||||
:migration v2/migration}
|
||||
{:schema v3/schema
|
||||
:schemaVersion 3
|
||||
:migration v3/migration}])
|
|
@ -0,0 +1,32 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v3.chat
|
||||
(:require [taoensso.timbre :as log]
|
||||
[status-im.components.styles :refer [default-chat-color]]))
|
||||
|
||||
(def schema {:name :chat
|
||||
:primaryKey :chat-id
|
||||
:properties {:chat-id "string"
|
||||
:name "string"
|
||||
:color {:type "string"
|
||||
:default default-chat-color}
|
||||
:group-chat {:type "bool"
|
||||
:indexed true}
|
||||
:is-active "bool"
|
||||
:timestamp "int"
|
||||
:contacts {:type "list"
|
||||
:objectType "chat-contact"}
|
||||
:dapp-url {:type :string
|
||||
:optional true}
|
||||
:dapp-hash {:type :int
|
||||
:optional true}
|
||||
:removed-at {:type :int
|
||||
:optional true}
|
||||
:last-message-id "string"
|
||||
:public-key {:type :string
|
||||
:optional true}
|
||||
:private-key {:type :string
|
||||
:optional true}
|
||||
:clock-value {:type :int
|
||||
:default 0}}})
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating chat schema"))
|
|
@ -0,0 +1,29 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v3.core
|
||||
(:require [taoensso.timbre :as log]
|
||||
[status-im.data-store.realm.schemas.account.v3.chat :as chat]
|
||||
[status-im.data-store.realm.schemas.account.v3.message :as message]
|
||||
[status-im.data-store.realm.schemas.account.v2.contact :as contact]
|
||||
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
|
||||
[status-im.data-store.realm.schemas.account.v1.command :as command]
|
||||
[status-im.data-store.realm.schemas.account.v1.discovery :as discovery]
|
||||
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
|
||||
[status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message]
|
||||
[status-im.data-store.realm.schemas.account.v1.request :as request]
|
||||
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
|
||||
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]))
|
||||
|
||||
(def schema [chat/schema
|
||||
chat-contact/schema
|
||||
command/schema
|
||||
contact/schema
|
||||
discovery/schema
|
||||
kv-store/schema
|
||||
message/schema
|
||||
pending-message/schema
|
||||
request/schema
|
||||
tag/schema
|
||||
user-status/schema])
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating v3 account database: " old-realm new-realm)
|
||||
(contact/migration old-realm new-realm))
|
|
@ -0,0 +1,34 @@
|
|||
(ns status-im.data-store.realm.schemas.account.v3.message
|
||||
(:require [taoensso.timbre :as log]))
|
||||
|
||||
(def schema {:name :message
|
||||
:primaryKey :message-id
|
||||
:properties {:message-id "string"
|
||||
:from "string"
|
||||
:to {:type "string"
|
||||
:optional true}
|
||||
:group-id {:type "string"
|
||||
:optional true}
|
||||
:content "string" ;; TODO make it ArrayBuffer
|
||||
:content-type "string"
|
||||
:timestamp "int"
|
||||
:chat-id {:type "string"
|
||||
:indexed true}
|
||||
:outgoing "bool"
|
||||
:retry-count {:type :int
|
||||
:default 0}
|
||||
:same-author "bool"
|
||||
:same-direction "bool"
|
||||
:preview {:type :string
|
||||
:optional true}
|
||||
:message-type {:type :string
|
||||
:optional true}
|
||||
:message-status {:type :string
|
||||
:optional true}
|
||||
:user-statuses {:type :list
|
||||
:objectType "user-status"}
|
||||
:clock-value {:type :int
|
||||
:default 0}}})
|
||||
|
||||
(defn migration [old-realm new-realm]
|
||||
(log/debug "migrating message schema"))
|
|
@ -23,7 +23,7 @@
|
|||
content)
|
||||
|
||||
payload' (-> message
|
||||
(select-keys [:message-id :requires-ack? :type])
|
||||
(select-keys [:message-id :requires-ack? :type :clock-value])
|
||||
(merge payload)
|
||||
(assoc :content content')
|
||||
prn-str
|
||||
|
|
Loading…
Reference in New Issue