|
6 | 6 | [status-im.chat.events.requests :as requests-events] |
7 | 7 | [status-im.chat.models :as chat-model] |
8 | 8 | [status-im.chat.models.commands :as commands-model] |
9 | | - [status-im.utils.clocks :as clocks-utils] |
| 9 | + [status-im.utils.clocks :as utils.clocks] |
10 | 10 | [status-im.utils.handlers :as handlers] |
11 | 11 | [status-im.transport.utils :as transport.utils] |
12 | 12 | [status-im.transport.message.core :as transport] |
|
26 | 26 | (:ref (get available-commands-responses response-name)))) |
27 | 27 |
|
28 | 28 | (defn- add-message |
29 | | - [chat-id {:keys [message-id from-clock-value to-clock-value] :as message} current-chat? {:keys [db]}] |
| 29 | + [chat-id {:keys [message-id clock-value] :as message} current-chat? {:keys [db]}] |
30 | 30 | (let [prepared-message (cond-> (assoc message :appearing? true) |
31 | 31 | (not current-chat?) |
32 | 32 | (assoc :appearing? false))] |
33 | | - {:db (cond-> (-> db |
34 | | - (update-in [:chats chat-id :messages] dissoc from-clock-value) |
35 | | - (update-in [:chats chat-id :messages] assoc message-id prepared-message) |
36 | | - (update-in [:chats chat-id :last-from-clock-value] max from-clock-value) |
37 | | - (update-in [:chats chat-id :last-to-clock-value] max to-clock-value)) |
| 33 | + {:db (cond-> |
| 34 | + (-> db |
| 35 | + (update-in [:chats chat-id :messages] assoc message-id prepared-message) |
| 36 | + (update-in [:chats chat-id :last-clock-value] (partial utils.clocks/receive clock-value))) ; this will increase last-clock-value twice when sending our own messages |
38 | 37 | (not current-chat?) |
39 | 38 | (update-in [:chats chat-id :unviewed-messages] (fnil conj #{}) message-id)) |
40 | 39 | :data-store/save-message prepared-message})) |
41 | 40 |
|
42 | | -;; We start with [0 0] ([from-clock-value to-clock-value]) for each participant of 1-1 chat (local perspective on each device). |
43 | | -;; Now for sending, we always increment the to-clock-value and include it in message payload being sent (so only to-clock-value is present in network message). |
44 | | -;; Locally, the sent message always replicates the latest-from-clock-value of the chat. |
45 | | -;; Upon receiving message, receiver reads the to-clock-value of the received message and sets that to be the from-clock-value locally |
46 | | -;; (this will be also the new latest-from-clock-value of the chat), to-clock-value for the message is the latest-to-clock-value of the 1-1 chat`. |
47 | | - |
48 | | -;; All this ensures, that there will be no [from-clock-value to-clock-value] duplicate in chat message on each device + the local order will appear consistent, |
49 | | -;; even if it’s possible it won’t be the same on both devices (for example user A sends 5 messages, during the sending, |
50 | | -;; he receives the message from user B, so his local order will be A1, A2, B, A3, A4, A5, but his messages will take a long time to reach user B, |
51 | | -;; for some reason, so user B will see it as B, A1, A2, A3, A4, A5). |
52 | | -;; I don’t think that’s very problematic and I don’t think we can do much about it without single source of truth where order received messages are serialised |
53 | | -;; and definite order is established (server), it is the case even in the current implementation. |
54 | 41 | (defn- prepare-chat [chat-id {:keys [db] :as cofx}] |
55 | 42 | (if (get-in db [:chats chat-id]) |
56 | 43 | (chat-model/upsert-chat {:chat-id chat-id} cofx) |
|
63 | 50 | (when send-seen? |
64 | 51 | (transport/send (protocol/map->MessagesSeen {:message-ids #{message-id}}) chat-id cofx))) |
65 | 52 |
|
66 | | -(defn- placeholder-message [chat-id from timestamp temp-id to-clock] |
67 | | - {:message-id temp-id |
68 | | - :outgoing false |
69 | | - :chat-id chat-id |
70 | | - :from from |
71 | | - :to "me" |
72 | | - :content "Waiting for message to arrive..." |
73 | | - :content-type constants/content-type-placeholder |
74 | | - :show? true |
75 | | - :from-clock-value temp-id |
76 | | - :to-clock-value to-clock |
77 | | - :timestamp timestamp}) |
78 | | - |
79 | | -(defn- add-placeholder-messages [chat-id from timestamp old-from-clock to-clock new-from-clock {:keys [db]}] |
80 | | - (when (> (- new-from-clock old-from-clock) 1) |
81 | | - {:db (reduce (fn [db temp-id] |
82 | | - (assoc-in db [:chats chat-id :messages temp-id] (placeholder-message chat-id from timestamp temp-id to-clock))) |
83 | | - db |
84 | | - (range (inc old-from-clock) new-from-clock))})) |
85 | 53 |
|
86 | 54 | (defn- add-received-message |
87 | | - [{:keys [from message-id chat-id content content-type timestamp to-clock-value] :as message} |
| 55 | + [{:keys [from message-id chat-id content content-type timestamp clock-value to-clock-value] :as message} |
88 | 56 | {:keys [db now] :as cofx}] |
89 | 57 | (let [{:keys [current-chat-id |
90 | 58 | view-id |
91 | 59 | access-scope->commands-responses] |
92 | 60 | :contacts/keys [contacts]} db |
93 | 61 | {:keys [public-key] :as current-account} (get-current-account db) |
94 | 62 | current-chat? (and (= :chat view-id) (= current-chat-id chat-id)) |
95 | | - {:keys [last-from-clock-value |
96 | | - last-to-clock-value] :as chat} (get-in db [:chats chat-id]) |
| 63 | + {:keys [last-clock-value] :as chat} (get-in db [:chats chat-id]) |
97 | 64 | request-command (:request-command content) |
98 | 65 | command-request? (and (= content-type constants/content-type-command-request) |
99 | 66 | request-command) |
100 | | - new-from-clock-value (or to-clock-value (inc last-from-clock-value)) |
101 | 67 | new-timestamp (or timestamp now)] |
102 | 68 | (handlers/merge-fx cofx |
103 | 69 | (add-message chat-id |
104 | 70 | (cond-> (assoc message |
105 | 71 | :timestamp new-timestamp |
106 | | - :show? true |
107 | | - :from-clock-value new-from-clock-value |
108 | | - :to-clock-value last-to-clock-value) |
| 72 | + :show? true) |
109 | 73 | public-key |
110 | 74 | (assoc :user-statuses {public-key (if current-chat? :seen :received)}) |
| 75 | + |
| 76 | + (not clock-value) |
| 77 | + (assoc :clock-value (utils.clocks/send last-clock-value)) ; TODO (cammeelos): for backward compatibility, we use received time to be removed when not an issue anymore |
111 | 78 | command-request? |
112 | 79 | (assoc-in [:content :request-command-ref] |
113 | 80 | (lookup-response-ref access-scope->commands-responses |
|
116 | 83 | (send-message-seen chat-id message-id (and public-key |
117 | 84 | current-chat? |
118 | 85 | (not (chat-model/bot-only-chat? db chat-id)) |
119 | | - (not (= constants/system from)))) |
120 | | - (add-placeholder-messages chat-id from new-timestamp last-from-clock-value last-to-clock-value new-from-clock-value)))) |
| 86 | + (not (= constants/system from))))))) |
121 | 87 |
|
122 | 88 | (defn receive |
123 | 89 | [{:keys [chat-id message-id] :as message} cofx] |
|
213 | 179 | (defn add-message-type [message {:keys [chat-id group-chat public?]}] |
214 | 180 | (cond-> message |
215 | 181 | (not group-chat) |
216 | | - (assoc :message-type :user-message) |
| 182 | + (assoc :message-type :user-message) |
217 | 183 | (and group-chat public?) |
218 | 184 | (assoc :message-type :public-group-user-message) |
219 | 185 | (and group-chat (not public?)) |
220 | 186 | (assoc :message-type :group-user-message))) |
221 | 187 |
|
222 | 188 | (defn- prepare-plain-message [chat-id {:keys [identity message-text]} |
223 | | - {:keys [last-to-clock-value last-from-clock-value] :as chat} now] |
| 189 | + {:keys [last-clock-value] :as chat} now] |
224 | 190 | (add-message-type {:chat-id chat-id |
225 | 191 | :content message-text |
226 | 192 | :from identity |
227 | 193 | :content-type constants/text-content-type |
228 | 194 | :outgoing true |
229 | 195 | :timestamp now |
230 | | - :to-clock-value (inc last-to-clock-value) |
231 | | - :from-clock-value last-from-clock-value |
| 196 | + :clock-value (utils.clocks/send last-clock-value) |
232 | 197 | :show? true} |
233 | 198 | chat)) |
234 | 199 |
|
235 | | -(def ^:private transport-keys [:content :content-type :message-type :to-clock-value :timestamp]) |
| 200 | +(def ^:private transport-keys [:content :content-type :message-type :clock-value :timestamp]) |
236 | 201 |
|
237 | 202 | (defn- upsert-and-send [{:keys [chat-id] :as message} cofx] |
238 | 203 | (let [send-record (protocol/map->Message (select-keys message transport-keys)) |
|
247 | 212 |
|
248 | 213 | (defn- prepare-command-message |
249 | 214 | [identity |
250 | | - {:keys [last-to-clock-value last-from-clock-value chat-id] :as chat} |
| 215 | + {:keys [last-clock-value chat-id] :as chat} |
251 | 216 | now |
252 | 217 | {request-params :params |
253 | 218 | request-command :command |
|
280 | 245 | constants/content-type-command-request |
281 | 246 | constants/content-type-command)) |
282 | 247 | :outgoing true |
283 | | - :to-clock-value (inc last-to-clock-value) |
284 | | - :from-clock-value last-from-clock-value |
| 248 | + :clock-value (utils.clocks/send last-clock-value) |
285 | 249 | :show? true} |
286 | 250 | chat))) |
287 | 251 |
|
|
0 commit comments