Read at startup & write through async queues
This commit is contained in:
parent
8e7bf6eab4
commit
80fb8dde8b
|
@ -1,9 +1,11 @@
|
||||||
(ns status-im.chat.events
|
(ns status-im.chat.events
|
||||||
(:require [cljs.core.async :as async]
|
(:require [clojure.set :as set]
|
||||||
|
[cljs.core.async :as async]
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.gfycat.core :as gfycat]
|
[status-im.utils.gfycat.core :as gfycat]
|
||||||
|
[status-im.utils.async :as async-utils]
|
||||||
[status-im.chat.models :as model]
|
[status-im.chat.models :as model]
|
||||||
[status-im.chat.console :as console-chat]
|
[status-im.chat.console :as console-chat]
|
||||||
[status-im.chat.constants :as chat-const]
|
[status-im.chat.constants :as chat-const]
|
||||||
|
@ -13,6 +15,7 @@
|
||||||
[status-im.data-store.contacts :as contacts-store]
|
[status-im.data-store.contacts :as contacts-store]
|
||||||
[status-im.data-store.requests :as requests-store]
|
[status-im.data-store.requests :as requests-store]
|
||||||
[status-im.data-store.messages :as messages-store]
|
[status-im.data-store.messages :as messages-store]
|
||||||
|
[status-im.data-store.pending-messages :as pending-messages-store]
|
||||||
[status-im.ui.screens.navigation :as navigation]
|
[status-im.ui.screens.navigation :as navigation]
|
||||||
[status-im.protocol.core :as protocol]
|
[status-im.protocol.core :as protocol]
|
||||||
[status-im.constants :as const]
|
[status-im.constants :as const]
|
||||||
|
@ -46,6 +49,11 @@
|
||||||
(fn [cofx _]
|
(fn [cofx _]
|
||||||
(assoc cofx :get-stored-messages messages-store/get-by-chat-id)))
|
(assoc cofx :get-stored-messages messages-store/get-by-chat-id)))
|
||||||
|
|
||||||
|
(re-frame/reg-cofx
|
||||||
|
:stored-message-ids
|
||||||
|
(fn [cofx _]
|
||||||
|
(assoc cofx :stored-message-ids (messages-store/get-stored-message-ids))))
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
(re-frame/reg-cofx
|
||||||
:all-stored-chats
|
:all-stored-chats
|
||||||
(fn [cofx _]
|
(fn [cofx _]
|
||||||
|
@ -57,38 +65,50 @@
|
||||||
(assoc cofx :get-stored-chat chats-store/get-by-id)))
|
(assoc cofx :get-stored-chat chats-store/get-by-id)))
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
(re-frame/reg-cofx
|
||||||
:message-exists?
|
:inactive-chat-ids
|
||||||
(fn [cofx]
|
(fn [cofx _]
|
||||||
(assoc cofx :message-exists? messages-store/exists?)))
|
(assoc cofx :inactive-chat-ids (chats-store/get-inactive-ids))))
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
|
||||||
:get-last-clock-value
|
|
||||||
(fn [cofx]
|
|
||||||
(assoc cofx :get-last-clock-value messages-store/get-last-clock-value)))
|
|
||||||
|
|
||||||
;;;; Effects
|
;;;; Effects
|
||||||
|
|
||||||
(def ^:private update-message-queue (async/chan 100))
|
(def ^:private realm-queue (async-utils/task-queue 200))
|
||||||
|
|
||||||
(async/go-loop [message (async/<! update-message-queue)]
|
|
||||||
(when message
|
|
||||||
(messages-store/update-message message)
|
|
||||||
(recur (async/<! update-message-queue))))
|
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:update-message
|
:update-message
|
||||||
(fn [message]
|
(fn [message]
|
||||||
(async/put! update-message-queue message)))
|
(async/put! realm-queue #(messages-store/update-message message))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:save-message
|
:save-message
|
||||||
(fn [message]
|
(fn [message]
|
||||||
(messages-store/save message)))
|
(async/put! realm-queue #(messages-store/save message))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:delete-chat-messages
|
||||||
|
(fn [{:keys [chat-id group-chat debug?]}]
|
||||||
|
(when (or group-chat debug?)
|
||||||
|
(async/put! realm-queue #(messages-store/delete-by-chat-id chat-id)))
|
||||||
|
(async/put! realm-queue #(pending-messages-store/delete-all-by-chat-id chat-id))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:update-message-overhead
|
||||||
|
(fn [[chat-id network-status]]
|
||||||
|
(let [update-fn (if (= network-status :offline)
|
||||||
|
chats-store/inc-message-overhead
|
||||||
|
chats-store/reset-message-overhead)]
|
||||||
|
(async/put! realm-queue #(update-fn chat-id)))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:save-chat
|
:save-chat
|
||||||
(fn [chat]
|
(fn [chat]
|
||||||
(chats-store/save chat)))
|
(async/put! realm-queue #(chats-store/save chat))))
|
||||||
|
|
||||||
|
(re-frame/reg-fx
|
||||||
|
:delete-chat
|
||||||
|
(fn [{:keys [chat-id debug?]}]
|
||||||
|
(if debug?
|
||||||
|
(async/put! realm-queue #(chats-store/delete chat-id))
|
||||||
|
(async/put! realm-queue #(chats-store/set-inactive chat-id)))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:save-all-contacts
|
:save-all-contacts
|
||||||
|
@ -141,17 +161,18 @@
|
||||||
(fn [{{:keys [current-chat-id] :as db} :db get-stored-messages :get-stored-messages} _]
|
(fn [{{:keys [current-chat-id] :as db} :db get-stored-messages :get-stored-messages} _]
|
||||||
(when-not (get-in db [:chats current-chat-id :all-loaded?])
|
(when-not (get-in db [:chats current-chat-id :all-loaded?])
|
||||||
(let [loaded-count (count (get-in db [:chats current-chat-id :messages]))
|
(let [loaded-count (count (get-in db [:chats current-chat-id :messages]))
|
||||||
new-messages (get-stored-messages current-chat-id loaded-count)]
|
new-messages (index-messages (get-stored-messages current-chat-id loaded-count))]
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(update-in [:chats current-chat-id :messages] merge (index-messages new-messages))
|
(update-in [:chats current-chat-id :messages] merge new-messages)
|
||||||
|
(update-in [:chats current-chat-id :not-loaded-message-ids] #(apply disj % (keys new-messages)))
|
||||||
(assoc-in [:chats current-chat-id :all-loaded?]
|
(assoc-in [:chats current-chat-id :all-loaded?]
|
||||||
(> const/default-number-of-messages (count new-messages))))}))))
|
(> const/default-number-of-messages (count new-messages))))}))))
|
||||||
|
|
||||||
(handlers/register-handler-db
|
(handlers/register-handler-db
|
||||||
:set-message-shown
|
:message-appeared
|
||||||
[re-frame/trim-v]
|
[re-frame/trim-v]
|
||||||
(fn [db [{:keys [chat-id message-id]}]]
|
(fn [db [{:keys [chat-id message-id]}]]
|
||||||
(update-in db [:chats chat-id :messages message-id] assoc :new? false)))
|
(update-in db [:chats chat-id :messages message-id] assoc :appearing? false)))
|
||||||
|
|
||||||
(defn init-console-chat
|
(defn init-console-chat
|
||||||
[{:keys [chats] :accounts/keys [current-account-id] :as db}]
|
[{:keys [chats] :accounts/keys [current-account-id] :as db}]
|
||||||
|
@ -167,7 +188,6 @@
|
||||||
(not current-account-id)
|
(not current-account-id)
|
||||||
(update :dispatch-n concat [[:chat-received-message/add-when-commands-loaded console-chat/intro-message1]]))))
|
(update :dispatch-n concat [[:chat-received-message/add-when-commands-loaded console-chat/intro-message1]]))))
|
||||||
|
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:init-console-chat
|
:init-console-chat
|
||||||
(fn [{:keys [db]} _]
|
(fn [{:keys [db]} _]
|
||||||
|
@ -176,14 +196,18 @@
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:initialize-chats
|
:initialize-chats
|
||||||
[(re-frame/inject-cofx :all-stored-chats)
|
[(re-frame/inject-cofx :all-stored-chats)
|
||||||
|
(re-frame/inject-cofx :inactive-chat-ids)
|
||||||
(re-frame/inject-cofx :get-stored-messages)
|
(re-frame/inject-cofx :get-stored-messages)
|
||||||
(re-frame/inject-cofx :stored-unviewed-messages)
|
(re-frame/inject-cofx :stored-unviewed-messages)
|
||||||
|
(re-frame/inject-cofx :stored-message-ids)
|
||||||
(re-frame/inject-cofx :get-stored-unanswered-requests)]
|
(re-frame/inject-cofx :get-stored-unanswered-requests)]
|
||||||
(fn [{:keys [db
|
(fn [{:keys [db
|
||||||
all-stored-chats
|
all-stored-chats
|
||||||
|
inactive-chat-ids
|
||||||
stored-unanswered-requests
|
stored-unanswered-requests
|
||||||
get-stored-messages
|
get-stored-messages
|
||||||
stored-unviewed-messages]} _]
|
stored-unviewed-messages
|
||||||
|
stored-message-ids]} _]
|
||||||
(let [{:accounts/keys [account-creation?]} db
|
(let [{:accounts/keys [account-creation?]} db
|
||||||
load-default-contacts-event [:load-default-contacts!]]
|
load-default-contacts-event [:load-default-contacts!]]
|
||||||
(if account-creation?
|
(if account-creation?
|
||||||
|
@ -194,15 +218,19 @@
|
||||||
{}
|
{}
|
||||||
stored-unanswered-requests)
|
stored-unanswered-requests)
|
||||||
chats (reduce (fn [acc {:keys [chat-id] :as chat}]
|
chats (reduce (fn [acc {:keys [chat-id] :as chat}]
|
||||||
|
(let [chat-messages (index-messages (get-stored-messages chat-id))]
|
||||||
(assoc acc chat-id
|
(assoc acc chat-id
|
||||||
(assoc chat
|
(assoc chat
|
||||||
:unviewed-messages (get stored-unviewed-messages chat-id)
|
:unviewed-messages (get stored-unviewed-messages chat-id)
|
||||||
:requests (get chat->message-id->request chat-id)
|
:requests (get chat->message-id->request chat-id)
|
||||||
:messages (index-messages (get-stored-messages chat-id)))))
|
:messages chat-messages
|
||||||
|
:not-loaded-message-ids (set/difference (get stored-message-ids chat-id)
|
||||||
|
(-> chat-messages keys set))))))
|
||||||
{}
|
{}
|
||||||
all-stored-chats)]
|
all-stored-chats)]
|
||||||
(-> db
|
(-> db
|
||||||
(assoc :chats chats)
|
(assoc :chats chats
|
||||||
|
:deleted-chats inactive-chat-ids)
|
||||||
init-console-chat
|
init-console-chat
|
||||||
(update :dispatch-n conj load-default-contacts-event)))))))
|
(update :dispatch-n conj load-default-contacts-event)))))))
|
||||||
|
|
||||||
|
@ -272,7 +300,7 @@
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:add-chat-loaded-event
|
:add-chat-loaded-event
|
||||||
[re-frame/trim-v]
|
[(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v]
|
||||||
(fn [{:keys [db] :as cofx} [chat-id event]]
|
(fn [{:keys [db] :as cofx} [chat-id event]]
|
||||||
(if (get (:chats db) chat-id)
|
(if (get (:chats db) chat-id)
|
||||||
{:db (assoc-in db [:chats chat-id :chat-loaded-event] event)}
|
{:db (assoc-in db [:chats chat-id :chat-loaded-event] event)}
|
||||||
|
@ -282,7 +310,7 @@
|
||||||
;; TODO(janherich): remove this unnecessary event in the future (only model function `add-chat` will stay)
|
;; TODO(janherich): remove this unnecessary event in the future (only model function `add-chat` will stay)
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:add-chat
|
:add-chat
|
||||||
[re-frame/trim-v]
|
[(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v]
|
||||||
(fn [cofx [chat-id chat-props]]
|
(fn [cofx [chat-id chat-props]]
|
||||||
(model/add-chat cofx chat-id chat-props)))
|
(model/add-chat cofx chat-id chat-props)))
|
||||||
|
|
||||||
|
@ -305,7 +333,7 @@
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:start-chat
|
:start-chat
|
||||||
[re-frame/trim-v]
|
[(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v]
|
||||||
(fn [{:keys [db] :as cofx} [contact-id {:keys [navigation-replace?]}]]
|
(fn [{:keys [db] :as cofx} [contact-id {:keys [navigation-replace?]}]]
|
||||||
(when (not= (:current-public-key db) contact-id) ; don't allow to open chat with yourself
|
(when (not= (:current-public-key db) contact-id) ; don't allow to open chat with yourself
|
||||||
(if (get (:chats db) contact-id)
|
(if (get (:chats db) contact-id)
|
||||||
|
@ -319,13 +347,17 @@
|
||||||
;; TODO(janherich): remove this unnecessary event in the future (only model function `update-chat` will stay)
|
;; TODO(janherich): remove this unnecessary event in the future (only model function `update-chat` will stay)
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:update-chat!
|
:update-chat!
|
||||||
[(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v]
|
[re-frame/trim-v]
|
||||||
(fn [cofx [chat]]
|
(fn [cofx [chat]]
|
||||||
(model/update-chat cofx chat)))
|
(model/update-chat cofx chat)))
|
||||||
|
|
||||||
;; TODO(janherich): remove this unnecessary event in the future (only model function `upsert-chat` will stay)
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:upsert-chat!
|
:remove-chat
|
||||||
[(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v]
|
[re-frame/trim-v]
|
||||||
(fn [cofx [chat]]
|
(fn [{:keys [db]} [chat-id]]
|
||||||
(model/upsert-chat cofx chat)))
|
(let [chat (get-in db [:chats chat-id])]
|
||||||
|
{:db (-> db
|
||||||
|
(update :chats dissoc chat-id)
|
||||||
|
(update :deleted-chats (fnil conj #{}) chat-id))
|
||||||
|
:delete-chat chat
|
||||||
|
:delete-chat-messages chat})))
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
:contacts/keys [contacts]} db
|
:contacts/keys [contacts]} db
|
||||||
jail-id (or bot jail-id chat-id)
|
jail-id (or bot jail-id chat-id)
|
||||||
jail-command-name (or content-command-name command-name)]
|
jail-command-name (or content-command-name command-name)]
|
||||||
|
(if-not (get contacts jail-id) ;; bot is not even in contacts, do nothing
|
||||||
|
{:db db}
|
||||||
(if (get-in contacts [jail-id :jail-loaded?])
|
(if (get-in contacts [jail-id :jail-loaded?])
|
||||||
(let [path [(if (= :response (keyword type)) :responses :commands)
|
(let [path [(if (= :response (keyword type)) :responses :commands)
|
||||||
[jail-command-name
|
[jail-command-name
|
||||||
|
@ -47,7 +49,7 @@
|
||||||
[[::jail-command-data-response
|
[[::jail-command-data-response
|
||||||
jail-response message opts]])}})
|
jail-response message opts]])}})
|
||||||
{:db (update-in db [:contacts/contacts jail-id :jail-loaded-events]
|
{:db (update-in db [:contacts/contacts jail-id :jail-loaded-events]
|
||||||
conj [:request-command-message-data message opts])})))
|
conj [:request-command-message-data message opts])}))))
|
||||||
|
|
||||||
;;;; Handlers
|
;;;; Handlers
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
[re-frame.core :as re-frame]
|
[re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.chat.constants :as constants]
|
[status-im.chat.constants :as constants]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.chat.models :as model]
|
[status-im.chat.models :as model]
|
||||||
[status-im.chat.models.input :as input-model]
|
[status-im.chat.models.input :as input-model]
|
||||||
[status-im.chat.models.commands :as commands-model]
|
[status-im.chat.models.commands :as commands-model]
|
||||||
|
@ -193,7 +192,7 @@
|
||||||
:validation-messages nil
|
:validation-messages nil
|
||||||
:prev-command name})
|
:prev-command name})
|
||||||
(set-chat-input-metadata metadata)
|
(set-chat-input-metadata metadata)
|
||||||
(set-chat-input-text (str (chat-utils/command-name command)
|
(set-chat-input-text (str (commands-model/command-name command)
|
||||||
constants/spacing-char
|
constants/spacing-char
|
||||||
(when-not sequential-params
|
(when-not sequential-params
|
||||||
(input-model/join-command-args prefill)))))
|
(input-model/join-command-args prefill)))))
|
||||||
|
@ -476,9 +475,7 @@
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
:send-current-message
|
:send-current-message
|
||||||
[(re-frame/inject-cofx :random-id)
|
message-model/send-interceptors
|
||||||
(re-frame/inject-cofx :get-last-clock-value)
|
|
||||||
(re-frame/inject-cofx :get-stored-chat)]
|
|
||||||
(fn [{{:keys [current-chat-id current-public-key] :as db} :db message-id :random-id current-time :now
|
(fn [{{:keys [current-chat-id current-public-key] :as db} :db message-id :random-id current-time :now
|
||||||
:as cofx} _]
|
:as cofx} _]
|
||||||
(when-not (get-in db [:chat-ui-props current-chat-id :sending-in-progress?])
|
(when-not (get-in db [:chat-ui-props current-chat-id :sending-in-progress?])
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
(ns status-im.chat.events.receive-message
|
(ns status-im.chat.events.receive-message
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.data-store.chats :as chat-store]
|
|
||||||
[status-im.data-store.messages :as messages-store]
|
[status-im.data-store.messages :as messages-store]
|
||||||
[status-im.chat.events.commands :as commands-events]
|
[status-im.chat.events.commands :as commands-events]
|
||||||
[status-im.chat.models.message :as message-model]
|
[status-im.chat.models.message :as message-model]
|
||||||
|
@ -9,16 +8,7 @@
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.random :as random]))
|
[status-im.utils.random :as random]))
|
||||||
|
|
||||||
;;;; Coeffects
|
;;;; Handlers
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
|
||||||
:pop-up-chat?
|
|
||||||
(fn [cofx]
|
|
||||||
(assoc cofx :pop-up-chat? (fn [chat-id]
|
|
||||||
(or (not (chat-store/exists? chat-id))
|
|
||||||
(chat-store/is-active? chat-id))))))
|
|
||||||
|
|
||||||
;;;; FX
|
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
::received-message
|
::received-message
|
||||||
|
@ -30,6 +20,7 @@
|
||||||
:chat-received-message/add
|
:chat-received-message/add
|
||||||
message-model/receive-interceptors
|
message-model/receive-interceptors
|
||||||
(fn [{:keys [db] :as cofx} [{:keys [content] :as message}]]
|
(fn [{:keys [db] :as cofx} [{:keys [content] :as message}]]
|
||||||
|
(when (message-model/add-to-chat? cofx message)
|
||||||
(if (:command content)
|
(if (:command content)
|
||||||
;; we are dealing with received command message, we can't add it right away,
|
;; we are dealing with received command message, we can't add it right away,
|
||||||
;; we first need to fetch short-preview + preview and add it only after we already have those.
|
;; we first need to fetch short-preview + preview and add it only after we already have those.
|
||||||
|
@ -48,7 +39,7 @@
|
||||||
{:short-preview short-preview
|
{:short-preview short-preview
|
||||||
:preview preview})])}])})
|
:preview preview})])}])})
|
||||||
;; regular non command message, we can add it right away
|
;; regular non command message, we can add it right away
|
||||||
(message-model/receive cofx message))))
|
(message-model/receive cofx message)))))
|
||||||
|
|
||||||
;; TODO janherich: get rid of this special case once they hacky app start-up sequence is refactored
|
;; TODO janherich: get rid of this special case once they hacky app start-up sequence is refactored
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
(ns status-im.chat.events.send-message
|
(ns status-im.chat.events.send-message
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.chat.models.message :as message-model]
|
[status-im.chat.models.message :as message-model]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.data-store.chats :as chats-store]
|
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[status-im.protocol.core :as protocol]
|
[status-im.protocol.core :as protocol]
|
||||||
[status-im.utils.config :as config]
|
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.utils.random :as random]
|
|
||||||
[status-im.utils.types :as types]
|
[status-im.utils.types :as types]
|
||||||
[status-im.utils.datetime :as datetime]
|
|
||||||
[taoensso.timbre :as log]))
|
[taoensso.timbre :as log]))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
|
@ -34,13 +29,6 @@
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(protocol/send-message! value)))
|
(protocol/send-message! value)))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
|
||||||
:update-message-overhead!
|
|
||||||
(fn [[chat-id network-status]]
|
|
||||||
(if (= network-status :offline)
|
|
||||||
(chats-store/inc-message-overhead chat-id)
|
|
||||||
(chats-store/reset-message-overhead chat-id))))
|
|
||||||
|
|
||||||
;;;; Handlers
|
;;;; Handlers
|
||||||
|
|
||||||
(handlers/register-handler-fx
|
(handlers/register-handler-fx
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
(ns status-im.chat.handlers
|
(ns status-im.chat.handlers
|
||||||
(:require [re-frame.core :refer [enrich after debug dispatch reg-fx]]
|
(:require [re-frame.core :refer [after dispatch reg-fx]]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
[status-im.ui.components.styles :refer [default-chat-color]]
|
[status-im.ui.components.styles :refer [default-chat-color]]
|
||||||
[status-im.chat.constants :as chat-consts]
|
[status-im.chat.constants :as chat-consts]
|
||||||
[status-im.protocol.core :as protocol]
|
[status-im.protocol.core :as protocol]
|
||||||
[status-im.data-store.chats :as chats]
|
[status-im.data-store.chats :as chats]
|
||||||
[status-im.data-store.messages :as messages]
|
[status-im.data-store.messages :as messages]
|
||||||
[status-im.data-store.pending-messages :as pending-messages]
|
|
||||||
[status-im.constants :refer [text-content-type
|
[status-im.constants :refer [text-content-type
|
||||||
content-type-command
|
content-type-command
|
||||||
content-type-command-request
|
content-type-command-request
|
||||||
|
@ -15,33 +14,6 @@
|
||||||
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
[status-im.utils.handlers :refer [register-handler register-handler-fx] :as u]
|
||||||
status-im.chat.events))
|
status-im.chat.events))
|
||||||
|
|
||||||
(defn remove-chat
|
|
||||||
[db [_ chat-id]]
|
|
||||||
(update db :chats dissoc chat-id))
|
|
||||||
|
|
||||||
(reg-fx
|
|
||||||
::delete-messages
|
|
||||||
(fn [id]
|
|
||||||
(messages/delete-by-chat-id id)))
|
|
||||||
|
|
||||||
(defn delete-messages!
|
|
||||||
[{:keys [current-chat-id chats]} [_ chat-id]]
|
|
||||||
(let [id (or chat-id current-chat-id)
|
|
||||||
{:keys [group-chat]} (chats/get-by-id chat-id)]
|
|
||||||
(when group-chat
|
|
||||||
(messages/delete-by-chat-id id))))
|
|
||||||
|
|
||||||
(defn delete-chat!
|
|
||||||
[_ [_ chat-id]]
|
|
||||||
(let [{:keys [debug?]} (chats/get-by-id chat-id)]
|
|
||||||
(if debug?
|
|
||||||
(chats/delete chat-id)
|
|
||||||
(chats/set-inactive chat-id))))
|
|
||||||
|
|
||||||
(defn remove-pending-messages!
|
|
||||||
[_ [_ chat-id]]
|
|
||||||
(pending-messages/delete-all-by-chat-id chat-id))
|
|
||||||
|
|
||||||
(register-handler
|
(register-handler
|
||||||
:leave-group-chat
|
:leave-group-chat
|
||||||
;; todo order of operations tbd
|
;; todo order of operations tbd
|
||||||
|
@ -62,14 +34,6 @@
|
||||||
:message-id (random/id)}})))
|
:message-id (random/id)}})))
|
||||||
(dispatch [:remove-chat current-chat-id]))))
|
(dispatch [:remove-chat current-chat-id]))))
|
||||||
|
|
||||||
(register-handler
|
|
||||||
:remove-chat
|
|
||||||
(u/handlers->
|
|
||||||
remove-chat
|
|
||||||
delete-messages!
|
|
||||||
remove-pending-messages!
|
|
||||||
delete-chat!))
|
|
||||||
|
|
||||||
(register-handler :update-group-message
|
(register-handler :update-group-message
|
||||||
(u/side-effect!
|
(u/side-effect!
|
||||||
(fn [{:keys [current-public-key web3 chats]}
|
(fn [{:keys [current-public-key web3 chats]}
|
||||||
|
@ -93,11 +57,6 @@
|
||||||
:keypair keypair
|
:keypair keypair
|
||||||
:callback #(dispatch [:incoming-message %1 %2])}))))))))
|
:callback #(dispatch [:incoming-message %1 %2])}))))))))
|
||||||
|
|
||||||
(reg-fx
|
|
||||||
::save-public-chat
|
|
||||||
(fn [chat]
|
|
||||||
(chats/save chat)))
|
|
||||||
|
|
||||||
(reg-fx
|
(reg-fx
|
||||||
::start-watching-group
|
::start-watching-group
|
||||||
(fn [{:keys [group-id web3 current-public-key keypair]}]
|
(fn [{:keys [group-id web3 current-public-key keypair]}]
|
||||||
|
@ -122,17 +81,12 @@
|
||||||
(merge
|
(merge
|
||||||
(when-not exists?
|
(when-not exists?
|
||||||
{:db (assoc-in db [:chats (:chat-id chat)] chat)
|
{:db (assoc-in db [:chats (:chat-id chat)] chat)
|
||||||
::save-public-chat chat
|
:save-chat chat
|
||||||
::start-watching-group (merge {:group-id topic}
|
::start-watching-group (merge {:group-id topic}
|
||||||
(select-keys db [:web3 :current-public-key]))})
|
(select-keys db [:web3 :current-public-key]))})
|
||||||
{:dispatch-n [[:navigate-to-clean :home]
|
{:dispatch-n [[:navigate-to-clean :home]
|
||||||
[:navigate-to-chat topic]]}))))
|
[:navigate-to-chat topic]]}))))
|
||||||
|
|
||||||
(reg-fx
|
|
||||||
::save-chat
|
|
||||||
(fn [new-chat]
|
|
||||||
(chats/save new-chat)))
|
|
||||||
|
|
||||||
(reg-fx
|
(reg-fx
|
||||||
::start-listen-group
|
::start-listen-group
|
||||||
(fn [{:keys [new-chat web3 current-public-key]}]
|
(fn [{:keys [new-chat web3 current-public-key]}]
|
||||||
|
@ -193,7 +147,7 @@
|
||||||
{:db (-> db
|
{:db (-> db
|
||||||
(assoc-in [:chats (:chat-id new-chat)] new-chat)
|
(assoc-in [:chats (:chat-id new-chat)] new-chat)
|
||||||
(assoc :group/selected-contacts #{}))
|
(assoc :group/selected-contacts #{}))
|
||||||
::save-chat new-chat
|
:save-chat new-chat
|
||||||
::start-listen-group (merge {:new-chat new-chat}
|
::start-listen-group (merge {:new-chat new-chat}
|
||||||
(select-keys db [:web3 :current-public-key]))
|
(select-keys db [:web3 :current-public-key]))
|
||||||
:dispatch-n [[:navigate-to-clean :home]
|
:dispatch-n [[:navigate-to-clean :home]
|
||||||
|
|
|
@ -13,40 +13,45 @@
|
||||||
(update-in db [:chat-ui-props current-chat-id ui-element] not))
|
(update-in db [:chat-ui-props current-chat-id ui-element] not))
|
||||||
|
|
||||||
(defn- create-new-chat
|
(defn- create-new-chat
|
||||||
[{:keys [db now] :as cofx} chat-id chat-props]
|
[{:keys [db now] :as cofx} chat-id]
|
||||||
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
(let [name (get-in db [:contacts/contacts chat-id :name])]
|
||||||
(merge {:chat-id chat-id
|
{:chat-id chat-id
|
||||||
:name (or name (gfycat/generate-gfy chat-id))
|
:name (or name (gfycat/generate-gfy chat-id))
|
||||||
:color styles/default-chat-color
|
:color styles/default-chat-color
|
||||||
:group-chat false
|
:group-chat false
|
||||||
:is-active true
|
:is-active true
|
||||||
:timestamp now
|
:timestamp now
|
||||||
:contacts [{:identity chat-id}]}
|
:contacts [{:identity chat-id}]}))
|
||||||
chat-props)))
|
|
||||||
|
|
||||||
(defn add-chat
|
(defn add-chat
|
||||||
|
"Adds new chat to db & realm, if the chat with same id already exists, justs restores it"
|
||||||
([cofx chat-id]
|
([cofx chat-id]
|
||||||
(add-chat cofx chat-id {}))
|
(add-chat cofx chat-id {}))
|
||||||
([{:keys [db] :as cofx} chat-id chat-props]
|
([{:keys [db get-stored-chat] :as cofx} chat-id chat-props]
|
||||||
(let [new-chat (create-new-chat cofx chat-id chat-props)
|
(let [{:keys [chats deleted-chats]} db
|
||||||
existing-chats (:chats db)]
|
new-chat (merge (if (get deleted-chats chat-id)
|
||||||
{:db (cond-> db
|
(assoc (get-stored-chat chat-id) :is-active true)
|
||||||
(not (contains? existing-chats chat-id))
|
(create-new-chat cofx chat-id))
|
||||||
(update :chats assoc chat-id new-chat))
|
chat-props)]
|
||||||
|
{:db (-> db
|
||||||
|
(update :chats assoc chat-id new-chat)
|
||||||
|
(update :deleted-chats (fnil disj #{}) chat-id))
|
||||||
:save-chat new-chat})))
|
:save-chat new-chat})))
|
||||||
|
|
||||||
;; TODO (yenda): there should be an option to update the timestamp
|
;; TODO (yenda): there should be an option to update the timestamp
|
||||||
;; this shouldn't need a specific function like `upsert-chat` which
|
;; this shouldn't need a specific function like `upsert-chat` which
|
||||||
;; is wrongfuly named
|
;; is wrongfuly named
|
||||||
(defn update-chat
|
(defn update-chat
|
||||||
"Updates chat properties, if chat is not present in db, creates a default new one"
|
"Updates chat properties when not deleted, if chat is not present in app-db, creates a default new one"
|
||||||
[{:keys [db get-stored-chat] :as cofx} {:keys [chat-id] :as chat}]
|
[{:keys [db] :as cofx} {:keys [chat-id] :as chat-props}]
|
||||||
(let [chat (merge (or (get-stored-chat chat-id)
|
(let [{:keys [chats deleted-chats]} db]
|
||||||
(create-new-chat cofx chat-id {}))
|
(if (get deleted-chats chat-id) ;; when chat is deleted, don't change anything
|
||||||
chat)]
|
{:db db}
|
||||||
{:db (cond-> db
|
(let [chat (merge (or (get chats chat-id)
|
||||||
(:is-active chat) (update-in [:chats chat-id] merge chat))
|
(create-new-chat cofx chat-id))
|
||||||
:save-chat chat}))
|
chat-props)]
|
||||||
|
{:db (update-in db [:chats chat-id] merge chat)
|
||||||
|
:save-chat chat}))))
|
||||||
|
|
||||||
;; TODO (yenda): an upsert is suppose to add the entry if it doesn't
|
;; TODO (yenda): an upsert is suppose to add the entry if it doesn't
|
||||||
;; exist and update it if it does
|
;; exist and update it if it does
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
(defn- is-dapp? [all-contacts {:keys [identity]}]
|
(defn- is-dapp? [all-contacts {:keys [identity]}]
|
||||||
(get-in all-contacts [identity :dapp?]))
|
(get-in all-contacts [identity :dapp?]))
|
||||||
|
|
||||||
|
(defn command-name [{:keys [name]}]
|
||||||
|
(str chat-consts/command-char name))
|
||||||
|
|
||||||
(defn commands-responses
|
(defn commands-responses
|
||||||
"Returns map of commands/responses eligible for current chat."
|
"Returns map of commands/responses eligible for current chat."
|
||||||
[type access-scope->commands-responses {:keys [address]} {:keys [contacts group-chat public?]} all-contacts]
|
[type access-scope->commands-responses {:keys [address]} {:keys [contacts group-chat public?]} all-contacts]
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
[status-im.chat.constants :as const]
|
[status-im.chat.constants :as const]
|
||||||
[status-im.chat.models.commands :as commands-model]
|
[status-im.chat.models.commands :as commands-model]
|
||||||
[status-im.chat.views.input.validation-messages :refer [validation-message]]
|
[status-im.chat.views.input.validation-messages :refer [validation-message]]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.utils.phone-number :as phone-number]
|
[status-im.utils.phone-number :as phone-number]
|
||||||
[status-im.js-dependencies :as dependencies]
|
[status-im.js-dependencies :as dependencies]
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
[status-im.chat.events.requests :as requests-events]
|
[status-im.chat.events.requests :as requests-events]
|
||||||
[status-im.chat.models :as chat-model]
|
[status-im.chat.models :as chat-model]
|
||||||
[status-im.chat.models.commands :as commands-model]
|
[status-im.chat.models.commands :as commands-model]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.data-store.messages :as messages-store]
|
|
||||||
[status-im.utils.datetime :as datetime-utils]
|
[status-im.utils.datetime :as datetime-utils]
|
||||||
[status-im.utils.clocks :as clocks-utils]
|
[status-im.utils.clocks :as clocks-utils]
|
||||||
[status-im.utils.random :as random]))
|
[status-im.utils.random :as random]))
|
||||||
|
@ -16,12 +14,8 @@
|
||||||
(get accounts current-account-id))
|
(get accounts current-account-id))
|
||||||
|
|
||||||
(def receive-interceptors
|
(def receive-interceptors
|
||||||
[(re-frame/inject-cofx :message-exists?)
|
[(re-frame/inject-cofx :get-stored-message) (re-frame/inject-cofx :get-stored-chat)
|
||||||
(re-frame/inject-cofx :pop-up-chat?)
|
(re-frame/inject-cofx :random-id) re-frame/trim-v])
|
||||||
(re-frame/inject-cofx :get-last-clock-value)
|
|
||||||
(re-frame/inject-cofx :random-id)
|
|
||||||
(re-frame/inject-cofx :get-stored-chat)
|
|
||||||
re-frame/trim-v])
|
|
||||||
|
|
||||||
(defn- lookup-response-ref
|
(defn- lookup-response-ref
|
||||||
[access-scope->commands-responses account chat contacts response-name]
|
[access-scope->commands-responses account chat contacts response-name]
|
||||||
|
@ -32,35 +26,34 @@
|
||||||
contacts)]
|
contacts)]
|
||||||
(:ref (get available-commands-responses response-name))))
|
(:ref (get available-commands-responses response-name))))
|
||||||
|
|
||||||
(defn- add-message-to-db
|
(defn add-message-to-db
|
||||||
[db {:keys [message-id] :as message} chat-id current-chat?]
|
[db chat-id {:keys [message-id clock-value] :as message} current-chat?]
|
||||||
(cond-> (chat-utils/add-message-to-db db chat-id chat-id message (:new? message))
|
(let [prepared-message (cond-> (assoc message
|
||||||
|
:chat-id chat-id
|
||||||
|
:appearing? true)
|
||||||
(not current-chat?)
|
(not current-chat?)
|
||||||
(update-in [:chats chat-id :unviewed-messages] (fnil conj #{}) message-id)))
|
(assoc :appearing? false))]
|
||||||
|
(cond-> (-> db
|
||||||
|
(update-in [:chats chat-id :messages] assoc message-id prepared-message)
|
||||||
|
(update-in [:chats chat-id :last-clock-value] (fnil max 0) clock-value))
|
||||||
|
(not current-chat?)
|
||||||
|
(update-in [:chats chat-id :unviewed-messages] (fnil conj #{}) message-id))))
|
||||||
|
|
||||||
(defn receive
|
(defn receive
|
||||||
[{:keys [db message-exists? pop-up-chat? get-last-clock-value now] :as cofx}
|
[{:keys [db now] :as cofx}
|
||||||
{:keys [from group-id chat-id content-type content message-id timestamp clock-value]
|
{:keys [from group-id chat-id content-type content message-id timestamp clock-value]
|
||||||
:as message
|
:as message}]
|
||||||
:or {clock-value 0}}]
|
|
||||||
(let [{:keys [current-chat-id view-id
|
(let [{:keys [current-chat-id view-id
|
||||||
access-scope->commands-responses] :contacts/keys [contacts]} db
|
access-scope->commands-responses] :contacts/keys [contacts]} db
|
||||||
{:keys [public-key] :as current-account} (get-current-account db)
|
{:keys [public-key] :as current-account} (get-current-account db)
|
||||||
chat-identifier (or group-id chat-id from)
|
chat-identifier (or group-id chat-id from)
|
||||||
direct-message? (nil? group-id)]
|
current-chat? (and (= :chat view-id)
|
||||||
;; proceed with adding message if message is not already stored in realm,
|
|
||||||
;; it's not from current user (outgoing message) and it's for relevant chat
|
|
||||||
;; (either current active chat or new chat not existing yet or it's a direct message)
|
|
||||||
(when (and (not (message-exists? message-id))
|
|
||||||
(not= from public-key)
|
|
||||||
(or (pop-up-chat? chat-identifier)
|
|
||||||
direct-message?))
|
|
||||||
(let [current-chat? (and (= :chat view-id)
|
|
||||||
(= current-chat-id chat-identifier))
|
(= current-chat-id chat-identifier))
|
||||||
fx (if (get-in db [:chats chat-identifier])
|
fx (if (get-in db [:chats chat-identifier])
|
||||||
(chat-model/upsert-chat cofx {:chat-id chat-identifier
|
(chat-model/upsert-chat cofx {:chat-id chat-identifier
|
||||||
:group-chat (boolean group-id)})
|
:group-chat (boolean group-id)})
|
||||||
(chat-model/add-chat cofx chat-identifier))
|
(chat-model/add-chat cofx chat-identifier))
|
||||||
|
chat (get-in fx [:db :chats chat-identifier])
|
||||||
command-request? (= content-type constants/content-type-command-request)
|
command-request? (= content-type constants/content-type-command-request)
|
||||||
command (:command content)
|
command (:command content)
|
||||||
enriched-message (cond-> (assoc message
|
enriched-message (cond-> (assoc message
|
||||||
|
@ -69,7 +62,7 @@
|
||||||
:show? true
|
:show? true
|
||||||
:clock-value (clocks-utils/receive
|
:clock-value (clocks-utils/receive
|
||||||
clock-value
|
clock-value
|
||||||
(get-last-clock-value chat-identifier)))
|
(:last-clock-value chat)))
|
||||||
public-key
|
public-key
|
||||||
(assoc :user-statuses {public-key (if current-chat? :seen :received)})
|
(assoc :user-statuses {public-key (if current-chat? :seen :received)})
|
||||||
(and command command-request?)
|
(and command command-request?)
|
||||||
|
@ -80,10 +73,34 @@
|
||||||
contacts
|
contacts
|
||||||
command)))]
|
command)))]
|
||||||
(cond-> (-> fx
|
(cond-> (-> fx
|
||||||
(update :db add-message-to-db enriched-message chat-identifier current-chat?)
|
(update :db add-message-to-db chat-identifier enriched-message current-chat?)
|
||||||
(assoc :save-message (dissoc enriched-message :new?)))
|
(assoc :save-message (dissoc enriched-message :new?)))
|
||||||
command-request?
|
command-request?
|
||||||
(requests-events/add-request chat-identifier enriched-message))))))
|
(requests-events/add-request chat-identifier enriched-message))))
|
||||||
|
|
||||||
|
(defn add-to-chat?
|
||||||
|
[{:keys [db get-stored-message]} {:keys [group-id chat-id from message-id]}]
|
||||||
|
(let [chat-identifier (or group-id chat-id from)
|
||||||
|
{:keys [chats deleted-chats current-public-key]} db
|
||||||
|
{:keys [messages not-loaded-message-ids]} (get chats chat-identifier)]
|
||||||
|
(when (not= from current-public-key)
|
||||||
|
(if group-id
|
||||||
|
(not (or (get deleted-chats chat-identifier)
|
||||||
|
(get messages message-id)
|
||||||
|
(get not-loaded-message-ids message-id)))
|
||||||
|
(not (or (get messages message-id)
|
||||||
|
(get not-loaded-message-ids message-id)
|
||||||
|
(and (get deleted-chats chat-identifier)
|
||||||
|
(get-stored-message message-id))))))))
|
||||||
|
|
||||||
|
(defn message-seen-by? [message user-pk]
|
||||||
|
(= :seen (get-in message [:user-statuses user-pk])))
|
||||||
|
|
||||||
|
;;;; Send message
|
||||||
|
|
||||||
|
(def send-interceptors
|
||||||
|
[(re-frame/inject-cofx :random-id) (re-frame/inject-cofx :random-id-seq)
|
||||||
|
(re-frame/inject-cofx :get-stored-chat) re-frame/trim-v])
|
||||||
|
|
||||||
(defn- handle-message-from-bot [cofx {:keys [message chat-id]}]
|
(defn- handle-message-from-bot [cofx {:keys [message chat-id]}]
|
||||||
(when-let [message (cond
|
(when-let [message (cond
|
||||||
|
@ -171,19 +188,9 @@
|
||||||
(merge {:send-message (assoc-in options [:message :to] chat-id)}
|
(merge {:send-message (assoc-in options [:message :to] chat-id)}
|
||||||
(when-not command) {:send-notification fcm-token}))))))
|
(when-not command) {:send-notification fcm-token}))))))
|
||||||
|
|
||||||
;;;; Send message
|
(defn- prepare-message [params chat]
|
||||||
|
|
||||||
(def send-interceptors
|
|
||||||
[(re-frame/inject-cofx :random-id)
|
|
||||||
(re-frame/inject-cofx :random-id-seq)
|
|
||||||
(re-frame/inject-cofx :get-stored-chat)
|
|
||||||
(re-frame/inject-cofx :now)
|
|
||||||
(re-frame/inject-cofx :get-last-clock-value)
|
|
||||||
re-frame/trim-v])
|
|
||||||
|
|
||||||
(defn- prepare-message [clock-value params chat]
|
|
||||||
(let [{:keys [chat-id identity message-text]} params
|
(let [{:keys [chat-id identity message-text]} params
|
||||||
{:keys [group-chat public?]} chat
|
{:keys [group-chat public? last-clock-value]} chat
|
||||||
message {:message-id (random/id)
|
message {:message-id (random/id)
|
||||||
:chat-id chat-id
|
:chat-id chat-id
|
||||||
:content message-text
|
:content message-text
|
||||||
|
@ -191,7 +198,7 @@
|
||||||
:content-type constants/text-content-type
|
:content-type constants/text-content-type
|
||||||
:outgoing true
|
:outgoing true
|
||||||
:timestamp (datetime-utils/now-ms)
|
:timestamp (datetime-utils/now-ms)
|
||||||
:clock-value (clocks-utils/send clock-value)
|
:clock-value (clocks-utils/send last-clock-value)
|
||||||
:show? true}]
|
:show? true}]
|
||||||
(cond-> message
|
(cond-> message
|
||||||
(not group-chat)
|
(not group-chat)
|
||||||
|
@ -206,18 +213,16 @@
|
||||||
(not group-chat)
|
(not group-chat)
|
||||||
(assoc :to chat-id :message-type :user-message))))
|
(assoc :to chat-id :message-type :user-message))))
|
||||||
|
|
||||||
|
|
||||||
(defn send-message [{{:keys [network-status] :as db} :db
|
(defn send-message [{{:keys [network-status] :as db} :db
|
||||||
:keys [now get-stored-chat get-last-clock-value]}
|
:keys [now]}
|
||||||
{:keys [chat-id] :as params}]
|
{:keys [chat-id] :as params}]
|
||||||
(let [chat (get-in db [:chats chat-id])
|
(let [chat (get-in db [:chats chat-id])
|
||||||
message (prepare-message (get-last-clock-value chat-id) params chat)
|
message (prepare-message params chat)
|
||||||
params' (assoc params :message message)
|
params' (assoc params :message message)
|
||||||
|
fx {:db (add-message-to-db db chat-id message true)
|
||||||
fx {:db (chat-utils/add-message-to-db db chat-id chat-id message)
|
:update-message-overhead [chat-id network-status]
|
||||||
:update-message-overhead! [chat-id network-status]
|
|
||||||
:save-message message}]
|
:save-message message}]
|
||||||
(-> (merge fx (chat-model/upsert-chat (assoc fx :get-stored-chat get-stored-chat :now now)
|
(-> (merge fx (chat-model/upsert-chat (assoc fx :now now)
|
||||||
{:chat-id chat-id}))
|
{:chat-id chat-id}))
|
||||||
(as-> fx'
|
(as-> fx'
|
||||||
(merge fx' (send fx' params'))))))
|
(merge fx' (send fx' params'))))))
|
||||||
|
@ -263,22 +268,23 @@
|
||||||
:show? true}))
|
:show? true}))
|
||||||
|
|
||||||
(defn send-command
|
(defn send-command
|
||||||
[{{:keys [current-public-key network-status] :as db} :db
|
[{{:keys [current-public-key network-status chats] :as db} :db
|
||||||
:keys [now get-stored-chat random-id-seq get-last-clock-value]} result add-to-chat-id params]
|
:keys [now random-id-seq]} result add-to-chat-id params]
|
||||||
(let [{{:keys [handler-data
|
(let [{{:keys [handler-data
|
||||||
command]
|
command]
|
||||||
:as content} :command
|
:as content} :command
|
||||||
chat-id :chat-id} params
|
chat-id :chat-id} params
|
||||||
request (:request handler-data)
|
request (:request handler-data)
|
||||||
|
last-clock-value (get-in chats [chat-id :last-clock-value])
|
||||||
hidden-params (->> (:params command)
|
hidden-params (->> (:params command)
|
||||||
(filter :hidden)
|
(filter :hidden)
|
||||||
(map :name))
|
(map :name))
|
||||||
command' (prepare-command current-public-key chat-id (get-last-clock-value chat-id) request content)
|
command' (prepare-command current-public-key chat-id last-clock-value request content)
|
||||||
params' (assoc params :command command')
|
params' (assoc params :command command')
|
||||||
|
|
||||||
fx {:db (-> (merge db (:db result))
|
fx {:db (-> (merge db (:db result))
|
||||||
(chat-utils/add-message-to-db add-to-chat-id chat-id command'))
|
(add-message-to-db chat-id command' true))
|
||||||
:update-message-overhead! [chat-id network-status]
|
:update-message-overhead [chat-id network-status]
|
||||||
:save-message (-> command'
|
:save-message (-> command'
|
||||||
(assoc :chat-id chat-id)
|
(assoc :chat-id chat-id)
|
||||||
(update-in [:content :params]
|
(update-in [:content :params]
|
||||||
|
@ -286,7 +292,7 @@
|
||||||
(dissoc :to-message :has-handler :raw-input))}]
|
(dissoc :to-message :has-handler :raw-input))}]
|
||||||
|
|
||||||
(cond-> (merge fx
|
(cond-> (merge fx
|
||||||
(chat-model/upsert-chat (assoc fx :get-stored-chat get-stored-chat :now now)
|
(chat-model/upsert-chat (assoc fx :now now)
|
||||||
{:chat-id chat-id})
|
{:chat-id chat-id})
|
||||||
(dissoc result :db))
|
(dissoc result :db))
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
(:require [cljs.spec.alpha :as s]))
|
(:require [cljs.spec.alpha :as s]))
|
||||||
|
|
||||||
(s/def :chat/chats (s/nilable map?)) ; {id (string) chat (map)} active chats on chat's tab
|
(s/def :chat/chats (s/nilable map?)) ; {id (string) chat (map)} active chats on chat's tab
|
||||||
|
(s/def :chat/deleted-chats (s/nilable set?)) ; set of deleted chat ids
|
||||||
(s/def :chat/current-chat-id (s/nilable string?)) ; current or last opened chat-id
|
(s/def :chat/current-chat-id (s/nilable string?)) ; current or last opened chat-id
|
||||||
(s/def :chat/chat-id (s/nilable string?)) ; what is the difference ? ^
|
(s/def :chat/chat-id (s/nilable string?)) ; what is the difference ? ^
|
||||||
(s/def :chat/new-chat-name (s/nilable string?)) ; we have name in the new-chat why do we need this field
|
(s/def :chat/new-chat-name (s/nilable string?)) ; we have name in the new-chat why do we need this field
|
||||||
|
@ -15,5 +16,7 @@
|
||||||
(s/def :chat/public-group-topic (s/nilable string?))
|
(s/def :chat/public-group-topic (s/nilable string?))
|
||||||
(s/def :chat/confirmation-code-sms-listener (s/nilable any?)) ; .addListener result object
|
(s/def :chat/confirmation-code-sms-listener (s/nilable any?)) ; .addListener result object
|
||||||
(s/def :chat/messages (s/nilable map?)) ; messages indexed by message-id
|
(s/def :chat/messages (s/nilable map?)) ; messages indexed by message-id
|
||||||
|
(s/def :chat/not-loaded-message-ids (s/nilable set?)) ; set of message-ids not yet fully loaded from persisted state
|
||||||
|
(s/def :chat/last-clock-value (s/nilable number?)) ; last logical clock value of messages in chat
|
||||||
(s/def :chat/loaded-chats (s/nilable seq?))
|
(s/def :chat/loaded-chats (s/nilable seq?))
|
||||||
(s/def :chat/bot-db (s/nilable map?))
|
(s/def :chat/bot-db (s/nilable map?))
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.chat.models.input :as input-model]
|
[status-im.chat.models.input :as input-model]
|
||||||
[status-im.chat.models.commands :as commands-model]
|
[status-im.chat.models.commands :as commands-model]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.chat.views.input.utils :as input-utils]
|
[status-im.chat.views.input.utils :as input-utils]
|
||||||
[status-im.commands.utils :as commands-utils]
|
[status-im.commands.utils :as commands-utils]
|
||||||
[status-im.utils.datetime :as time]
|
[status-im.utils.datetime :as time]
|
||||||
|
@ -11,7 +10,7 @@
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[clojure.string :as string]))
|
[clojure.string :as string]))
|
||||||
|
|
||||||
(reg-sub :chats :chats)
|
(reg-sub :get-chats :chats)
|
||||||
|
|
||||||
(reg-sub :get-current-chat-id :current-chat-id)
|
(reg-sub :get-current-chat-id :current-chat-id)
|
||||||
|
|
||||||
|
@ -48,15 +47,21 @@
|
||||||
(fn [kb-height]
|
(fn [kb-height]
|
||||||
(if platform/ios? kb-height 0)))
|
(if platform/ios? kb-height 0)))
|
||||||
|
|
||||||
|
(reg-sub
|
||||||
|
:get-active-chats
|
||||||
|
:<- [:get-chats]
|
||||||
|
(fn [chats]
|
||||||
|
(into {} (filter (comp :is-active second)) chats)))
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:get-chat
|
:get-chat
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
(fn [chats [_ chat-id]]
|
(fn [chats [_ chat-id]]
|
||||||
(get chats chat-id)))
|
(get chats chat-id)))
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:get-current-chat
|
:get-current-chat
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
:<- [:get-current-chat-id]
|
:<- [:get-current-chat-id]
|
||||||
(fn [[chats current-chat-id]]
|
(fn [[chats current-chat-id]]
|
||||||
(get chats current-chat-id)))
|
(get chats current-chat-id)))
|
||||||
|
@ -69,7 +74,7 @@
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:chat
|
:chat
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
:<- [:get-current-chat-id]
|
:<- [:get-current-chat-id]
|
||||||
(fn [[chats id] [_ k chat-id]]
|
(fn [[chats id] [_ k chat-id]]
|
||||||
(get-in chats [(or chat-id id) k])))
|
(get-in chats [(or chat-id id) k])))
|
||||||
|
@ -161,7 +166,7 @@
|
||||||
(defn- available-commands-responses [[commands-responses {:keys [input-text]}]]
|
(defn- available-commands-responses [[commands-responses {:keys [input-text]}]]
|
||||||
(->> commands-responses
|
(->> commands-responses
|
||||||
map->sorted-seq
|
map->sorted-seq
|
||||||
(filter #(string/includes? (chat-utils/command-name %) (or input-text "")))))
|
(filter #(string/includes? (commands-model/command-name %) (or input-text "")))))
|
||||||
|
|
||||||
(reg-sub
|
(reg-sub
|
||||||
:get-available-commands
|
:get-available-commands
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
(ns status-im.chat.utils
|
|
||||||
(:require [status-im.chat.constants :as chat.constants]
|
|
||||||
[taoensso.timbre :as log]))
|
|
||||||
|
|
||||||
(defn add-message-to-db
|
|
||||||
([db add-to-chat-id chat-id message] (add-message-to-db db add-to-chat-id chat-id message true))
|
|
||||||
([db add-to-chat-id chat-id {:keys [message-id] :as message} new?]
|
|
||||||
(let [prepared-message (assoc message
|
|
||||||
:chat-id chat-id
|
|
||||||
:new? (if (nil? new?) true new?))]
|
|
||||||
(update-in db [:chats add-to-chat-id :messages] assoc message-id prepared-message))))
|
|
||||||
|
|
||||||
(defn message-seen-by? [message user-pk]
|
|
||||||
(= :seen (get-in message [:user-statuses user-pk])))
|
|
||||||
|
|
||||||
(defn command-name [{:keys [name]}]
|
|
||||||
(str chat.constants/command-char name))
|
|
|
@ -6,8 +6,8 @@
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.chat.constants :as const]
|
[status-im.chat.constants :as const]
|
||||||
[status-im.chat.models.input :as input-model]
|
[status-im.chat.models.input :as input-model]
|
||||||
|
[status-im.chat.models.commands :as commands-model]
|
||||||
[status-im.chat.styles.input.input :as style]
|
[status-im.chat.styles.input.input :as style]
|
||||||
[status-im.chat.utils :as chat-utils]
|
|
||||||
[status-im.chat.views.input.emoji :as emoji]
|
[status-im.chat.views.input.emoji :as emoji]
|
||||||
[status-im.chat.views.input.parameter-box :as parameter-box]
|
[status-im.chat.views.input.parameter-box :as parameter-box]
|
||||||
[status-im.chat.views.input.input-actions :as input-actions]
|
[status-im.chat.views.input.input-actions :as input-actions]
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
[react/view
|
[react/view
|
||||||
[react/text {:style (style/command first?)
|
[react/text {:style (style/command first?)
|
||||||
:font :roboto-mono}
|
:font :roboto-mono}
|
||||||
(chat-utils/command-name command)]]])
|
(commands-model/command-name command)]]])
|
||||||
|
|
||||||
(defview commands-view []
|
(defview commands-view []
|
||||||
[all-commands-responses [:get-available-commands-responses]
|
[all-commands-responses [:get-available-commands-responses]
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.chat.styles.input.suggestions :as style]
|
[status-im.chat.styles.input.suggestions :as style]
|
||||||
[status-im.chat.views.input.animations.expandable :as expandable]
|
[status-im.chat.views.input.animations.expandable :as expandable]
|
||||||
[status-im.chat.utils :as chat.utils]
|
[status-im.chat.models.commands :as commands-model]
|
||||||
[status-im.i18n :as i18n]))
|
[status-im.i18n :as i18n]))
|
||||||
|
|
||||||
(defn suggestion-item [{:keys [on-press name description last?]}]
|
(defn suggestion-item [{:keys [on-press name description last?]}]
|
||||||
|
@ -23,14 +23,14 @@
|
||||||
[suggestion-item
|
[suggestion-item
|
||||||
{:on-press #(let [metadata (assoc params :to-message-id message-id)]
|
{:on-press #(let [metadata (assoc params :to-message-id message-id)]
|
||||||
(re-frame/dispatch [:select-chat-input-command command metadata]))
|
(re-frame/dispatch [:select-chat-input-command command metadata]))
|
||||||
:name (chat.utils/command-name command)
|
:name (commands-model/command-name command)
|
||||||
:description description
|
:description description
|
||||||
:last? last?}])
|
:last? last?}])
|
||||||
|
|
||||||
(defn command-item [{:keys [name description bot] :as command} last?]
|
(defn command-item [{:keys [name description bot] :as command} last?]
|
||||||
[suggestion-item
|
[suggestion-item
|
||||||
{:on-press #(re-frame/dispatch [:select-chat-input-command command nil])
|
{:on-press #(re-frame/dispatch [:select-chat-input-command command nil])
|
||||||
:name (chat.utils/command-name command)
|
:name (commands-model/command-name command)
|
||||||
:description description
|
:description description
|
||||||
:last? last?}])
|
:last? last?}])
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,14 @@
|
||||||
[status-im.ui.components.react :as react]
|
[status-im.ui.components.react :as react]
|
||||||
[status-im.ui.components.animation :as animation]
|
[status-im.ui.components.animation :as animation]
|
||||||
[status-im.ui.components.list-selection :as list-selection]
|
[status-im.ui.components.list-selection :as list-selection]
|
||||||
[status-im.chat.models.commands :as commands]
|
|
||||||
[status-im.commands.utils :as commands.utils]
|
[status-im.commands.utils :as commands.utils]
|
||||||
[status-im.chat.utils :as chat.utils]
|
[status-im.chat.models.commands :as models.commands]
|
||||||
|
[status-im.chat.models.message :as models.message]
|
||||||
[status-im.chat.styles.message.message :as style]
|
[status-im.chat.styles.message.message :as style]
|
||||||
[status-im.chat.styles.message.command-pill :as pill-style]
|
[status-im.chat.styles.message.command-pill :as pill-style]
|
||||||
[status-im.chat.views.message.request-message :as request-message]
|
[status-im.chat.views.message.request-message :as request-message]
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
[status-im.ui.components.chat-icon.screen :as chat-icon.screen]
|
||||||
[status-im.utils.events-buffer :as events-buffer]
|
|
||||||
[status-im.utils.identicon :as identicon]
|
[status-im.utils.identicon :as identicon]
|
||||||
[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]
|
||||||
|
@ -79,7 +78,7 @@
|
||||||
[react/view (pill-style/pill command)
|
[react/view (pill-style/pill command)
|
||||||
[react/text {:style pill-style/pill-text
|
[react/text {:style pill-style/pill-text
|
||||||
:font :default}
|
:font :default}
|
||||||
(chat.utils/command-name command)]]])
|
(models.commands/command-name command)]]])
|
||||||
(when icon-path
|
(when icon-path
|
||||||
[react/view style/command-image-view
|
[react/view style/command-image-view
|
||||||
[react/icon icon-path style/command-image]])
|
[react/icon icon-path style/command-image]])
|
||||||
|
@ -266,10 +265,10 @@
|
||||||
(callback))))))))
|
(callback))))))))
|
||||||
|
|
||||||
(defn message-container [message & children]
|
(defn message-container [message & children]
|
||||||
(if (:new? message)
|
(if (:appearing? message)
|
||||||
(let [layout-height (reagent/atom 0)
|
(let [layout-height (reagent/atom 0)
|
||||||
anim-value (animation/create-value 1)
|
anim-value (animation/create-value 1)
|
||||||
anim-callback #(events-buffer/dispatch [:set-message-shown message])
|
anim-callback #(re-frame/dispatch [:message-appeared message])
|
||||||
context {:to-value layout-height
|
context {:to-value layout-height
|
||||||
:val anim-value
|
:val anim-value
|
||||||
:callback anim-callback}
|
:callback anim-callback}
|
||||||
|
@ -296,13 +295,12 @@
|
||||||
"chat-message"
|
"chat-message"
|
||||||
:component-did-mount
|
:component-did-mount
|
||||||
;; send `:seen` signal when we have signed-in user, message not from us and we didn't sent it already
|
;; send `:seen` signal when we have signed-in user, message not from us and we didn't sent it already
|
||||||
(fn []
|
#(when (and current-public-key message-id chat-id (not outgoing)
|
||||||
(when (and current-public-key message-id chat-id (not outgoing)
|
(not (models.message/message-seen-by? message current-public-key)))
|
||||||
(not (chat.utils/message-seen-by? message current-public-key)))
|
(re-frame/dispatch [:send-seen! {:chat-id chat-id
|
||||||
(events-buffer/dispatch [:send-seen! {:chat-id chat-id
|
|
||||||
:from from
|
:from from
|
||||||
:me current-public-key
|
:me current-public-key
|
||||||
:message-id message-id}])))
|
:message-id message-id}]))
|
||||||
:reagent-render
|
:reagent-render
|
||||||
(fn [{:keys [outgoing group-chat content-type content] :as message}]
|
(fn [{:keys [outgoing group-chat content-type content] :as message}]
|
||||||
[message-container message
|
[message-container message
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
(get-in contacts [whisper-identity :debug?]))
|
(get-in contacts [whisper-identity :debug?]))
|
||||||
(let [dapp (merge dapp-data {:dapp? true
|
(let [dapp (merge dapp-data {:dapp? true
|
||||||
:debug? true})]
|
:debug? true})]
|
||||||
(re-frame/dispatch [:upsert-chat! {:chat-id whisper-identity
|
(re-frame/dispatch [:update-chat! {:chat-id whisper-identity
|
||||||
:name name
|
:name name
|
||||||
:debug? true}])
|
:debug? true}])
|
||||||
(if (get contacts whisper-identity)
|
(if (get contacts whisper-identity)
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
(:require [status-im.data-store.realm.chats :as data-store])
|
(:require [status-im.data-store.realm.chats :as data-store])
|
||||||
(:refer-clojure :exclude [exists?]))
|
(:refer-clojure :exclude [exists?]))
|
||||||
|
|
||||||
(defn- normalize-contacts
|
|
||||||
[item]
|
|
||||||
(update item :contacts vals))
|
|
||||||
|
|
||||||
(defn get-all
|
(defn get-all
|
||||||
[]
|
[]
|
||||||
(map normalize-contacts (data-store/get-all-active)))
|
(data-store/get-all-active))
|
||||||
|
|
||||||
|
(defn get-inactive-ids
|
||||||
|
[]
|
||||||
|
(data-store/get-inactive-ids))
|
||||||
|
|
||||||
(defn get-by-id
|
(defn get-by-id
|
||||||
[id]
|
[id]
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
(data-store/exists? chat-id))
|
(data-store/exists? chat-id))
|
||||||
|
|
||||||
(defn save
|
(defn save
|
||||||
[{:keys [last-message-id chat-id] :as chat}]
|
[{:keys [chat-id] :as chat}]
|
||||||
(data-store/save chat (data-store/exists? chat-id)))
|
(data-store/save chat (data-store/exists? chat-id)))
|
||||||
|
|
||||||
(defn delete
|
(defn delete
|
||||||
|
|
|
@ -16,9 +16,6 @@
|
||||||
{:outgoing false
|
{:outgoing false
|
||||||
:to nil})
|
:to nil})
|
||||||
|
|
||||||
(defn exists? [message-id]
|
|
||||||
(data-store/exists? message-id))
|
|
||||||
|
|
||||||
(defn get-by-id
|
(defn get-by-id
|
||||||
[message-id]
|
[message-id]
|
||||||
(data-store/get-by-id message-id))
|
(data-store/get-by-id message-id))
|
||||||
|
@ -33,18 +30,16 @@
|
||||||
(update message :content reader/read-string)
|
(update message :content reader/read-string)
|
||||||
message))))))
|
message))))))
|
||||||
|
|
||||||
|
(defn get-stored-message-ids
|
||||||
|
[]
|
||||||
|
(data-store/get-stored-message-ids))
|
||||||
|
|
||||||
(defn get-log-messages
|
(defn get-log-messages
|
||||||
[chat-id]
|
[chat-id]
|
||||||
(->> (data-store/get-by-chat-id chat-id 0 100)
|
(->> (data-store/get-by-chat-id chat-id 0 100)
|
||||||
(filter #(= (:content-type %) constants/content-type-log-message))
|
(filter #(= (:content-type %) constants/content-type-log-message))
|
||||||
(map #(select-keys % [:content :timestamp]))))
|
(map #(select-keys % [:content :timestamp]))))
|
||||||
|
|
||||||
(defn get-last-clock-value
|
|
||||||
[chat-id]
|
|
||||||
(if-let [message (data-store/get-last-message chat-id)]
|
|
||||||
(:clock-value message)
|
|
||||||
0))
|
|
||||||
|
|
||||||
(defn get-unviewed
|
(defn get-unviewed
|
||||||
[current-public-key]
|
[current-public-key]
|
||||||
(into {}
|
(into {}
|
||||||
|
|
|
@ -1,31 +1,39 @@
|
||||||
(ns status-im.data-store.realm.chats
|
(ns status-im.data-store.realm.chats
|
||||||
(:require [goog.object :as object]
|
(:require [goog.object :as object]
|
||||||
[status-im.data-store.realm.core :as realm]
|
[status-im.data-store.realm.core :as realm]
|
||||||
|
[status-im.data-store.realm.messages :as messages]
|
||||||
[status-im.utils.random :refer [timestamp]]
|
[status-im.utils.random :refer [timestamp]]
|
||||||
[taoensso.timbre :as log])
|
[taoensso.timbre :as log])
|
||||||
(:refer-clojure :exclude [exists?]))
|
(:refer-clojure :exclude [exists?]))
|
||||||
|
|
||||||
(defn get-all
|
(defn- normalize-chat [{:keys [chat-id] :as chat}]
|
||||||
[]
|
(let [last-message (messages/get-last-message chat-id)]
|
||||||
(-> @realm/account-realm
|
(-> chat
|
||||||
(realm/get-all :chat)
|
(realm/fix-map->vec :contacts)
|
||||||
(realm/sorted :timestamp :desc)))
|
(assoc :last-clock-value (or (:clock-value last-message) 0)))))
|
||||||
|
|
||||||
(defn get-all-as-list
|
|
||||||
[]
|
|
||||||
(realm/js-object->clj (get-all)))
|
|
||||||
|
|
||||||
(defn get-all-active
|
(defn get-all-active
|
||||||
[]
|
[]
|
||||||
|
(map normalize-chat
|
||||||
(-> (realm/get-by-field @realm/account-realm :chat :is-active true)
|
(-> (realm/get-by-field @realm/account-realm :chat :is-active true)
|
||||||
(realm/sorted :timestamp :desc)
|
(realm/sorted :timestamp :desc)
|
||||||
realm/js-object->clj))
|
realm/js-object->clj)))
|
||||||
|
|
||||||
|
(defn get-inactive-ids
|
||||||
|
[]
|
||||||
|
(-> (realm/get-by-field @realm/account-realm :chat :is-active false)
|
||||||
|
(.map (fn [chat _ _]
|
||||||
|
(aget chat "chat-id")))
|
||||||
|
realm/js-object->clj
|
||||||
|
set))
|
||||||
|
|
||||||
(defn- groups
|
(defn- groups
|
||||||
[active?]
|
[active?]
|
||||||
(realm/filtered (get-all)
|
(-> @realm/account-realm
|
||||||
(str "group-chat = true && is-active = "
|
(realm/get-all :chat)
|
||||||
(if active? "true" "false"))))
|
(realm/sorted :timestamp :desc)
|
||||||
|
(realm/filtered (str "group-chat = true && is-active = "
|
||||||
|
(if active? "true" "false")))))
|
||||||
|
|
||||||
(defn get-active-group-chats
|
(defn get-active-group-chats
|
||||||
[]
|
[]
|
||||||
|
@ -46,7 +54,7 @@
|
||||||
[chat-id]
|
[chat-id]
|
||||||
(-> @realm/account-realm
|
(-> @realm/account-realm
|
||||||
(realm/get-one-by-field-clj :chat :chat-id chat-id)
|
(realm/get-one-by-field-clj :chat :chat-id chat-id)
|
||||||
(realm/fix-map->vec :contacts)))
|
normalize-chat))
|
||||||
|
|
||||||
(defn save
|
(defn save
|
||||||
[chat update?]
|
[chat update?]
|
||||||
|
|
|
@ -32,6 +32,19 @@
|
||||||
realm/js-object->clj)]
|
realm/js-object->clj)]
|
||||||
(mapv transform-message messages))))
|
(mapv transform-message messages))))
|
||||||
|
|
||||||
|
(defn get-stored-message-ids
|
||||||
|
[]
|
||||||
|
(let [chat-id->message-id (volatile! {})]
|
||||||
|
(-> @realm/account-realm
|
||||||
|
(.objects "message")
|
||||||
|
(.map (fn [msg _ _]
|
||||||
|
(vswap! chat-id->message-id
|
||||||
|
#(update %
|
||||||
|
(aget msg "chat-id")
|
||||||
|
(fnil conj #{})
|
||||||
|
(aget msg "message-id"))))))
|
||||||
|
@chat-id->message-id))
|
||||||
|
|
||||||
(defn get-by-fields
|
(defn get-by-fields
|
||||||
[fields from number-of-messages]
|
[fields from number-of-messages]
|
||||||
(-> (realm/get-by-fields @realm/account-realm :message :and fields)
|
(-> (realm/get-by-fields @realm/account-realm :message :and fields)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
(ns status-im.protocol.handlers
|
(ns status-im.protocol.handlers
|
||||||
(:require [re-frame.core :as re-frame]
|
(:require [re-frame.core :as re-frame]
|
||||||
|
[cljs.core.async :as async]
|
||||||
[status-im.utils.handlers :as handlers]
|
[status-im.utils.handlers :as handlers]
|
||||||
[status-im.data-store.contacts :as contacts]
|
[status-im.data-store.contacts :as contacts]
|
||||||
[status-im.data-store.messages :as messages]
|
[status-im.data-store.messages :as messages]
|
||||||
|
@ -10,13 +11,13 @@
|
||||||
[status-im.constants :as constants]
|
[status-im.constants :as constants]
|
||||||
[status-im.i18n :as i18n]
|
[status-im.i18n :as i18n]
|
||||||
[status-im.utils.random :as random]
|
[status-im.utils.random :as random]
|
||||||
|
[status-im.utils.async :as async-utils]
|
||||||
[status-im.protocol.message-cache :as cache]
|
[status-im.protocol.message-cache :as cache]
|
||||||
[status-im.protocol.listeners :as listeners]
|
[status-im.protocol.listeners :as listeners]
|
||||||
[status-im.chat.utils :as chat.utils]
|
[status-im.chat.models.message :as models.message]
|
||||||
[status-im.protocol.web3.inbox :as inbox]
|
[status-im.protocol.web3.inbox :as inbox]
|
||||||
[status-im.protocol.web3.keys :as web3.keys]
|
[status-im.protocol.web3.keys :as web3.keys]
|
||||||
[status-im.utils.datetime :as datetime]
|
[status-im.utils.datetime :as datetime]
|
||||||
[status-im.utils.events-buffer :as events-buffer]
|
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.native-module.core :as status]
|
[status-im.native-module.core :as status]
|
||||||
[clojure.string :as string]
|
[clojure.string :as string]
|
||||||
|
@ -40,11 +41,6 @@
|
||||||
(fn [coeffects _]
|
(fn [coeffects _]
|
||||||
(assoc coeffects :pending-messages (pending-messages/get-all))))
|
(assoc coeffects :pending-messages (pending-messages/get-all))))
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
|
||||||
::get-all-contacts
|
|
||||||
(fn [coeffects _]
|
|
||||||
(assoc coeffects :contacts (contacts/get-all))))
|
|
||||||
|
|
||||||
(re-frame/reg-cofx
|
(re-frame/reg-cofx
|
||||||
::message-get-by-id
|
::message-get-by-id
|
||||||
(fn [coeffects _]
|
(fn [coeffects _]
|
||||||
|
@ -74,6 +70,8 @@
|
||||||
|
|
||||||
;;;; FX
|
;;;; FX
|
||||||
|
|
||||||
|
(def ^:private protocol-realm-queue (async-utils/task-queue 200))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
:stop-whisper
|
:stop-whisper
|
||||||
(fn [] (protocol/stop-whisper!)))
|
(fn [] (protocol/stop-whisper!)))
|
||||||
|
@ -85,7 +83,7 @@
|
||||||
{:web3 web3
|
{:web3 web3
|
||||||
:identity public-key
|
:identity public-key
|
||||||
:groups groups
|
:groups groups
|
||||||
:callback #(events-buffer/dispatch [:incoming-message %1 %2])
|
:callback #(re-frame/dispatch [:incoming-message %1 %2])
|
||||||
:ack-not-received-s-interval 125
|
:ack-not-received-s-interval 125
|
||||||
:default-ttl 120
|
:default-ttl 120
|
||||||
:send-online-s-interval 180
|
:send-online-s-interval 180
|
||||||
|
@ -118,7 +116,7 @@
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::save-processed-messages
|
::save-processed-messages
|
||||||
(fn [processed-message]
|
(fn [processed-message]
|
||||||
(processed-messages/save processed-message)))
|
(async/put! protocol-realm-queue #(processed-messages/save processed-message))))
|
||||||
|
|
||||||
(defn system-message [message-id timestamp content]
|
(defn system-message [message-id timestamp content]
|
||||||
{:from "system"
|
{:from "system"
|
||||||
|
@ -198,12 +196,12 @@
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::pending-messages-delete
|
::pending-messages-delete
|
||||||
(fn [message-id]
|
(fn [message-id]
|
||||||
(pending-messages/delete message-id)))
|
(async/put! protocol-realm-queue #(pending-messages/delete message-id))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::pending-messages-save
|
::pending-messages-save
|
||||||
(fn [pending-message]
|
(fn [pending-message]
|
||||||
(pending-messages/save pending-message)))
|
(async/put! protocol-realm-queue #(pending-messages/save pending-message))))
|
||||||
|
|
||||||
(re-frame/reg-fx
|
(re-frame/reg-fx
|
||||||
::status-init-jail
|
::status-init-jail
|
||||||
|
@ -370,15 +368,15 @@
|
||||||
(re-frame/inject-cofx ::get-web3)
|
(re-frame/inject-cofx ::get-web3)
|
||||||
(re-frame/inject-cofx ::get-chat-groups)
|
(re-frame/inject-cofx ::get-chat-groups)
|
||||||
(re-frame/inject-cofx ::get-pending-messages)
|
(re-frame/inject-cofx ::get-pending-messages)
|
||||||
(re-frame/inject-cofx ::get-all-contacts)]
|
(re-frame/inject-cofx :get-all-contacts)]
|
||||||
(fn [{:keys [db web3 groups contacts pending-messages]} [current-account-id ethereum-rpc-url]]
|
(fn [{:keys [db web3 groups all-contacts pending-messages]} [current-account-id ethereum-rpc-url]]
|
||||||
(let [{:keys [public-key status updates-public-key
|
(let [{:keys [public-key status updates-public-key
|
||||||
updates-private-key]}
|
updates-private-key]}
|
||||||
(get-in db [:accounts/accounts current-account-id])]
|
(get-in db [:accounts/accounts current-account-id])]
|
||||||
(when public-key
|
(when public-key
|
||||||
{::init-whisper {:web3 web3 :public-key public-key :groups groups :pending-messages pending-messages
|
{::init-whisper {:web3 web3 :public-key public-key :groups groups :pending-messages pending-messages
|
||||||
:updates-public-key updates-public-key :updates-private-key updates-private-key
|
:updates-public-key updates-public-key :updates-private-key updates-private-key
|
||||||
:status status :contacts contacts}
|
:status status :contacts all-contacts}
|
||||||
:db (assoc db :web3 web3
|
:db (assoc db :web3 web3
|
||||||
:rpc-url (or ethereum-rpc-url constants/ethereum-rpc-url))}))))
|
:rpc-url (or ethereum-rpc-url constants/ethereum-rpc-url))}))))
|
||||||
|
|
||||||
|
@ -429,7 +427,7 @@
|
||||||
(defn- transform-protocol-message [{:keys [from to payload]}]
|
(defn- transform-protocol-message [{:keys [from to payload]}]
|
||||||
(merge payload {:from from
|
(merge payload {:from from
|
||||||
:to to
|
:to to
|
||||||
:chat-id from}))
|
:chat-id (or (:group-id payload) from)}))
|
||||||
|
|
||||||
(defn- message-from-self [{:keys [current-public-key]} {:keys [id to group-id]}]
|
(defn- message-from-self [{:keys [current-public-key]} {:keys [id to group-id]}]
|
||||||
{:from to
|
{:from to
|
||||||
|
@ -491,11 +489,14 @@
|
||||||
chat-identifier (or (:group-id payload) from)
|
chat-identifier (or (:group-id payload) from)
|
||||||
message-db-path [:chats chat-identifier :messages message-identifier]
|
message-db-path [:chats chat-identifier :messages message-identifier]
|
||||||
from-id (or sent-from from)
|
from-id (or sent-from from)
|
||||||
message (get-stored-message message-identifier)]
|
message (or (get-in db message-db-path)
|
||||||
|
(and (get (:not-loaded-message-ids db) message-identifier)
|
||||||
|
(get-stored-message message-identifier)))]
|
||||||
;; proceed with updating status if chat is in db, status is not the same and message was not already seen
|
;; proceed with updating status if chat is in db, status is not the same and message was not already seen
|
||||||
(when (and (get-in db [:chats chat-identifier])
|
(when (and message
|
||||||
|
(get-in db [:chats chat-identifier])
|
||||||
(not= status (get-in message [:user-statuses from-id]))
|
(not= status (get-in message [:user-statuses from-id]))
|
||||||
(not (chat.utils/message-seen-by? message from-id)))
|
(not (models.message/message-seen-by? message from-id)))
|
||||||
(let [statuses (assoc (:user-statuses message) from-id status)]
|
(let [statuses (assoc (:user-statuses message) from-id status)]
|
||||||
(cond-> {:update-message {:message-id message-identifier
|
(cond-> {:update-message {:message-id message-identifier
|
||||||
:user-statuses statuses}}
|
:user-statuses statuses}}
|
||||||
|
@ -527,7 +528,6 @@
|
||||||
;; Root level "timestamp" is a unix ts in seconds.
|
;; Root level "timestamp" is a unix ts in seconds.
|
||||||
timestamp' (or (:payload timestamp)
|
timestamp' (or (:payload timestamp)
|
||||||
(* 1000 timestamp))]
|
(* 1000 timestamp))]
|
||||||
|
|
||||||
(if-not existing-contact
|
(if-not existing-contact
|
||||||
(let [contact (assoc contact :pending? true)]
|
(let [contact (assoc contact :pending? true)]
|
||||||
{:dispatch-n [[:add-contacts [contact]]
|
{:dispatch-n [[:add-contacts [contact]]
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
(ns status-im.protocol.listeners
|
(ns status-im.protocol.listeners
|
||||||
(:require [cljs.reader :as r]
|
(:require [cljs.reader :as r]
|
||||||
|
[re-frame.core :as re-frame]
|
||||||
[status-im.protocol.ack :as ack]
|
[status-im.protocol.ack :as ack]
|
||||||
[status-im.protocol.web3.utils :as u]
|
[status-im.protocol.web3.utils :as u]
|
||||||
[status-im.protocol.encryption :as e]
|
[status-im.protocol.encryption :as e]
|
||||||
[taoensso.timbre :as log]
|
[taoensso.timbre :as log]
|
||||||
[status-im.utils.hex :as i]
|
[status-im.utils.hex :as i]))
|
||||||
[status-im.utils.events-buffer :as events-buffer]))
|
|
||||||
|
|
||||||
(defn empty-public-key? [public-key]
|
(defn empty-public-key? [public-key]
|
||||||
(or (= "0x0" public-key)
|
(or (= "0x0" public-key)
|
||||||
|
@ -96,5 +96,5 @@
|
||||||
"Valid options are: web3, identity, callback, keypair"
|
"Valid options are: web3, identity, callback, keypair"
|
||||||
[options]
|
[options]
|
||||||
(fn [js-error js-message]
|
(fn [js-error js-message]
|
||||||
(events-buffer/dispatch [:handle-whisper-message js-error js-message options])))
|
(re-frame/dispatch [:handle-whisper-message js-error js-message options])))
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
;;;; COFX
|
;;;; COFX
|
||||||
|
|
||||||
(reg-cofx
|
(reg-cofx
|
||||||
::get-all-contacts
|
:get-all-contacts
|
||||||
(fn [coeffects _]
|
(fn [coeffects _]
|
||||||
(assoc coeffects :all-contacts (contacts/get-all))))
|
(assoc coeffects :all-contacts (contacts/get-all))))
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@
|
||||||
|
|
||||||
(register-handler-fx
|
(register-handler-fx
|
||||||
:load-contacts
|
:load-contacts
|
||||||
[(inject-cofx ::get-all-contacts)]
|
[(inject-cofx :get-all-contacts)]
|
||||||
(fn [{:keys [db all-contacts]} _]
|
(fn [{:keys [db all-contacts]} _]
|
||||||
(let [contacts-list (map #(vector (:whisper-identity %) %) all-contacts)
|
(let [contacts-list (map #(vector (:whisper-identity %) %) all-contacts)
|
||||||
contacts (into {} contacts-list)]
|
contacts (into {} contacts-list)]
|
||||||
|
|
|
@ -161,6 +161,7 @@
|
||||||
:qr/qr-modal
|
:qr/qr-modal
|
||||||
:qr/current-qr-context
|
:qr/current-qr-context
|
||||||
:chat/chats
|
:chat/chats
|
||||||
|
:chat/deleted-chats
|
||||||
:chat/current-chat-id
|
:chat/current-chat-id
|
||||||
:chat/chat-id
|
:chat/chat-id
|
||||||
:chat/new-chat
|
:chat/new-chat
|
||||||
|
@ -177,6 +178,8 @@
|
||||||
:chat/public-group-topic
|
:chat/public-group-topic
|
||||||
:chat/confirmation-code-sms-listener
|
:chat/confirmation-code-sms-listener
|
||||||
:chat/messages
|
:chat/messages
|
||||||
|
:chat/not-loaded-message-ids
|
||||||
|
:chat/last-clock-value
|
||||||
:chat/loaded-chats
|
:chat/loaded-chats
|
||||||
:chat/bot-db
|
:chat/bot-db
|
||||||
:commands/access-scope->commands-responses
|
:commands/access-scope->commands-responses
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
(reg-sub :discover/discoveries-with-priority
|
(reg-sub :discover/discoveries-with-priority
|
||||||
:<- [:discover/discoveries]
|
:<- [:discover/discoveries]
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
:<- [:get-contacts]
|
:<- [:get-contacts]
|
||||||
:<- [:get :current-public-key]
|
:<- [:get :current-public-key]
|
||||||
(fn [[discoveries chats contacts current-public-key]]
|
(fn [[discoveries chats contacts current-public-key]]
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
(reg-sub :discover/search-results
|
(reg-sub :discover/search-results
|
||||||
:<- [:discover/discoveries-by-tags]
|
:<- [:discover/discoveries-by-tags]
|
||||||
:<- [:discover/search-tags]
|
:<- [:discover/search-tags]
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
:<- [:get-contacts]
|
:<- [:get-contacts]
|
||||||
:<- [:get :current-public-key]
|
:<- [:get :current-public-key]
|
||||||
(fn [[discoveries search-tags chats contacts current-public-key] [_ limit]]
|
(fn [[discoveries search-tags chats contacts current-public-key] [_ limit]]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
(:require [re-frame.core :as re-frame]))
|
(:require [re-frame.core :as re-frame]))
|
||||||
|
|
||||||
(re-frame/reg-sub :home-items
|
(re-frame/reg-sub :home-items
|
||||||
:<- [:chats]
|
:<- [:get-active-chats]
|
||||||
:<- [:browsers]
|
:<- [:browsers]
|
||||||
(fn [[chats browsers]]
|
(fn [[chats browsers]]
|
||||||
(sort-by #(-> % second :timestamp) > (merge chats browsers))))
|
(sort-by #(-> % second :timestamp) > (merge chats browsers))))
|
||||||
|
|
|
@ -22,3 +22,15 @@
|
||||||
(recur (conj acc v) (and (seq acc) flush?))
|
(recur (conj acc v) (and (seq acc) flush?))
|
||||||
(async/close! output-ch))
|
(async/close! output-ch))
|
||||||
(recur acc (seq acc)))))))
|
(recur acc (seq acc)))))))
|
||||||
|
|
||||||
|
(defn task-queue
|
||||||
|
"Creates `core.async` channel which will process 0 arg functions put there in serial fashon.
|
||||||
|
Takes the same argument/s as `core.async/chan`, those arguments will be delegated to the
|
||||||
|
channel constructor.
|
||||||
|
Returns task-queue where tasks represented by 0 arg task functions can be put for processing."
|
||||||
|
[& args]
|
||||||
|
(let [task-queue (apply async/chan args)]
|
||||||
|
(async/go-loop [task-fn (async/<! task-queue)]
|
||||||
|
(task-fn)
|
||||||
|
(recur (async/<! task-queue)))
|
||||||
|
task-queue))
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
;; http://amturing.acm.org/p558-lamport.pdf
|
;; http://amturing.acm.org/p558-lamport.pdf
|
||||||
|
|
||||||
(defn send [local-clock]
|
(defn send [local-clock]
|
||||||
(inc local-clock))
|
(inc (or local-clock 0)))
|
||||||
|
|
||||||
(defn receive [message-clock local-clock]
|
(defn receive [message-clock local-clock]
|
||||||
(inc (max message-clock local-clock)))
|
(inc (max (or message-clock 0) (or local-clock 0))))
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
(ns status-im.utils.events-buffer
|
|
||||||
(:require [cljs.core.async :as async]
|
|
||||||
[re-frame.core :as re-frame])
|
|
||||||
(:require-macros [cljs.core.async.macros :refer [go-loop]]))
|
|
||||||
|
|
||||||
;; NOTE:(dmitryn) Ideally we should not exceed current buffer size.
|
|
||||||
;; Buffer length is an experimental number, consider to change it.
|
|
||||||
(defonce ^:private buffer (async/chan 10000))
|
|
||||||
|
|
||||||
;; NOTE:(dmitryn) Reference to re-frame event loop mechanism
|
|
||||||
;; https://github.com/Day8/re-frame/blob/master/src/re_frame/router.cljc#L8
|
|
||||||
;; Might need future improvements.
|
|
||||||
;; "Fast" events could be processed in batches to speed up things,
|
|
||||||
;; so multiple buffers/channels could be introduced.
|
|
||||||
(defn- start-loop! [c t]
|
|
||||||
"Dispatches events to re-frame processing queue,
|
|
||||||
but in a way that doesn't block events processing."
|
|
||||||
(go-loop [e (async/<! c)]
|
|
||||||
(re-frame/dispatch e)
|
|
||||||
(async/<! (async/timeout t))
|
|
||||||
(recur (async/<! c))))
|
|
||||||
|
|
||||||
(defonce ^:private dispatch-loop (start-loop! buffer 0))
|
|
||||||
|
|
||||||
;; Accepts re-frame event vector [:event-id args]
|
|
||||||
;; NOTE(dmitryn) Puts all events into a single buffer (naive approach).
|
|
||||||
(defn dispatch [event]
|
|
||||||
(async/put! buffer event))
|
|
|
@ -79,7 +79,7 @@
|
||||||
(rf/reg-fx :save-chat #())
|
(rf/reg-fx :save-chat #())
|
||||||
|
|
||||||
(rf/reg-cofx
|
(rf/reg-cofx
|
||||||
::contacts-events/get-all-contacts
|
:get-all-contacts
|
||||||
(fn [coeffects _]
|
(fn [coeffects _]
|
||||||
(assoc coeffects :all-contacts [])))
|
(assoc coeffects :all-contacts [])))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue