Move message processing to status-go and introduce protobuf
This commit moves all the processing of messages to status-go. Messages are going arrive to status-react already saved an processed. Receiving/sending/retrieving from db is now using the same identical structure. The only processing left in status-react is to mark the messages as seen and update the unviewed count locally (only status-react knows whether the count should be updated). Partially remove commands as well as won't be used anymore. Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
bee7804fd0
commit
78d694f52f
|
@ -57,6 +57,8 @@ var TopLevel = {
|
|||
"code" : function () {},
|
||||
"concat" : function () {},
|
||||
"confirmMessagesProcessed" : function () {},
|
||||
"chats": function() {},
|
||||
"rawMessages": function() {},
|
||||
"messages": function() {},
|
||||
"discovery": function() {},
|
||||
"dismiss": function() {},
|
||||
|
|
|
@ -140,7 +140,7 @@ class NewMessageSignalHandler {
|
|||
|
||||
void handleNewMessageSignal(JSONObject newMessageSignal) {
|
||||
try {
|
||||
JSONArray chatsNewMessagesData = newMessageSignal.getJSONObject("event").getJSONArray("messages");
|
||||
JSONArray chatsNewMessagesData = newMessageSignal.getJSONObject("event").getJSONArray("chats");
|
||||
for (int i = 0; i < chatsNewMessagesData.length(); i++) {
|
||||
try {
|
||||
upsertChat(chatsNewMessagesData.getJSONObject(i));
|
||||
|
@ -148,6 +148,15 @@ class NewMessageSignalHandler {
|
|||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
JSONArray messagesNewMessagesData = newMessageSignal.getJSONObject("event").getJSONArray("messages");
|
||||
for (int i = 0; i < messagesNewMessagesData.length(); i++) {
|
||||
try {
|
||||
upsertMessage(messagesNewMessagesData.getJSONObject(i));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if(shouldRefreshNotifications) {
|
||||
refreshNotifications();
|
||||
shouldRefreshNotifications = false;
|
||||
|
@ -173,72 +182,69 @@ class NewMessageSignalHandler {
|
|||
return person;
|
||||
}
|
||||
|
||||
private void upsertChat(JSONObject chatNewMessagesData) {
|
||||
private void upsertChat(JSONObject chatData) {
|
||||
try {
|
||||
JSONObject chatData = chatNewMessagesData.getJSONObject("chat");
|
||||
// NOTE: this is an exemple of chatData
|
||||
// {"chatId":"contact-discovery-3622","filterId":"c0239d63f830e8b25f4bf7183c8d207f355a925b89514a17068cae4898e7f193",
|
||||
// "symKeyId":"","oneToOne":true,"identity":"046599511623d7385b926ce709ac57d518dac10d451a81f75cd32c7fb4b1c...",
|
||||
// "topic":"0xc446561b","discovery":false,"negotiated":false,"listen":true}
|
||||
boolean oneToOne = chatData.getBoolean("oneToOne");
|
||||
int oneToOne = chatData.getInt("chatType");
|
||||
// NOTE: for now we only notify one to one chats
|
||||
// TODO: also notifiy on mentions, keywords and group chats
|
||||
// TODO: one would have to pass the ens name and keywords to notify on when instanciating the class as well
|
||||
// as have a method to add new ones after the handler is instanciated
|
||||
if (oneToOne) {
|
||||
JSONArray messagesData = chatNewMessagesData.getJSONArray("messages");
|
||||
if (oneToOne == 1) {
|
||||
//JSONArray messagesData = chatNewMessagesData.getJSONArray("messages");
|
||||
|
||||
// there is no proper id for oneToOne chat in chatData so we peek into first message sig
|
||||
// TODO: won't work for sync becaus it could be our own message
|
||||
String id = messagesData.getJSONObject(0).getJSONObject("message").getString("sig");
|
||||
String id = chatData.getString("id");
|
||||
StatusChat chat = chats.get(id);
|
||||
|
||||
|
||||
// if the chat was not already there, we create one
|
||||
if (chat == null) {
|
||||
chat = new StatusChat(id, oneToOne);
|
||||
chat = new StatusChat(id, true);
|
||||
}
|
||||
|
||||
ArrayList<StatusMessage> messages = chat.getMessages();
|
||||
// parse the new messages
|
||||
for (int j = 0; j < messagesData.length(); j++) {
|
||||
StatusMessage message = createMessage(messagesData.getJSONObject(j));
|
||||
if (message != null) {
|
||||
messages.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
chat.setMessages(messages);
|
||||
chats.put(id, chat);
|
||||
shouldRefreshNotifications = true;
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private StatusMessage createMessage(JSONObject messageData) {
|
||||
try {
|
||||
JSONObject metadata = messageData.getJSONObject("metadata");
|
||||
JSONObject authorMetadata = metadata.getJSONObject("author");
|
||||
JSONArray payload = new JSONArray(messageData.getString("payload"));
|
||||
// NOTE: this is an exemple of payload we are currently working with
|
||||
// it is in the transit format, which is basically JSON
|
||||
// refer to `transport.message.transit.cljs` on react side for details
|
||||
// ["~#c4",["7","text/plain","~:public-group-user-message",157201130275201,1572011302752,["^ ","~:chat-id","test","~:text","7"]]]
|
||||
if (payload.getString(0).equals("~#c4")) {
|
||||
Person author = getPerson(authorMetadata.getString("publicKey"), authorMetadata.getString("identicon"), authorMetadata.getString("alias"));
|
||||
JSONArray payloadContent = payload.getJSONArray(1);
|
||||
String text = payloadContent.getString(0);
|
||||
Double timestamp = payloadContent.getDouble(4);
|
||||
return new StatusMessage(author, timestamp.longValue(), text);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
|
||||
|
||||
private void upsertMessage(JSONObject messageData) {
|
||||
try {
|
||||
String chatId = messageData.getString("localChatId");
|
||||
StatusChat chat = chats.get(chatId);
|
||||
if (chat == null) {
|
||||
return;
|
||||
}
|
||||
return null;
|
||||
|
||||
StatusMessage message = createMessage(messageData);
|
||||
if (message != null) {
|
||||
chat.appendMessage(message);
|
||||
chats.put(chatId, chat);
|
||||
shouldRefreshNotifications = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private StatusMessage createMessage(JSONObject messageData) {
|
||||
try {
|
||||
Person author = getPerson(messageData.getString("from"), messageData.getString("identicon"), messageData.getString("alias"));
|
||||
return new StatusMessage(author, messageData.getLong("whisperTimestamp"), messageData.getString("text"));
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSON conversion failed: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,6 +258,7 @@ class StatusChat {
|
|||
this.id = id;
|
||||
this.oneToOne = oneToOne;
|
||||
this.messages = new ArrayList<StatusMessage>();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -259,15 +266,23 @@ class StatusChat {
|
|||
}
|
||||
|
||||
public String getName() {
|
||||
//TODO this should be improved as it would rename the chat
|
||||
// after our own user if we were posting from another device
|
||||
// in 1-1 chats it should be the name of the user whose
|
||||
// key is different than ours
|
||||
return getLastMessage().getAuthor().getName().toString();
|
||||
|
||||
//TODO this should be improved as it would rename the chat
|
||||
// after our own user if we were posting from another device
|
||||
// in 1-1 chats it should be the name of the user whose
|
||||
// key is different than ours
|
||||
StatusMessage message = getLastMessage();
|
||||
if (message == null) {
|
||||
return "no-name";
|
||||
}
|
||||
return message.getAuthor().getName().toString();
|
||||
}
|
||||
|
||||
private StatusMessage getLastMessage() {
|
||||
if (messages.size() > 0) {
|
||||
return messages.get(messages.size()-1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
|
@ -278,8 +293,8 @@ class StatusChat {
|
|||
return messages;
|
||||
}
|
||||
|
||||
public void setMessages(ArrayList<StatusMessage> messages) {
|
||||
this.messages = messages;
|
||||
public void appendMessage(StatusMessage message) {
|
||||
this.messages.add(message);
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
|
|
|
@ -114,13 +114,6 @@
|
|||
[{:keys [db] :as cofx} chat-id]
|
||||
(chats-store/save-chat cofx (get-in db [:chats chat-id])))
|
||||
|
||||
(fx/defn save-chat-delayed
|
||||
"Debounce saving the chat"
|
||||
[_ chat-id]
|
||||
{:dispatch-debounce [{:key :save-chat
|
||||
:event [::save-chat chat-id]
|
||||
:delay 500}]})
|
||||
|
||||
(fx/defn add-public-chat
|
||||
"Adds new public group chat to db"
|
||||
[cofx topic]
|
||||
|
@ -139,12 +132,9 @@
|
|||
"Clears history of the particular chat"
|
||||
[{:keys [db] :as cofx} chat-id]
|
||||
(let [{:keys [messages
|
||||
last-message
|
||||
deleted-at-clock-value]} (get-in db [:chats chat-id])
|
||||
last-message-clock-value (or (->> messages
|
||||
vals
|
||||
(sort-by (comp unchecked-negate :clock-value))
|
||||
first
|
||||
:clock-value)
|
||||
last-message-clock-value (or (:clock-value last-message)
|
||||
deleted-at-clock-value
|
||||
(utils.clocks/send 0))]
|
||||
(fx/merge
|
||||
|
@ -152,9 +142,7 @@
|
|||
{:db (update-in db [:chats chat-id] merge
|
||||
{:messages {}
|
||||
:message-list nil
|
||||
:last-message-content nil
|
||||
:last-message-content-type nil
|
||||
:last-message-timestamp nil
|
||||
:last-message nil
|
||||
:unviewed-messages-count 0
|
||||
:deleted-at-clock-value last-message-clock-value})}
|
||||
(messages-store/delete-messages-by-chat-id chat-id)
|
||||
|
@ -204,13 +192,11 @@
|
|||
[{:keys [db] :as cofx} {:keys [chat-id loaded-unviewed-messages-ids]}]
|
||||
(let [{:keys [loaded-unviewed-messages-ids unviewed-messages-count]}
|
||||
(get-in db [:chats chat-id])]
|
||||
(upsert-chat
|
||||
cofx
|
||||
{:chat-id chat-id
|
||||
:unviewed-messages-count (subtract-seen-messages
|
||||
unviewed-messages-count
|
||||
loaded-unviewed-messages-ids)
|
||||
:loaded-unviewed-messages-ids #{}})))
|
||||
{:db (update-in db [:chats chat-id] assoc
|
||||
:unviewed-messages-count (subtract-seen-messages
|
||||
unviewed-messages-count
|
||||
loaded-unviewed-messages-ids)
|
||||
:loaded-unviewed-messages-ids #{})}))
|
||||
|
||||
(fx/defn mark-messages-seen
|
||||
"Marks all unviewed loaded messages as seen in particular chat"
|
||||
|
@ -224,7 +210,7 @@
|
|||
true))
|
||||
db
|
||||
loaded-unviewed-ids)}
|
||||
(messages-store/mark-messages-seen loaded-unviewed-ids)
|
||||
(messages-store/mark-messages-seen chat-id loaded-unviewed-ids)
|
||||
(update-chats-unviewed-messages-count {:chat-id chat-id})
|
||||
(when platform/desktop?
|
||||
(update-dock-badge-label))))))
|
||||
|
|
|
@ -100,12 +100,9 @@
|
|||
:content-type (if emoji?
|
||||
constants/content-type-emoji
|
||||
constants/content-type-text)
|
||||
:content (cond-> {:chat-id current-chat-id
|
||||
:text input-text}
|
||||
message-id
|
||||
(assoc :response-to message-id)
|
||||
preferred-name
|
||||
(assoc :name preferred-name))})
|
||||
:text input-text
|
||||
:response-to message-id
|
||||
:ens-name preferred-name})
|
||||
(set-chat-input-text nil)
|
||||
(process-cooldown)))))
|
||||
|
||||
|
@ -114,10 +111,9 @@
|
|||
(when-not (string/blank? hash)
|
||||
(chat.message/send-message cofx {:chat-id current-chat-id
|
||||
:content-type constants/content-type-sticker
|
||||
:content (cond-> {:chat-id current-chat-id
|
||||
:hash hash
|
||||
:pack pack
|
||||
:text "Update to latest version to see a nice sticker here!"})})))
|
||||
:sticker {:hash hash
|
||||
:pack pack}
|
||||
:text "Update to latest version to see a nice sticker here!"})))
|
||||
|
||||
(fx/defn send-current-message
|
||||
"Sends message from current chat input"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
[status-im.chat.models.message-content :as message-content]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[status-im.data-store.messages :as messages-store]
|
||||
[status-im.data-store.messages :as data-store.messages]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.mailserver.core :as mailserver]
|
||||
[status-im.native-module.core :as status]
|
||||
|
@ -26,40 +26,20 @@
|
|||
[status-im.utils.types :as types]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn- wrap-group-message
|
||||
"Wrap a group message in a membership update"
|
||||
[cofx chat-id message]
|
||||
(when-let [chat (get-in cofx [:db :chats chat-id])]
|
||||
(message.group-chat/map->GroupMembershipUpdate.
|
||||
{:chat-id chat-id
|
||||
:membership-updates (:membership-updates chat)
|
||||
:message message})))
|
||||
|
||||
(defn- prepare-message
|
||||
[{:keys [content content-type] :as message} chat-id current-chat?]
|
||||
(cond-> message
|
||||
current-chat?
|
||||
(assoc :seen true) (and (= constants/content-type-text content-type)
|
||||
(message-content/should-collapse?
|
||||
(:text content)
|
||||
(:line-count content)))
|
||||
(assoc :seen true)
|
||||
|
||||
(and (= constants/content-type-text content-type)
|
||||
(message-content/should-collapse?
|
||||
(:text content)
|
||||
(:line-count content)))
|
||||
(assoc :should-collapse? true)))
|
||||
|
||||
(defn system-message? [{:keys [message-type]}]
|
||||
(= :system-message message-type))
|
||||
|
||||
(defn add-outgoing-status
|
||||
[{:keys [from outgoing-status] :as message} current-public-key]
|
||||
(if (and (= from current-public-key)
|
||||
(not (system-message? message)))
|
||||
(assoc message
|
||||
:outgoing true
|
||||
;; We don't override outgoing-status if there, which means
|
||||
;; that our device has sent the message, while if empty is coming
|
||||
;; from a different device
|
||||
:outgoing-status (or outgoing-status :sent))
|
||||
message))
|
||||
(= constants/message-type-private-group-system-message message-type))
|
||||
|
||||
(defn build-desktop-notification
|
||||
[{:keys [db] :as cofx} {:keys [chat-id timestamp content from] :as message}]
|
||||
|
@ -81,16 +61,10 @@
|
|||
|
||||
(fx/defn add-message
|
||||
[{:keys [db] :as cofx}
|
||||
{{:keys [chat-id message-id clock-value timestamp from] :as message} :message
|
||||
:keys [current-chat? batch?]}]
|
||||
{{:keys [chat-id message-id timestamp from] :as message} :message
|
||||
:keys [current-chat?]}]
|
||||
(let [current-public-key (multiaccounts.model/current-public-key cofx)
|
||||
prepared-message (-> message
|
||||
(prepare-message chat-id current-chat?)
|
||||
(add-outgoing-status current-public-key))
|
||||
chat-initialized?
|
||||
(or
|
||||
current-chat?
|
||||
(get-in db [:chats chat-id :messages-initialized?]))]
|
||||
prepared-message (prepare-message message chat-id current-chat?)]
|
||||
(when (and platform/desktop?
|
||||
(not= from current-public-key)
|
||||
(get-in db [:multiaccount :desktop-notifications?])
|
||||
|
@ -100,7 +74,6 @@
|
|||
(fx/merge cofx
|
||||
{:db (cond->
|
||||
(-> db
|
||||
(update-in [:chats chat-id :last-clock-value] (partial utils.clocks/receive clock-value))
|
||||
;; We should not be always adding to the list, as it does not make sense
|
||||
;; if the chat has not been initialized, but run into
|
||||
;; some troubles disabling it, so next time
|
||||
|
@ -110,25 +83,21 @@
|
|||
(not= from current-public-key))
|
||||
(update-in [:chats chat-id :loaded-unviewed-messages-ids]
|
||||
(fnil conj #{}) message-id))}
|
||||
#(messages-store/save-message % prepared-message)
|
||||
(when (and platform/desktop?
|
||||
(not batch?)
|
||||
(not (system-message? prepared-message)))
|
||||
|
||||
(chat-model/update-dock-badge-label)))))
|
||||
|
||||
(fx/defn add-received-message
|
||||
[{:keys [db] :as cofx}
|
||||
{:keys [from message-id chat-id content metadata] :as message}]
|
||||
{:keys [from message-id chat-id content] :as message}]
|
||||
(let [{:keys [current-chat-id view-id]} db
|
||||
current-public-key (multiaccounts.model/current-public-key cofx)
|
||||
current-chat? (and (or (= :chat view-id)
|
||||
(= :chat-modal view-id))
|
||||
(= current-chat-id chat-id))]
|
||||
(add-message cofx {:batch? true
|
||||
:message message
|
||||
:metadata metadata
|
||||
:current-chat? current-chat?})))
|
||||
(fx/merge cofx
|
||||
(add-message {:message message
|
||||
:current-chat? current-chat?}))))
|
||||
|
||||
(defn- add-to-chat?
|
||||
[{:keys [db]} {:keys [chat-id clock-value message-id from]}]
|
||||
|
@ -140,43 +109,36 @@
|
|||
(defn extract-chat-id [cofx {:keys [chat-id from message-type]}]
|
||||
"Validate and return a valid chat-id"
|
||||
(cond
|
||||
(and (= :group-user-message message-type)
|
||||
(and (= constants/message-type-private-group message-type)
|
||||
(and (get-in cofx [:db :chats chat-id :contacts from])
|
||||
(get-in cofx [:db :chats chat-id :members-joined (multiaccounts.model/current-public-key cofx)]))) chat-id
|
||||
(and (= :public-group-user-message message-type)
|
||||
(and (= constants/message-type-public-group message-type)
|
||||
(get-in cofx [:db :chats chat-id :public?])) chat-id
|
||||
(and (= :user-message message-type)
|
||||
(and (= constants/message-type-one-to-one message-type)
|
||||
(= (multiaccounts.model/current-public-key cofx) from)) chat-id
|
||||
(= :user-message message-type) from))
|
||||
(= constants/message-type-one-to-one message-type) from))
|
||||
|
||||
(defn calculate-unviewed-message-count
|
||||
[{:keys [db] :as cofx} {:keys [chat-id from]}]
|
||||
(fx/defn update-unviewed-count
|
||||
[{:keys [now db] :as cofx} {:keys [chat-id
|
||||
from
|
||||
message-id] :as message}]
|
||||
(let [{:keys [current-chat-id view-id]} db
|
||||
chat-view? (or (= :chat view-id)
|
||||
(= :chat-modal view-id))
|
||||
current-count (get-in db [:chats chat-id :unviewed-messages-count])]
|
||||
(if (or (and chat-view? (= current-chat-id chat-id))
|
||||
(= from (multiaccounts.model/current-public-key cofx)))
|
||||
current-count
|
||||
(inc current-count))))
|
||||
(cond
|
||||
(= from (multiaccounts.model/current-public-key cofx))
|
||||
;; nothing to do
|
||||
nil
|
||||
|
||||
(fx/defn update-unviewed-count [{:keys [now db] :as cofx} {:keys [chat-id] :as message}]
|
||||
{:db (update-in db [:chats chat-id]
|
||||
assoc
|
||||
:is-active true
|
||||
:timestamp now
|
||||
:unviewed-messages-count (calculate-unviewed-message-count cofx message))})
|
||||
(and chat-view? (= current-chat-id chat-id))
|
||||
(fx/merge cofx
|
||||
(data-store.messages/mark-messages-seen current-chat-id [message-id]))
|
||||
|
||||
(fx/defn update-last-message [{:keys [db]} {:keys [clock-value chat-id content timestamp content-type]}]
|
||||
(let [last-chat-clock-value (get-in db [:chats chat-id :last-message-clock-value])]
|
||||
;; We should also compare message-id in case of clashes, but not sure it's worth
|
||||
(when (> clock-value last-chat-clock-value)
|
||||
:else
|
||||
{:db (update-in db [:chats chat-id]
|
||||
assoc
|
||||
:last-message-clock-value clock-value
|
||||
:last-message-content content
|
||||
:last-message-timestamp timestamp
|
||||
:last-message-content-type content-type)})))
|
||||
:unviewed-messages-count (inc current-count))})))
|
||||
|
||||
(fx/defn receive-one
|
||||
[cofx message]
|
||||
|
@ -184,128 +146,32 @@
|
|||
(let [message-with-chat-id (assoc message :chat-id chat-id)]
|
||||
(when (add-to-chat? cofx message-with-chat-id)
|
||||
(fx/merge cofx
|
||||
(chat-model/ensure-chat {:chat-id chat-id})
|
||||
(add-received-message message-with-chat-id)
|
||||
(update-unviewed-count message-with-chat-id)
|
||||
(chat-model/join-time-messages-checked chat-id)
|
||||
(update-last-message message-with-chat-id)
|
||||
(when platform/desktop?
|
||||
(chat-model/update-dock-badge-label))
|
||||
;; And save chat
|
||||
(chat-model/save-chat-delayed chat-id))))))
|
||||
|
||||
(defn system-message [{:keys [now] :as cofx} {:keys [clock-value chat-id content from]}]
|
||||
(let [{:keys [last-clock-value]} (get-in cofx [:db :chats chat-id])
|
||||
message {:chat-id chat-id
|
||||
:from from
|
||||
:timestamp now
|
||||
:whisper-timestamp now
|
||||
:clock-value (or clock-value
|
||||
(utils.clocks/send last-clock-value))
|
||||
:content content
|
||||
:message-type :system-message
|
||||
:content-type constants/content-type-status}]
|
||||
(assoc message
|
||||
:message-id (transport.utils/system-message-id message))))
|
||||
|
||||
(defn group-message? [{:keys [message-type]}]
|
||||
(#{:group-user-message :public-group-user-message} message-type))
|
||||
(chat-model/update-dock-badge-label)))))))
|
||||
|
||||
;;;; Send message
|
||||
|
||||
(fx/defn send
|
||||
[{{:keys [peers-count]} :db :as cofx} chat-id message send-record]
|
||||
(protocol/send send-record chat-id (assoc cofx :message message)))
|
||||
|
||||
(defn add-message-type [message {:keys [chat-id group-chat public?]}]
|
||||
(cond-> message
|
||||
(not group-chat)
|
||||
(assoc :message-type :user-message)
|
||||
(and group-chat public?)
|
||||
(assoc :message-type :public-group-user-message)
|
||||
(and group-chat (not public?))
|
||||
(assoc :message-type :group-user-message)))
|
||||
|
||||
(def ^:private transport-keys [:content :content-type :message-type :clock-value :timestamp :name])
|
||||
|
||||
(defn remove-icon
|
||||
"Coin's icon's resource is represented as a function,
|
||||
can't be properly de/serialised and has to be removed."
|
||||
[message]
|
||||
(cond-> message
|
||||
(get-in message [:content :params :coin :icon :source])
|
||||
(update-in [:content :params :coin] dissoc :icon)))
|
||||
|
||||
(fx/defn add-message-with-id [cofx message chat-id]
|
||||
(when (and message
|
||||
(not (get-in cofx [:db :chats chat-id :messages (:message-id message)])))
|
||||
(add-message cofx {:batch? false
|
||||
:message message
|
||||
:current-chat? (= (get-in cofx [:db :current-chat-id]) chat-id)})))
|
||||
|
||||
(fx/defn prepare-message-content [cofx chat-id message]
|
||||
{::json-rpc/call
|
||||
[{:method "shhext_prepareContent"
|
||||
:params [(:content message)]
|
||||
:on-success #(re-frame/dispatch [::prepared-message chat-id message %])
|
||||
:on-failure #(log/error "failed to prepare content" %)}]})
|
||||
|
||||
(fx/defn prepared-message
|
||||
{:events [::prepared-message]}
|
||||
[{:keys [now] :as cofx} chat-id message content]
|
||||
(let [message-with-content
|
||||
(update message :content
|
||||
assoc
|
||||
:parsed-text (:parsedText content)
|
||||
:line-count (:lineCount content)
|
||||
:should-collapse? (message-content/should-collapse?
|
||||
(:text content)
|
||||
(:lineCount content))
|
||||
:rtl? (:rtl content))
|
||||
send-record (protocol/map->Message
|
||||
(select-keys message-with-content transport-keys))
|
||||
wrapped-record (if (= (:message-type send-record) :group-user-message)
|
||||
(wrap-group-message cofx chat-id send-record)
|
||||
send-record)]
|
||||
(fx/merge cofx
|
||||
(chat-model/upsert-chat
|
||||
{:chat-id chat-id
|
||||
:timestamp now
|
||||
:last-message-timestamp (:timestamp message-with-content)
|
||||
:last-message-content (:content message-with-content)
|
||||
:last-message-content-type (:content-type message-with-content)
|
||||
:last-clock-value (:clock-value message-with-content)})
|
||||
(send chat-id message-with-content wrapped-record))))
|
||||
|
||||
(fx/defn upsert-and-send
|
||||
[{:keys [now] :as cofx} {:keys [chat-id from] :as message}]
|
||||
(let [message (remove-icon message)
|
||||
message (assoc message :outgoing-status :sending)]
|
||||
|
||||
(prepare-message-content cofx chat-id message)))
|
||||
|
||||
(fx/defn update-message-status
|
||||
[{:keys [db] :as cofx} chat-id message-id status]
|
||||
(fx/merge cofx
|
||||
{:db (assoc-in db
|
||||
[:chats chat-id :messages message-id :outgoing-status]
|
||||
status)}
|
||||
(messages-store/update-outgoing-status message-id status)))
|
||||
(data-store.messages/update-outgoing-status message-id status)))
|
||||
|
||||
(fx/defn resend-message
|
||||
[cofx chat-id message-id]
|
||||
(let [message (get-in cofx [:db :chats chat-id :messages message-id])
|
||||
send-record (-> message
|
||||
(select-keys transport-keys)
|
||||
(update :message-type keyword)
|
||||
protocol/map->Message)
|
||||
|
||||
wrapped-record (if (= (:message-type send-record) :group-user-message)
|
||||
(wrap-group-message cofx chat-id send-record)
|
||||
send-record)]
|
||||
(fx/merge cofx
|
||||
(send chat-id message wrapped-record)
|
||||
(update-message-status chat-id message-id :sending))))
|
||||
[{:keys [db] :as cofx} chat-id message-id]
|
||||
(fx/merge cofx
|
||||
{::json-rpc/call [{:method "shhext_reSendChatMessage"
|
||||
:params [message-id]
|
||||
:on-success #(log/debug "re-sent message successfully")
|
||||
:on-error #(log/error "failed to re-send message" %)}]}
|
||||
(update-message-status chat-id message-id :sending)))
|
||||
|
||||
(fx/defn rebuild-message-list
|
||||
[{:keys [db]} chat-id]
|
||||
|
@ -317,35 +183,26 @@
|
|||
[{:keys [db] :as cofx} chat-id message-id]
|
||||
(fx/merge cofx
|
||||
{:db (update-in db [:chats chat-id :messages] dissoc message-id)}
|
||||
(messages-store/delete-message message-id)
|
||||
(data-store.messages/delete-message message-id)
|
||||
(rebuild-message-list chat-id)))
|
||||
|
||||
(fx/defn handle-saved-system-messages
|
||||
{:events [:messages/system-messages-saved]}
|
||||
[cofx messages]
|
||||
(apply fx/merge cofx (map #(add-message {:message %
|
||||
:current-chat? true})
|
||||
messages)))
|
||||
|
||||
(fx/defn add-system-messages [cofx messages]
|
||||
(let [messages-fx (map #(add-message
|
||||
{:batch false
|
||||
:message (system-message cofx %)
|
||||
:current-chat? true})
|
||||
messages)]
|
||||
(apply fx/merge cofx messages-fx)))
|
||||
(data-store.messages/save-system-messages cofx messages))
|
||||
|
||||
(fx/defn send-message
|
||||
[{:keys [db now] :as cofx} {:keys [chat-id] :as message}]
|
||||
(let [{:keys [chats]} db
|
||||
{:keys [last-clock-value] :as chat} (get chats chat-id)
|
||||
message-data (-> message
|
||||
(assoc :from (multiaccounts.model/current-public-key cofx)
|
||||
:timestamp now
|
||||
:whisper-timestamp now
|
||||
:clock-value (utils.clocks/send
|
||||
last-clock-value))
|
||||
(tribute-to-talk/add-transaction-hash db)
|
||||
(add-message-type chat))]
|
||||
(upsert-and-send cofx message-data)))
|
||||
(tribute-to-talk/add-transaction-hash db))]
|
||||
(protocol/send-chat-message cofx message-data)))
|
||||
|
||||
(fx/defn toggle-expand-message
|
||||
[{:keys [db]} chat-id message-id]
|
||||
{:db (update-in db [:chats chat-id :messages message-id :expanded?] not)})
|
||||
|
||||
(fx/defn confirm-message-processed
|
||||
[_ raw-message]
|
||||
{:transport/confirm-messages-processed [raw-message]})
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require
|
||||
[status-im.js-dependencies :as dependencies]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.chat.db :as chat.db]
|
||||
[status-im.utils.datetime :as time]))
|
||||
|
@ -20,12 +21,13 @@
|
|||
whisper-timestamp]}]
|
||||
(-> {:whisper-timestamp whisper-timestamp
|
||||
:from from
|
||||
:one-to-one? (= :user-message message-type)
|
||||
:system-message? (= :system-message message-type)
|
||||
:one-to-one? (= constants/message-type-one-to-one message-type)
|
||||
:system-message? (= constants/message-type-private-group-system-message
|
||||
message-type)
|
||||
:clock-value clock-value
|
||||
:type :message
|
||||
:message-id message-id
|
||||
:outgoing outgoing}
|
||||
:outgoing (boolean outgoing)}
|
||||
add-datemark
|
||||
add-timestamp))
|
||||
|
||||
|
@ -65,7 +67,8 @@
|
|||
We divide messages in groups. Messages are sorted descending so :first? is
|
||||
the most recent message, similarly :first-in-group? is the most recent message
|
||||
in a group."
|
||||
[{:keys [one-to-one? outgoing] :as current-message}
|
||||
[{:keys [system-message?
|
||||
one-to-one? outgoing] :as current-message}
|
||||
{:keys [outgoing-seen?] :as previous-message}
|
||||
next-message]
|
||||
(let [last-in-group? (or (nil? next-message)
|
||||
|
@ -80,6 +83,7 @@
|
|||
(not (same-group? current-message previous-message)))
|
||||
:last-in-group? last-in-group?
|
||||
:display-username? (and last-in-group?
|
||||
(not system-message?)
|
||||
(not outgoing)
|
||||
(not one-to-one?))
|
||||
:display-photo? (display-photo? current-message))))
|
||||
|
@ -100,10 +104,13 @@
|
|||
|
||||
(defn update-previous-message
|
||||
"If this is a new group, we mark the previous as the last one in the group"
|
||||
[current-message {:keys [one-to-one? outgoing] :as previous-message}]
|
||||
[current-message {:keys [one-to-one?
|
||||
system-message?
|
||||
outgoing] :as previous-message}]
|
||||
(let [last-in-group? (not (same-group? current-message previous-message))]
|
||||
(assoc previous-message
|
||||
:display-username? (and last-in-group?
|
||||
(not system-message?)
|
||||
(not outgoing)
|
||||
(not one-to-one?))
|
||||
:last-in-group? last-in-group?)))
|
||||
|
|
|
@ -7,10 +7,15 @@
|
|||
|
||||
(def ms-in-bg-for-require-bioauth 5000)
|
||||
|
||||
(def content-type-text "text/plain")
|
||||
(def content-type-sticker "sticker")
|
||||
(def content-type-status "status")
|
||||
(def content-type-emoji "emoji")
|
||||
(def content-type-text 0)
|
||||
(def content-type-sticker 1)
|
||||
(def content-type-status 2)
|
||||
(def content-type-emoji 3)
|
||||
|
||||
(def message-type-one-to-one 0)
|
||||
(def message-type-public-group 1)
|
||||
(def message-type-private-group 2)
|
||||
(def message-type-private-group-system-message 3)
|
||||
|
||||
(def desktop-content-types
|
||||
#{content-type-text content-type-emoji content-type-status})
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
public-key
|
||||
{:keys [chat-id
|
||||
unviewed-messages-count
|
||||
last-message-content
|
||||
last-message-timestamp
|
||||
last-message-content-type]}]
|
||||
last-message]}]
|
||||
(let [removed-messages-ids (keep
|
||||
(fn [[message-id {:keys [from]}]]
|
||||
(when (= from public-key)
|
||||
|
@ -41,9 +39,7 @@
|
|||
(update-in [:chats chat-id]
|
||||
assoc
|
||||
:unviewed-messages-count unviewed-messages-count
|
||||
:last-message-content last-message-content
|
||||
:last-message-timestamp last-message-timestamp
|
||||
:last-message-content-type last-message-content-type))]
|
||||
:last-message last-message))]
|
||||
{:db (update-in db [:chats chat-id :message-list] message-list/add-many (vals (get-in db [:chats chat-id :messages])))}))
|
||||
|
||||
(fx/defn contact-blocked
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
(->> members
|
||||
(map #(or (get all-contacts %)
|
||||
(public-key->new-contact %)))
|
||||
(sort-by (comp clojure.string/lower-case :name))
|
||||
(sort-by (comp clojure.string/lower-case #(or (:name %) (:alias %))))
|
||||
(map #(if (get admins (:public-key %))
|
||||
(assoc % :admin? true)
|
||||
%)))))
|
||||
|
|
|
@ -111,13 +111,11 @@
|
|||
type->rpc
|
||||
marshal-members
|
||||
(update :membership-updates marshal-membership-updates)
|
||||
(utils/update-if-present :last-message-content messages/prepare-content)
|
||||
(update :last-message messages/->rpc)
|
||||
(clojure.set/rename-keys {:chat-id :id
|
||||
:membership-updates :membershipUpdates
|
||||
:unviewed-messages-count :unviewedMessagesCount
|
||||
:last-message-content :lastMessageContent
|
||||
:last-message-content-type :lastMessageContentType
|
||||
:last-message-timestamp :lastMessageTimestamp
|
||||
:last-message :lastMessage
|
||||
:deleted-at-clock-value :deletedAtClockValue
|
||||
:is-active :active
|
||||
:last-clock-value :lastClockValue})
|
||||
|
@ -133,16 +131,13 @@
|
|||
unmarshal-members
|
||||
(clojure.set/rename-keys {:id :chat-id
|
||||
:membershipUpdates :membership-updates
|
||||
:unviewedMessagesCount :unviewed-messages-count
|
||||
:lastMessageContent :last-message-content
|
||||
:lastMessageContentType :last-message-content-type
|
||||
:lastMessageTimestamp :last-message-timestamp
|
||||
:deletedAtClockValue :deleted-at-clock-value
|
||||
:unviewedMessagesCount :unviewed-messages-count
|
||||
:lastMessage :last-message
|
||||
:active :is-active
|
||||
:lastClockValue :last-clock-value})
|
||||
(update :membership-updates (partial unmarshal-membership-updates (:id chat)))
|
||||
(update :last-message-content utils/safe-read-message-content)
|
||||
(update :last-clock-value utils.clocks/safe-timestamp)
|
||||
(update :last-message #(when % (messages/<-rpc %)))
|
||||
(dissoc :chatType :members)))
|
||||
|
||||
(fx/defn save-chat [cofx {:keys [chat-id] :as chat}]
|
||||
|
|
|
@ -10,55 +10,37 @@
|
|||
[status-im.constants :as constants]
|
||||
[status-im.utils.core :as utils]))
|
||||
|
||||
(defn prepare-content [content]
|
||||
(if (string? content)
|
||||
(defn ->rpc [{:keys [content] :as message}]
|
||||
(cond-> message
|
||||
content
|
||||
(utils.types/clj->json content)))
|
||||
|
||||
(defn ->rpc [message]
|
||||
(-> message
|
||||
(dissoc :dedup-id)
|
||||
(update :message-type name)
|
||||
(update :outgoing-status #(if % (name %) ""))
|
||||
(utils/update-if-present :content prepare-content)
|
||||
(clojure.set/rename-keys {:message-id :id
|
||||
:whisper-timestamp :whisperTimestamp
|
||||
:message-type :messageType
|
||||
:chat-id :chatId
|
||||
:content-type :contentType
|
||||
:clock-value :clockValue
|
||||
:outgoing-status :outgoingStatus})
|
||||
(assoc :replyTo (get-in message [:content :response-to]))))
|
||||
|
||||
(defn update-quoted-message [message]
|
||||
(let [parsed-content (utils/safe-read-message-content (get-in message [:quotedMessage :content]))]
|
||||
(cond-> message
|
||||
parsed-content
|
||||
(assoc :quoted-message {:from (get-in message [:quotedMessage :from])
|
||||
:text (:text parsed-content)})
|
||||
:always
|
||||
(dissoc message :quotedMessage))))
|
||||
(assoc :text (:text content)
|
||||
:sticker (:sticker content))
|
||||
:always
|
||||
(clojure.set/rename-keys {:chat-id :chatId
|
||||
:clock-value :clock})))
|
||||
|
||||
(defn <-rpc [message]
|
||||
(when-let [parsed-content (utils/safe-read-message-content (:content message))]
|
||||
(let [outgoing-status (when-not (empty? (:outgoingStatus message))
|
||||
(keyword (:outgoingStatus message)))]
|
||||
(-> message
|
||||
(clojure.set/rename-keys {:id :message-id
|
||||
:whisperTimestamp :whisper-timestamp
|
||||
:messageType :message-type
|
||||
:localChatId :chat-id
|
||||
:contentType :content-type
|
||||
:clock :clock-value
|
||||
:quotedMessage :quoted-message
|
||||
:outgoingStatus :outgoing-status})
|
||||
|
||||
(-> message
|
||||
(update :messageType keyword)
|
||||
(update :outgoingStatus keyword)
|
||||
(assoc :content parsed-content
|
||||
:outgoingStatus outgoing-status
|
||||
:outgoing outgoing-status)
|
||||
(update-quoted-message)
|
||||
(clojure.set/rename-keys {:id :message-id
|
||||
:whisperTimestamp :whisper-timestamp
|
||||
:messageType :message-type
|
||||
:chatId :chat-id
|
||||
:contentType :content-type
|
||||
:replyTo :reply-to
|
||||
:clockValue :clock-value
|
||||
:outgoingStatus :outgoing-status})))))
|
||||
(update :outgoing-status keyword)
|
||||
(assoc :content {:chat-id (:chatId message)
|
||||
:text (:text message)
|
||||
:sticker (:sticker message)
|
||||
:ens-name (:ensName message)
|
||||
:line-count (:lineCount message)
|
||||
:parsed-text (:parsedText message)
|
||||
:rtl (:rtl message)
|
||||
:response-to (:responseTo message)}
|
||||
:outgoing (boolean (:outgoingStatus message)))
|
||||
(dissoc :ensName :chatId :text :rtl :responseTo :sticker :lineCount :parsedText)))
|
||||
|
||||
(defn update-outgoing-status-rpc [message-id status]
|
||||
{::json-rpc/call [{:method "shhext_updateMessageOutgoingStatus"
|
||||
|
@ -66,12 +48,11 @@
|
|||
:on-success #(log/debug "updated message outgoing stauts" message-id status)
|
||||
:on-failure #(log/error "failed to update message outgoing status" message-id status %)}]})
|
||||
|
||||
(defn save-messages-rpc [messages]
|
||||
(let [confirmations (keep :metadata messages)]
|
||||
(json-rpc/call {:method "shhext_saveMessages"
|
||||
:params [(map ->rpc messages)]
|
||||
:on-success #(re-frame/dispatch [:message/messages-persisted confirmations])
|
||||
:on-failure #(log/error "failed to save messages" %)})))
|
||||
(defn save-system-messages-rpc [messages]
|
||||
(json-rpc/call {:method "shhext_addSystemMessages"
|
||||
:params [(map ->rpc messages)]
|
||||
:on-success #(re-frame/dispatch [:messages/system-messages-saved (map <-rpc %)])
|
||||
:on-failure #(log/error "failed to save messages" %)}))
|
||||
|
||||
(defn messages-by-chat-id-rpc [chat-id cursor limit on-success]
|
||||
{::json-rpc/call [{:method "shhext_chatMessages"
|
||||
|
@ -80,9 +61,9 @@
|
|||
(on-success (update result :messages #(map <-rpc %))))
|
||||
:on-failure #(log/error "failed to get messages" %)}]})
|
||||
|
||||
(defn mark-seen-rpc [ids]
|
||||
(defn mark-seen-rpc [chat-id ids]
|
||||
{::json-rpc/call [{:method "shhext_markMessagesSeen"
|
||||
:params [ids]
|
||||
:params [chat-id ids]
|
||||
:on-success #(log/debug "successfully marked as seen")
|
||||
:on-failure #(log/error "failed to get messages" %)}]})
|
||||
|
||||
|
@ -105,28 +86,12 @@
|
|||
:on-failure #(log/error "failed to delete messages by chat-id" % chat-id)}]})
|
||||
|
||||
(re-frame/reg-fx
|
||||
::save-message
|
||||
::save-system-message
|
||||
(fn [messages]
|
||||
(save-messages-rpc messages)))
|
||||
(save-system-messages-rpc messages)))
|
||||
|
||||
(fx/defn save-messages [{:keys [db]}]
|
||||
(when-let [messages (vals (:messages/stored db))]
|
||||
;; Pull message from database to pick up most recent changes, default to
|
||||
;; stored one in case it has been offloaded
|
||||
(let [hydrated-messages (map #(get-in db [:chats (-> % :content :chat-id) :messages (:message-id %)] %) messages)]
|
||||
{:db (dissoc db :messages/stored)
|
||||
::save-message hydrated-messages})))
|
||||
|
||||
(fx/defn handle-save-messages
|
||||
{:events [::save-messages]}
|
||||
[cofx]
|
||||
(save-messages cofx))
|
||||
|
||||
(fx/defn save-message [{:keys [db]} {:keys [message-id] :as message}]
|
||||
{:db (assoc-in db [:messages/stored message-id] message)
|
||||
:dispatch-debounce [{:key :save-messages
|
||||
:event [::save-messages]
|
||||
:delay 500}]})
|
||||
(fx/defn save-system-messages [cofx messages]
|
||||
{::save-system-message messages})
|
||||
|
||||
(fx/defn delete-message [cofx id]
|
||||
(delete-message-rpc id))
|
||||
|
@ -134,8 +99,8 @@
|
|||
(fx/defn delete-messages-from [cofx author]
|
||||
(delete-messages-from-rpc author))
|
||||
|
||||
(fx/defn mark-messages-seen [_ ids]
|
||||
(mark-seen-rpc ids))
|
||||
(fx/defn mark-messages-seen [_ chat-id ids]
|
||||
(mark-seen-rpc chat-id ids))
|
||||
|
||||
(fx/defn update-outgoing-status [cofx message-id status]
|
||||
(update-outgoing-status-rpc message-id status))
|
||||
|
|
|
@ -291,8 +291,8 @@
|
|||
(stateofus/valid-username? ens-name))))
|
||||
|
||||
(fx/defn verify-names-from-message [cofx {:keys [content]} signature]
|
||||
(when (should-be-verified? cofx (:name content) signature)
|
||||
{::verify-names [{:name (:name content)
|
||||
(when (should-be-verified? cofx (:ens-name content) signature)
|
||||
{::verify-names [{:name (:ens-name content)
|
||||
:publicKey (subs signature 2)}]}))
|
||||
|
||||
(fx/defn verify-names-from-contact-request [cofx {:keys [name]} signature]
|
||||
|
|
|
@ -35,13 +35,15 @@
|
|||
"shhext_sendPublicMessage" {}
|
||||
"shhext_enableInstallation" {}
|
||||
"shhext_disableInstallation" {}
|
||||
"shhext_sendChatMessage" {}
|
||||
"shhext_reSendChatMessage" {}
|
||||
"shhext_getOurInstallations" {}
|
||||
"shhext_setInstallationMetadata" {}
|
||||
"shhext_loadFilters" {}
|
||||
"shhext_loadFilter" {}
|
||||
"shhext_removeFilters" {}
|
||||
"shhext_chats" {}
|
||||
"shhext_saveMessages" {}
|
||||
"shhext_addSystemMessages" {}
|
||||
"shhext_deleteMessagesFrom" {}
|
||||
"shhext_deleteMessagesByChatID" {}
|
||||
"shhext_deleteMessage" {}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[re-frame.core :as re-frame]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.data-store.messages :as data-store.messages]
|
||||
|
||||
[status-im.data-store.chats :as data-store.chats]
|
||||
[status-im.multiaccounts.create.core :as multiaccounts.create]
|
||||
[status-im.multiaccounts.login.core :as multiaccounts.login]
|
||||
[status-im.multiaccounts.logout.core :as multiaccounts.logout]
|
||||
|
@ -172,10 +172,7 @@
|
|||
(handlers/register-handler-fx
|
||||
:multiaccounts.logout.ui/logout-confirmed
|
||||
(fn [cofx _]
|
||||
(fx/merge
|
||||
cofx
|
||||
(data-store.messages/save-messages)
|
||||
(multiaccounts.logout/logout))))
|
||||
(multiaccounts.logout/logout cofx)))
|
||||
|
||||
;; multiaccounts update module
|
||||
|
||||
|
@ -551,8 +548,12 @@
|
|||
|
||||
(handlers/register-handler-fx
|
||||
:chat.ui/resend-message
|
||||
(fn [cofx [_ chat-id message-id]]
|
||||
(chat.message/resend-message cofx chat-id message-id)))
|
||||
(fn [{:keys [db] :as cofx} [_ chat-id message-id]]
|
||||
(let [message (get-in db [:chats chat-id :messages message-id])]
|
||||
(fx/merge
|
||||
cofx
|
||||
(transport.message/set-message-envelope-hash chat-id message-id (:message-type message) 1)
|
||||
(chat.message/resend-message chat-id message-id)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:chat.ui/delete-message
|
||||
|
@ -616,16 +617,6 @@
|
|||
(fn [cofx [_ chat-id message-id status]]
|
||||
(chat.message/update-message-status cofx chat-id message-id status)))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:message/messages-persisted
|
||||
(fn [cofx [_ raw-messages]]
|
||||
(apply fx/merge
|
||||
cofx
|
||||
(map
|
||||
(fn [raw-message]
|
||||
(chat.message/confirm-message-processed raw-message))
|
||||
raw-messages))))
|
||||
|
||||
;; signal module
|
||||
|
||||
(handlers/register-handler-fx
|
||||
|
@ -1204,13 +1195,20 @@
|
|||
(fn [{:keys [db] :as cofx} [_ err]]
|
||||
(log/error :send-status-message-error err)))
|
||||
|
||||
(fx/defn handle-update [cofx {:keys [chats messages] :as response}]
|
||||
(let [chats (map data-store.chats/<-rpc chats)
|
||||
messages (map data-store.messages/<-rpc messages)
|
||||
message-fxs (map chat.message/receive-one messages)
|
||||
chat-fxs (map #(chat/ensure-chat (dissoc % :unviewed-messages-count)) chats)]
|
||||
(apply fx/merge cofx (concat chat-fxs message-fxs))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:transport/message-sent
|
||||
(fn [cofx [_ chat-id message message-type message-id messages-count]]
|
||||
(fx/merge cofx
|
||||
(when message (chat.message/add-message-with-id (assoc message :message-id message-id) chat-id))
|
||||
|
||||
(transport.message/set-message-envelope-hash chat-id message-id message-type messages-count))))
|
||||
(fn [cofx [_ response messages-count]]
|
||||
(let [{:keys [localChatId id messageType]} (-> response :messages first)]
|
||||
(fx/merge cofx
|
||||
(handle-update response)
|
||||
(transport.message/set-message-envelope-hash localChatId id messageType messages-count)))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
:transport/contact-message-sent
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[clojure.string :as string]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.chat.models.message-content :as message-content]
|
||||
[status-im.multiaccounts.core :as multiaccounts]
|
||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
|
@ -141,7 +142,7 @@
|
|||
:success-event [:transport/message-sent
|
||||
chat-id
|
||||
(:message cofx)
|
||||
:group-user-message]
|
||||
constants/message-type-private-group]
|
||||
:payload payload}}))))
|
||||
|
||||
(fx/defn handle-membership-update-received
|
||||
|
@ -374,7 +375,7 @@
|
|||
(let [get-contact (partial models.contact/build-contact cofx)
|
||||
format-message (fn [contact text clock-value]
|
||||
{:chat-id chat-id
|
||||
:content {:text text}
|
||||
:text text
|
||||
:clock-value clock-value
|
||||
:from (:public-key contact)})
|
||||
creator-contact (when creator (get-contact creator))
|
||||
|
@ -465,43 +466,6 @@
|
|||
(transport.filters/upsert-group-chat-topics)
|
||||
(transport.filters/load-members members)))))
|
||||
|
||||
(fx/defn prepared-message
|
||||
{:events [::prepared-message]}
|
||||
[{:keys [now] :as cofx}
|
||||
chat-id message
|
||||
content
|
||||
sender-signature
|
||||
whisper-timestamp
|
||||
metadata]
|
||||
(let [message-with-content
|
||||
(update message :content
|
||||
assoc
|
||||
:parsed-text (:parsedText content)
|
||||
:line-count (:lineCount content)
|
||||
:should-collapse? (message-content/should-collapse?
|
||||
(:text content)
|
||||
(:lineCount content))
|
||||
:rtl? (:rtl content))]
|
||||
(protocol/receive message-with-content
|
||||
chat-id
|
||||
sender-signature
|
||||
whisper-timestamp
|
||||
(assoc cofx :metadata metadata))))
|
||||
|
||||
(fx/defn prepare-message-content
|
||||
[cofx chat-id message sender-signature whisper-timestamp metadata]
|
||||
{::json-rpc/call
|
||||
[{:method "shhext_prepareContent"
|
||||
:params [(:content message)]
|
||||
:on-success #(re-frame/dispatch [::prepared-message
|
||||
chat-id
|
||||
message
|
||||
%
|
||||
sender-signature
|
||||
whisper-timestamp
|
||||
metadata])
|
||||
:on-failure #(log/error "failed to prepare content" %)}]})
|
||||
|
||||
(fx/defn handle-membership-update
|
||||
"Upsert chat and receive message if valid"
|
||||
;; Care needs to be taken here as chat-id is not coming from a whisper filter
|
||||
|
@ -532,18 +496,7 @@
|
|||
:contacts (:contacts new-group)})
|
||||
(add-system-messages chat-id previous-chat new-group)
|
||||
|
||||
(set-up-filter chat-id previous-chat)
|
||||
#(when (and message
|
||||
;; don't allow anything but group messages
|
||||
(instance? protocol/Message message)
|
||||
(= :group-user-message (:message-type message)))
|
||||
(prepare-message-content
|
||||
%
|
||||
chat-id
|
||||
message
|
||||
sender-signature
|
||||
whisper-timestamp
|
||||
metadata)))))))
|
||||
(set-up-filter chat-id previous-chat))))))
|
||||
|
||||
(defn handle-sign-success
|
||||
"Upsert chat and send signed payload to group members"
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[status-im.multiaccounts.update.core :as multiaccounts.update]
|
||||
[status-im.native-module.core :as status]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.ui.screens.mobile-network-settings.utils
|
||||
:as
|
||||
mobile-network-utils]
|
||||
[status-im.ui.screens.navigation :as navigation]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.utils.platform :as platform]
|
||||
|
@ -43,6 +43,14 @@
|
|||
(defn connected? [db id]
|
||||
(= (:mailserver/current-id db) id))
|
||||
|
||||
(def whisper-opts
|
||||
{;; time drift that is tolerated by whisper, in seconds
|
||||
:whisper-drift-tolerance 10
|
||||
;; ttl of 10 sec
|
||||
:ttl 10
|
||||
:powTarget config/pow-target
|
||||
:powTime config/pow-time})
|
||||
|
||||
(defn fetch [db id]
|
||||
(get-in db [:mailserver/mailservers (node/current-fleet-key db) id]))
|
||||
|
||||
|
@ -297,8 +305,8 @@
|
|||
|
||||
(defn adjust-request-for-transit-time
|
||||
[from]
|
||||
(let [ttl (:ttl protocol/whisper-opts)
|
||||
whisper-tolerance (:whisper-drift-tolerance protocol/whisper-opts)
|
||||
(let [ttl (:ttl whisper-opts)
|
||||
whisper-tolerance (:whisper-drift-tolerance whisper-opts)
|
||||
adjustment (+ whisper-tolerance ttl)
|
||||
adjusted-from (- (max from adjustment) adjustment)]
|
||||
(log/debug "Adjusting mailserver request" "from:" from
|
||||
|
|
|
@ -115,8 +115,11 @@
|
|||
"return all the topics for this chat, including discovery topics if specified"
|
||||
[topics chat-id include-discovery?]
|
||||
(reduce-kv
|
||||
(fn [acc topic {:keys [discovery? chat-ids]}]
|
||||
(if (or (and discovery?
|
||||
(fn [acc topic {:keys [negotiated?
|
||||
discovery?
|
||||
chat-ids]}]
|
||||
(if (or (and (or discovery?
|
||||
negotiated?)
|
||||
include-discovery?)
|
||||
(chat-ids chat-id))
|
||||
(conj acc topic)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
[status-im.chat.models :as models.chat]
|
||||
[status-im.contact.core :as contact]
|
||||
[status-im.contact.db :as contact.db]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.i18n :as i18n]
|
||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
|
@ -70,10 +71,6 @@
|
|||
device-type utils.platform/os]
|
||||
(protocol/send (transport.pairing/PairInstallation. installation-id device-type installation-name nil) nil cofx)))
|
||||
|
||||
(fx/defn confirm-message-processed
|
||||
[cofx confirmation]
|
||||
{:transport/confirm-messages-processed [confirmation]})
|
||||
|
||||
(defn send-pair-installation
|
||||
[cofx payload]
|
||||
(let [current-public-key (multiaccounts.model/current-public-key cofx)]
|
||||
|
@ -321,8 +318,8 @@
|
|||
(defn handle-sync-installation
|
||||
[{:keys [db] :as cofx} {:keys [contacts account chat]} sender]
|
||||
(let [confirmation (:metadata cofx)]
|
||||
(if (= sender (multiaccounts.model/current-public-key cofx))
|
||||
(let [on-success #(re-frame/dispatch [:message/messages-persisted [confirmation]])
|
||||
(when (= sender (multiaccounts.model/current-public-key cofx))
|
||||
(let [on-success #(log/debug "handled sync installation successfully")
|
||||
new-contacts (when (seq contacts)
|
||||
(vals (merge-contacts (:contacts/contacts db)
|
||||
((comp ensure-photo-path
|
||||
|
@ -339,17 +336,15 @@
|
|||
:on-success on-success}]}
|
||||
#(when (:public? chat)
|
||||
(models.chat/start-public-chat % (:chat-id chat) {:dont-navigate? true}))]
|
||||
contacts-fx)))
|
||||
(confirm-message-processed cofx confirmation))))
|
||||
contacts-fx))))))
|
||||
|
||||
(defn handle-pair-installation
|
||||
[{:keys [db] :as cofx} {:keys [name installation-id
|
||||
device-type]} timestamp sender]
|
||||
(if (and (= sender (multiaccounts.model/current-public-key cofx))
|
||||
(not= (get-in db [:multiaccount :installation-id]) installation-id))
|
||||
(when (and (= sender (multiaccounts.model/current-public-key cofx))
|
||||
(not= (get-in db [:multiaccount :installation-id]) installation-id))
|
||||
{:pairing/set-installation-metadata [[installation-id {:name name
|
||||
:deviceType device-type}]]}
|
||||
(confirm-message-processed cofx (:metadata cofx))))
|
||||
:deviceType device-type}]]}))
|
||||
|
||||
(fx/defn update-installation [{:keys [db]} installation-id metadata]
|
||||
{:db (update-in db [:pairing/installations installation-id]
|
||||
|
|
|
@ -62,6 +62,6 @@
|
|||
"subscriptions.data" (ethereum.subscriptions/handle-signal cofx (js->clj event-js :keywordize-keys true))
|
||||
"subscriptions.error" (ethereum.subscriptions/handle-error cofx (js->clj event-js :keywordize-keys true))
|
||||
"whisper.filter.added" (transport.filters/handle-negotiated-filter cofx (js->clj event-js :keywordize-keys true))
|
||||
"messages.new" (transport.message/receive-messages cofx event-js)
|
||||
"messages.new" (transport.message/process-response cofx event-js)
|
||||
"wallet" (ethereum.subscriptions/new-wallet-event cofx (js->clj event-js :keywordize-keys true))
|
||||
(log/debug "Event " type " not handled"))))
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
(spec/def ::content-type #{constants/content-type-text
|
||||
constants/content-type-emoji
|
||||
constants/content-type-sticker})
|
||||
(spec/def ::message-type #{:group-user-message :public-group-user-message :user-message})
|
||||
(spec/def ::message-type #{constants/message-type-private-group constants/message-type-public-group constants/message-type-one-to-one})
|
||||
(spec/def ::clock-value (spec/and pos-int?
|
||||
utils.clocks/safe-timestamp?))
|
||||
(spec/def ::timestamp (spec/nilable pos-int?))
|
||||
|
|
|
@ -238,7 +238,7 @@
|
|||
(fx/defn handle-negotiated-filter
|
||||
"Check if it's a new filter, if so create an shh filter and process it"
|
||||
[{:keys [db] :as cofx} {:keys [filters]}]
|
||||
(let [processed-filters (map responses->filters filters)
|
||||
(let [processed-filters (map #(responses->filters (assoc % :negotiated true)) filters)
|
||||
new-filters (filter
|
||||
(partial not-loaded? db)
|
||||
processed-filters)]
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
(:require [goog.object :as o]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.chat.models.message :as models.message]
|
||||
[status-im.chat.models :as models.chat]
|
||||
[status-im.data-store.messages :as data-store.messages]
|
||||
[status-im.data-store.chats :as data-store.chats]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.handlers :as handlers]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
|
@ -12,77 +16,34 @@
|
|||
[status-im.transport.message.transit :as transit]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.tribute-to-talk.whitelist :as whitelist]
|
||||
[status-im.ens.core :as ens]
|
||||
[cljs-bean.core :as clj-bean]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]))
|
||||
|
||||
(def message-type-message 1)
|
||||
|
||||
(defn build-content [content-js]
|
||||
{:text (.-text content-js)
|
||||
:line-count (.-lineCount content-js)
|
||||
:parsed-text (clj-bean/->clj (.-parsedText content-js))
|
||||
:name (.-name content-js)
|
||||
:rtl? (.-rtl content-js)
|
||||
:response-to (aget content-js "response-to")
|
||||
:chat-id (.-chat_id content-js)})
|
||||
|
||||
(defn build-message [parsed-message-js]
|
||||
(let [content (.-content parsed-message-js)
|
||||
built-message
|
||||
(protocol/Message.
|
||||
(build-content content)
|
||||
(.-content_type parsed-message-js)
|
||||
(keyword (.-message_type parsed-message-js))
|
||||
(.-clock parsed-message-js)
|
||||
(.-timestamp parsed-message-js))]
|
||||
built-message))
|
||||
|
||||
(defn handle-message
|
||||
"Check if parsedMessage is present and of a supported type, if so
|
||||
build a record using the right type. Otherwise defaults to transit
|
||||
deserializing"
|
||||
[message-js]
|
||||
(if (and (.-parsedMessage message-js)
|
||||
(= message-type-message (.-messageType message-js)))
|
||||
(build-message (.-parsedMessage message-js))
|
||||
(transit/deserialize (.-payload message-js))))
|
||||
|
||||
(fx/defn receive-message
|
||||
(fx/defn handle-raw-message
|
||||
"Receive message handles a new status-message.
|
||||
dedup-id is passed by status-go and is used to deduplicate messages at that layer.
|
||||
Once a message has been successfuly processed, that id needs to be sent back
|
||||
in order to stop receiving that message"
|
||||
[{:keys [db] :as cofx} now-in-s filter-chat-id message-js]
|
||||
(let [blocked-contacts (get db :contacts/blocked #{})
|
||||
timestamp (.-timestamp (.-message message-js))
|
||||
metadata-js (.-metadata message-js)
|
||||
metadata {:author {:publicKey (.-publicKey (.-author metadata-js))
|
||||
:alias (.-alias (.-author metadata-js))
|
||||
:identicon (.-identicon (.-author metadata-js))}
|
||||
:dedupId (.-dedupId metadata-js)
|
||||
:encryptionId (.-encryptionId metadata-js)
|
||||
:messageId (.-messageId metadata-js)}
|
||||
status-message (handle-message message-js)
|
||||
sig (-> metadata :author :publicKey)]
|
||||
(when (and sig
|
||||
status-message
|
||||
(not (blocked-contacts sig)))
|
||||
(try
|
||||
(when-let [valid-message (protocol/validate status-message)]
|
||||
(protocol/receive
|
||||
(assoc valid-message
|
||||
:metadata metadata)
|
||||
(or
|
||||
filter-chat-id
|
||||
(get-in valid-message [:content :chat-id])
|
||||
sig)
|
||||
sig
|
||||
timestamp
|
||||
(assoc cofx :metadata metadata)))
|
||||
(catch :default e nil))))) ; ignore unknown message types
|
||||
[{:keys [db] :as cofx} raw-message-js]
|
||||
(let [timestamp (.-timestamp raw-message-js)
|
||||
sig (.-from raw-message-js)
|
||||
payload (.-payload raw-message-js)]
|
||||
(let [status-message (transit/deserialize payload)]
|
||||
(when (and sig
|
||||
status-message)
|
||||
(try
|
||||
(when-let [valid-message (protocol/validate status-message)]
|
||||
(protocol/receive
|
||||
valid-message
|
||||
sig
|
||||
sig
|
||||
timestamp
|
||||
cofx))
|
||||
(catch :default e nil)))))) ; ignore unknown message types
|
||||
|
||||
(defn- js-obj->seq [obj]
|
||||
;; Sometimes the filter will return a single object instead of a collection
|
||||
|
@ -91,42 +52,48 @@
|
|||
(aget obj i))
|
||||
[obj]))
|
||||
|
||||
(fx/defn handle-chat [cofx chat]
|
||||
;; :unviewed-messages-count is managed by status-react, so we don't copy
|
||||
;; over it
|
||||
(models.chat/ensure-chat cofx (dissoc chat :unviewed-messages-count)))
|
||||
|
||||
(fx/defn handle-message-2 [cofx message]
|
||||
(fx/merge cofx
|
||||
(models.message/receive-one message)
|
||||
(ens/verify-names-from-message message (:from message))))
|
||||
|
||||
(fx/defn process-response [cofx response-js]
|
||||
(let [chats (.-chats response-js)
|
||||
raw-messages (.-rawMessages response-js)
|
||||
messages (.-messages response-js)]
|
||||
(cond
|
||||
(seq chats)
|
||||
(let [chat (.pop chats)]
|
||||
(fx/merge cofx
|
||||
{:dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
|
||||
(handle-chat (-> chat (clj-bean/->clj) (data-store.chats/<-rpc)))))
|
||||
(seq raw-messages)
|
||||
(let [first-filter (aget raw-messages 0)
|
||||
messages (.-messages first-filter)
|
||||
first-message (.pop messages)]
|
||||
;; Pop the empty array
|
||||
(when (= (.-length messages) 0)
|
||||
(.pop raw-messages))
|
||||
(when first-message
|
||||
(fx/merge cofx
|
||||
{:dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
|
||||
(handle-raw-message first-message))))
|
||||
|
||||
(seq messages)
|
||||
(let [message (.pop messages)]
|
||||
(fx/merge cofx
|
||||
{:dispatch-later [{:ms 20 :dispatch [::process response-js]}]}
|
||||
(handle-message-2 (-> message (clj-bean/->clj) (data-store.messages/<-rpc))))))))
|
||||
|
||||
(handlers/register-handler-fx
|
||||
::process
|
||||
(fn [cofx [_ messages now-in-s]]
|
||||
(let [[chat-id message] (first messages)
|
||||
remaining-messages (rest messages)]
|
||||
(if (seq remaining-messages)
|
||||
(assoc
|
||||
(receive-message cofx now-in-s chat-id message)
|
||||
;; We dispatch later to let the UI thread handle events, without this
|
||||
;; it will keep processing events ignoring user input.
|
||||
:dispatch-later [{:ms 20 :dispatch [::process remaining-messages now-in-s]}])
|
||||
(receive-message cofx now-in-s chat-id message)))))
|
||||
|
||||
(fx/defn receive-messages
|
||||
"Initialize the ::process event, which will process messages one by one
|
||||
dispatching later to itself"
|
||||
[{:keys [now] :as cofx} event-js]
|
||||
(let [now-in-s (quot now 1000)
|
||||
events (reduce
|
||||
(fn [acc message-specs]
|
||||
(let [chat (.-chat message-specs)
|
||||
messages (.-messages message-specs)
|
||||
error (.-error message-specs)
|
||||
chat-id (if (or (.-discovery chat)
|
||||
(.-negotiated chat))
|
||||
nil
|
||||
(.-chatId chat))]
|
||||
(if (seq messages)
|
||||
(reduce (fn [acc m]
|
||||
(conj acc [chat-id m]))
|
||||
acc
|
||||
messages)
|
||||
acc)))
|
||||
[]
|
||||
(.-messages event-js))]
|
||||
{:dispatch [::process events now-in-s]}))
|
||||
(fn [cofx [_ response-js]]
|
||||
(process-response cofx response-js)))
|
||||
|
||||
(fx/defn remove-hash
|
||||
[{:keys [db] :as cofx} envelope-hash]
|
||||
|
@ -192,16 +159,3 @@
|
|||
{:name name
|
||||
:profile-image photo-path
|
||||
:address address}))
|
||||
|
||||
(fx/defn resend-contact-request [cofx own-info chat-id {:keys [sym-key topic]}]
|
||||
(protocol/send (contact/map->ContactRequest own-info)
|
||||
chat-id cofx))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:transport/confirm-messages-processed
|
||||
(fn [confirmations]
|
||||
(when (seq confirmations)
|
||||
(json-rpc/call {:method "shhext_confirmMessagesProcessedByID"
|
||||
:params [confirmations]
|
||||
:on-success #(log/debug "successfully confirmed messages")
|
||||
:on-failure #(log/error "failed to confirm messages" %)}))))
|
||||
|
|
|
@ -2,32 +2,24 @@
|
|||
status-im.transport.message.protocol
|
||||
(:require [cljs.spec.alpha :as spec]
|
||||
[status-im.multiaccounts.model :as multiaccounts.model]
|
||||
[re-frame.core :as re-frame]
|
||||
[status-im.data-store.messages :as data-store.messages]
|
||||
[status-im.ethereum.json-rpc :as json-rpc]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.transport.db :as transport.db]
|
||||
[status-im.utils.pairing :as pairing.utils]
|
||||
[status-im.transport.utils :as transport.utils]
|
||||
[status-im.tribute-to-talk.whitelist :as whitelist]
|
||||
[status-im.utils.config :as config]
|
||||
[status-im.utils.fx :as fx]
|
||||
[taoensso.timbre :as log]))
|
||||
|
||||
(defn discovery-topic-hash [] (transport.utils/get-topic constants/contact-discovery))
|
||||
|
||||
(defprotocol StatusMessage
|
||||
"Protocol for the messages that are sent through the transport layer"
|
||||
(send [this chat-id cofx] "Method producing all effects necessary for sending the message record")
|
||||
(receive [this chat-id signature timestamp cofx] "Method producing all effects necessary for receiving the message record")
|
||||
(validate [this] "Method returning the message if it is valid or nil if it is not"))
|
||||
|
||||
(def whisper-opts
|
||||
{;; time drift that is tolerated by whisper, in seconds
|
||||
:whisper-drift-tolerance 10
|
||||
;; ttl of 10 sec
|
||||
:ttl 10
|
||||
:powTarget config/pow-target
|
||||
:powTime config/pow-time})
|
||||
|
||||
(defn send-public-message
|
||||
"Sends the payload to topic"
|
||||
[cofx chat-id success-event payload]
|
||||
|
@ -52,24 +44,28 @@
|
|||
success-event
|
||||
payload))
|
||||
|
||||
(fx/defn send-chat-message [_ {:keys [chat-id
|
||||
text
|
||||
response-to
|
||||
ens-name
|
||||
message-type
|
||||
sticker
|
||||
content-type]
|
||||
:as message}]
|
||||
{::json-rpc/call [{:method "shhext_sendChatMessage"
|
||||
:params [{:chatId chat-id
|
||||
:text text
|
||||
:responseTo response-to
|
||||
:ensName ens-name
|
||||
:sticker sticker
|
||||
:contentType content-type}]
|
||||
:on-success
|
||||
#(re-frame/dispatch [:transport/message-sent % 1])
|
||||
:on-failure #(log/error "failed to send a message" %)}]})
|
||||
|
||||
(defrecord Message [content content-type message-type clock-value timestamp]
|
||||
StatusMessage
|
||||
(send [this chat-id {:keys [message] :as cofx}]
|
||||
(let [current-public-key (multiaccounts.model/current-public-key cofx)
|
||||
params {:chat-id chat-id
|
||||
:payload this
|
||||
:success-event [:transport/message-sent
|
||||
chat-id
|
||||
message
|
||||
message-type]}]
|
||||
(case message-type
|
||||
:public-group-user-message
|
||||
(send-public-message cofx chat-id (:success-event params) this)
|
||||
:user-message
|
||||
(fx/merge cofx
|
||||
(when (pairing.utils/has-paired-installations? cofx)
|
||||
(send-direct-message current-public-key nil this))
|
||||
(send-with-pubkey params)))))
|
||||
(send [this chat-id {:keys [message] :as cofx}])
|
||||
(validate [this]
|
||||
(if (spec/valid? :message/message this)
|
||||
this
|
||||
|
|
|
@ -4,17 +4,6 @@
|
|||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.js-dependencies :as dependencies]))
|
||||
|
||||
(defn system-message-id
|
||||
[{:keys [from chat-id clock-value]}]
|
||||
(ethereum/sha3 (str from chat-id clock-value)))
|
||||
|
||||
(defn message-id
|
||||
"Get a message-id by appending the hex-encoded pk of the sender to the raw-payload.
|
||||
We strip 0x from the payload so web3 understand that the whole thing is to be
|
||||
decoded as raw bytes"
|
||||
[from raw-payload]
|
||||
(ethereum/sha3 (str from (subs raw-payload 2))))
|
||||
|
||||
(defn get-topic
|
||||
"Get the topic of a group chat or public chat from the chat-id"
|
||||
[chat-id]
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.tribute-to-talk.whitelist
|
||||
(:require [status-im.contact.db :as contact.db]
|
||||
[status-im.data-store.contacts :as contacts-store]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.tribute-to-talk.db :as tribute-to-talk.db]
|
||||
[status-im.utils.fx :as fx]))
|
||||
|
||||
|
@ -61,7 +62,7 @@
|
|||
along the message"
|
||||
[{:keys [db] :as cofx} received-message-fx message-type tribute-transaction from]
|
||||
;; if it is not a user-message or the user is whitelisted it passes
|
||||
(if (or (not= :user-message message-type)
|
||||
(if (or (not= constants/message-type-one-to-one message-type)
|
||||
(contains? (:contacts/whitelist db) from))
|
||||
received-message-fx
|
||||
;; if ttt is disabled it passes
|
||||
|
|
|
@ -52,11 +52,6 @@
|
|||
:number-of-lines 5}
|
||||
(or text (:text quote))]])))
|
||||
|
||||
(defview message-content-status [{:keys [content]}]
|
||||
[react/view style/status-container
|
||||
[react/text {:style style/status-text}
|
||||
(:text content)]])
|
||||
|
||||
(defn expand-button [expanded? chat-id message-id]
|
||||
[react/text {:style style/message-expand-button
|
||||
:on-press #(re-frame/dispatch [:chat.ui/message-expand-toggled chat-id message-id])}
|
||||
|
@ -103,6 +98,14 @@
|
|||
|
||||
(conj acc literal)))
|
||||
|
||||
(defview message-content-status [{:keys [content]}]
|
||||
[react/view style/status-container
|
||||
[react/text {:style style/status-text}
|
||||
(reduce
|
||||
(fn [acc e] (render-inline (:text content) false acc e))
|
||||
[react/text-class {:style style/status-text}]
|
||||
(-> content :parsed-text peek :children))]])
|
||||
|
||||
(defn render-block [{:keys [chat-id message-id content
|
||||
timestamp-str group-chat outgoing
|
||||
current-public-key expanded?] :as message}
|
||||
|
@ -184,7 +187,7 @@
|
|||
[wrapper {:keys [content] :as message}]
|
||||
[wrapper message
|
||||
[react/image {:style {:margin 10 :width 140 :height 140}
|
||||
:source {:uri (contenthash/url (:hash content))}}]])
|
||||
:source {:uri (contenthash/url (-> content :sticker :hash))}}]])
|
||||
|
||||
(defmethod message-content :default
|
||||
[wrapper {:keys [content-type] :as message}]
|
||||
|
@ -220,7 +223,7 @@
|
|||
[{:keys [chat-id message-id outgoing-status
|
||||
first-outgoing?
|
||||
content message-type] :as message}]
|
||||
(when (not= :system-message message-type)
|
||||
(when (not= constants/message-type-private-group-system-message message-type)
|
||||
(case outgoing-status
|
||||
:sending [message-activity-indicator]
|
||||
:not-sent [message-not-sent-text chat-id message-id]
|
||||
|
@ -267,25 +270,26 @@
|
|||
|
||||
(defn chat-message
|
||||
[{:keys [outgoing group-chat modal? current-public-key content-type content] :as message}]
|
||||
[react/view
|
||||
[react/touchable-highlight
|
||||
{:on-press (fn [arg]
|
||||
(if (and platform/desktop? (= "right" (.-button (.-nativeEvent arg))))
|
||||
(open-chat-context-menu message)
|
||||
(do
|
||||
(when (and (= content-type constants/content-type-sticker) (:pack content))
|
||||
(re-frame/dispatch [:stickers/open-sticker-pack (:pack content)]))
|
||||
(re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true
|
||||
:input-bottom-sheet nil}])
|
||||
(when-not platform/desktop?
|
||||
(react/dismiss-keyboard!)))))
|
||||
:on-long-press #(when (or (= content-type constants/content-type-text)
|
||||
(= content-type constants/content-type-emoji))
|
||||
(open-chat-context-menu message))}
|
||||
[react/view {:accessibility-label :chat-item}
|
||||
(let [incoming-group (and group-chat (not outgoing))]
|
||||
[message-content message-body (merge message
|
||||
{:current-public-key current-public-key
|
||||
:group-chat group-chat
|
||||
:modal? modal?
|
||||
:incoming-group incoming-group})])]]])
|
||||
(let [sticker (:sticker content)]
|
||||
[react/view
|
||||
[react/touchable-highlight
|
||||
{:on-press (fn [arg]
|
||||
(if (and platform/desktop? (= "right" (.-button (.-nativeEvent arg))))
|
||||
(open-chat-context-menu message)
|
||||
(do
|
||||
(when (and (= content-type constants/content-type-sticker) (:pack sticker))
|
||||
(re-frame/dispatch [:stickers/open-sticker-pack (:pack sticker)]))
|
||||
(re-frame/dispatch [:chat.ui/set-chat-ui-props {:messages-focused? true
|
||||
:input-bottom-sheet nil}])
|
||||
(when-not platform/desktop?
|
||||
(react/dismiss-keyboard!)))))
|
||||
:on-long-press #(when (or (= content-type constants/content-type-text)
|
||||
(= content-type constants/content-type-emoji))
|
||||
(open-chat-context-menu message))}
|
||||
[react/view {:accessibility-label :chat-item}
|
||||
(let [incoming-group (and group-chat (not outgoing))]
|
||||
[message-content message-body (merge message
|
||||
{:current-public-key current-public-key
|
||||
:group-chat group-chat
|
||||
:modal? modal?
|
||||
:incoming-group incoming-group})])]]]))
|
||||
|
|
|
@ -20,16 +20,13 @@
|
|||
[{:keys [chat-id name group-chat
|
||||
color public? public-key
|
||||
timestamp chat-name
|
||||
last-message-content
|
||||
last-message-timestamp
|
||||
last-message-content-type]
|
||||
last-message]
|
||||
:as chat-item}]
|
||||
(views/letsubs [photo-path [:contacts/chat-photo chat-id]
|
||||
unviewed-messages-count [:chats/unviewed-messages-count chat-id]
|
||||
current-chat-id [:chats/current-chat-id]]
|
||||
(let [last-message {:content last-message-content
|
||||
:timestamp (if (pos? last-message-timestamp) last-message-timestamp timestamp)
|
||||
:content-type last-message-content-type}
|
||||
(let [last-message (or last-message
|
||||
{:timestamp timestamp})
|
||||
name (or chat-name
|
||||
(gfycat/generate-gfy public-key))
|
||||
[unviewed-messages-label large?] [(utils/unread-messages-count unviewed-messages-count) true]
|
||||
|
@ -60,7 +57,7 @@
|
|||
[react/text {:ellipsize-mode :tail
|
||||
:number-of-lines 1
|
||||
:style styles/chat-last-message}
|
||||
(or (:text last-message-content)
|
||||
(or (:text last-message)
|
||||
(i18n/label :no-messages-yet))]))]
|
||||
[react/view {:style styles/timestamp}
|
||||
[chat-item/message-timestamp (:timestamp last-message)]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[reagent.core :as reagent]
|
||||
[status-im.ens.core :as ens]
|
||||
[status-im.ethereum.core :as ethereum]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.ethereum.ens :as ethereum.ens]
|
||||
[status-im.ethereum.stateofus :as stateofus]
|
||||
[status-im.i18n :as i18n]
|
||||
|
@ -649,7 +650,7 @@
|
|||
:action-fn #(re-frame/dispatch [::ens/switch-show-username])
|
||||
:value show?}]]
|
||||
(let [message {:content {:parsed-text [{:type "paragraph", :children [{:literal (i18n/label :t/ens-test-message)}]}]}
|
||||
:content-type "text/plain"
|
||||
:content-type constants/content-type-text
|
||||
:timestamp-str "9:41 AM"}]
|
||||
[react/view
|
||||
[react/view {:padding-left 60}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
|
||||
(= constants/content-type-sticker content-type)
|
||||
[react/image {:style {:margin 1 :width 20 :height 20}
|
||||
:source {:uri (contenthash/url (:hash content))}}]
|
||||
:source {:uri (contenthash/url (-> content :sticker :hash))}}]
|
||||
|
||||
(string/blank? (:text content))
|
||||
[react/text {:style styles/last-message-text}
|
||||
|
@ -36,14 +36,7 @@
|
|||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label :chat-message-text}
|
||||
(string/trim-newline (:text content))]
|
||||
|
||||
:else
|
||||
[react/text {:style styles/last-message-text
|
||||
:number-of-lines 1
|
||||
:ellipsize-mode :tail
|
||||
:accessibility-label :chat-message-text}
|
||||
content])])
|
||||
(string/trim-newline (:text content))])])
|
||||
|
||||
(defn message-timestamp [timestamp]
|
||||
(when timestamp
|
||||
|
@ -61,10 +54,8 @@
|
|||
[chat-id chat-name
|
||||
color online group-chat
|
||||
public? contact
|
||||
last-message-timestamp
|
||||
timestamp
|
||||
last-message-content
|
||||
last-message-content-type]} home-item
|
||||
last-message]} home-item
|
||||
private-group? (and group-chat (not public?))
|
||||
public-group? (and group-chat public?)
|
||||
truncated-chat-name (utils/truncate-str chat-name 30)
|
||||
|
@ -81,14 +72,14 @@
|
|||
:else nil)
|
||||
:title truncated-chat-name
|
||||
:title-accessibility-label :chat-name-text
|
||||
:title-row-accessory [message-timestamp (if (pos? last-message-timestamp)
|
||||
last-message-timestamp
|
||||
:title-row-accessory [message-timestamp (if (pos? (:whisper-timestamp last-message))
|
||||
(:whisper-timestamp last-message)
|
||||
timestamp)]
|
||||
:subtitle
|
||||
(let [{:keys [tribute-status tribute-label]} (:tribute-to-talk contact)]
|
||||
(if (not (#{:require :pending} tribute-status))
|
||||
[message-content-text {:content last-message-content
|
||||
:content-type last-message-content-type}]
|
||||
[message-content-text {:content (:content last-message)
|
||||
:content-type (:content-type last-message)}]
|
||||
tribute-label))
|
||||
:subtitle-row-accessory [unviewed-indicator chat-id]
|
||||
:on-press #(do
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
;;
|
||||
;; But what we can do, is to use our time to make a "bid", hoping that it will
|
||||
;; beat the current chat-timestamp. So our Lamport timestamp format is:
|
||||
;; {unix-timestamp-ms}{2-digits-post-id}
|
||||
;; {unix-timestamp-ms}
|
||||
;;
|
||||
;; We always need to make sure we take the max value between the last-clock-value
|
||||
;; for the chat and the bid-timestamp.
|
||||
|
@ -70,13 +70,12 @@
|
|||
;; http://amturing.acm.org/p558-lamport.pdf
|
||||
|
||||
(def one-month-in-ms (* 60 60 24 31 1000))
|
||||
(def post-id-digits 100)
|
||||
|
||||
(defn- ->timestamp-bid []
|
||||
(* (utils.datetime/timestamp) post-id-digits))
|
||||
(utils.datetime/timestamp))
|
||||
|
||||
(defn max-timestamp []
|
||||
(* (+ one-month-in-ms (utils.datetime/timestamp)) post-id-digits))
|
||||
(+ one-month-in-ms (utils.datetime/timestamp)))
|
||||
; The timestamp has an upper limit of Number.MAX_SAFE_INTEGER
|
||||
; A malicious client could send a crafted message with timestamp = Number.MAX_SAFE_INTEGER
|
||||
; which effectively would DoS the chat, as any new message would get
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
cofx))
|
||||
|
||||
(def ^:private mergeable-keys
|
||||
#{:dispatch-debounce
|
||||
:filters/load-filters
|
||||
#{:filters/load-filters
|
||||
:pairing/set-installation-metadata
|
||||
:status-im.data-store.messages/save-message
|
||||
:status-im.ens.core/verify-names
|
||||
:shh/send-direct-message
|
||||
:shh/remove-filter
|
||||
|
|
|
@ -88,31 +88,6 @@
|
|||
(when address
|
||||
(get-shortened-address (eip55/address->checksum (ethereum/normalized-hex address)))))
|
||||
|
||||
;; debounce, taken from https://github.com/johnswanson/re-frame-debounce-fx
|
||||
; {:dispatch-debounce {:key :search
|
||||
; :event [:search value]
|
||||
; :delay 250}}))
|
||||
|
||||
(def registered-keys (atom nil))
|
||||
|
||||
(defn dispatch-if-not-superceded [{:keys [key delay event time-received]}]
|
||||
(when (= time-received (get @registered-keys key))
|
||||
;; no new events on this key!
|
||||
(re-frame/dispatch event)))
|
||||
|
||||
(defn dispatch-debounced [{:keys [delay] :as debounce}]
|
||||
(js/setTimeout
|
||||
(fn [] (dispatch-if-not-superceded debounce))
|
||||
delay))
|
||||
|
||||
(re-frame/reg-fx
|
||||
:dispatch-debounce
|
||||
(fn dispatch-debounce [debounces]
|
||||
(doseq [debounce debounces]
|
||||
(let [ts (.getTime (js/Date.))]
|
||||
(swap! registered-keys assoc (:key debounce) ts)
|
||||
(dispatch-debounced (assoc debounce :time-received ts))))))
|
||||
|
||||
;; background-timer
|
||||
|
||||
(defn set-timeout [cb ms]
|
||||
|
@ -159,4 +134,4 @@
|
|||
(let [decimal-part (get (string/split (str amount) ".") 1)]
|
||||
(if (> (count decimal-part) places)
|
||||
(gstring/format (str "%." places "f") amount)
|
||||
(or (str amount) 0))))
|
||||
(or (str amount) 0))))
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"_comment": "DO NOT EDIT THIS FILE BY HAND. USE 'scripts/update-status-go.sh <tag>' instead",
|
||||
"owner": "status-im",
|
||||
"repo": "status-go",
|
||||
"version": "v0.35.1",
|
||||
"commit-sha1": "4769fb91c3247c72c21013bf36194843d8d72d18",
|
||||
"src-sha256": "1b6050kvnvf69gqw5llb7gb5v25pq6vbhkf9nznk9ra2spasqqzy"
|
||||
"version": "v0.36.1",
|
||||
"commit-sha1": "fd49b0140ebafdcec35b4da84685bcd8559a7dd9",
|
||||
"src-sha256": "1pqnvmldg93vbmmsvpr24pj87d2vx3cfm7rr9rgwdk469pd1hhhy"
|
||||
}
|
||||
|
|
|
@ -861,13 +861,14 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
|||
self.errors.append('Public chat "%s" doesn\'t appear on other device when devices are paired'
|
||||
% public_chat_before_sync_name)
|
||||
|
||||
device_2_home.element_by_text(group_chat_name).click()
|
||||
device_2_group_chat = device_2_home.get_chat_view()
|
||||
# Disabling for now until GroupMembershipUpdate is also moved to status-go
|
||||
#device_2_home.element_by_text(group_chat_name).click()
|
||||
#device_2_group_chat = device_2_home.get_chat_view()
|
||||
|
||||
if not device_2_group_chat.chat_element_by_text(message_after_sync).is_element_displayed():
|
||||
self.errors.append('"%s" message in group chat is not synced' % message_after_sync)
|
||||
#if not device_2_group_chat.chat_element_by_text(message_after_sync).is_element_displayed():
|
||||
# self.errors.append('"%s" message in group chat is not synced' % message_after_sync)
|
||||
|
||||
device_2_group_chat.get_back_to_home_view()
|
||||
#device_2_group_chat.get_back_to_home_view()
|
||||
device_2_home.profile_button.click()
|
||||
if not device_2_profile.profile_picture.is_element_image_equals_template('sauce_logo_red_profile.png'):
|
||||
self.errors.append('Profile picture was not updated after changing when devices are paired')
|
||||
|
@ -951,4 +952,4 @@ class TestProfileMultipleDevice(MultipleDeviceTestCase):
|
|||
if not profile_2.element_by_text('@' + user_1['ens']).is_element_displayed():
|
||||
self.errors.append('ENS username is not shown in contacts')
|
||||
|
||||
self.errors.verify_no_errors()
|
||||
self.errors.verify_no_errors()
|
||||
|
|
|
@ -5,19 +5,19 @@ from views.sign_in_view import SignInView
|
|||
|
||||
|
||||
def return_left_chat_system_message(username):
|
||||
return "*%s* left the group" % username
|
||||
return "%s left the group" % username
|
||||
|
||||
|
||||
def return_created_chat_system_message(username, chat_name):
|
||||
return "*%s* created the group *%s*" % (username, chat_name)
|
||||
return "%s created the group %s" % (username, chat_name)
|
||||
|
||||
|
||||
def return_joined_chat_system_message(username):
|
||||
return "*%s* has joined the group" % username
|
||||
return "%s has joined the group" % username
|
||||
|
||||
|
||||
def return_made_admin_system_message(username):
|
||||
return "*%s* has been made admin" % username
|
||||
return "%s has been made admin" % username
|
||||
|
||||
|
||||
def create_users(driver_1, driver_2):
|
||||
|
|
|
@ -65,9 +65,7 @@
|
|||
(deftest clear-history-test
|
||||
(let [chat-id "1"
|
||||
cofx {:db {:chats {chat-id {:message-list [{:something "a"}]
|
||||
:messages {"1" {:clock-value 1}
|
||||
"2" {:clock-value 10}
|
||||
"3" {:clock-value 2}}
|
||||
:last-message {:clock-value 10}
|
||||
:unviewed-messages-count 1}}}}]
|
||||
(testing "it deletes all the messages"
|
||||
(let [actual (chat/clear-history cofx chat-id)]
|
||||
|
@ -85,7 +83,7 @@
|
|||
(let [actual (chat/clear-history (update-in cofx
|
||||
[:db :chats chat-id]
|
||||
assoc
|
||||
:messages {}
|
||||
:last-message nil
|
||||
:deleted-at-clock-value 100)
|
||||
chat-id)]
|
||||
(is (= 100 (get-in actual [:db :chats chat-id :deleted-at-clock-value])))))
|
||||
|
@ -94,7 +92,7 @@
|
|||
(let [actual (chat/clear-history (update-in cofx
|
||||
[:db :chats chat-id]
|
||||
assoc
|
||||
:messages {})
|
||||
:last-message nil)
|
||||
chat-id)]
|
||||
(is (= 42 (get-in actual [:db :chats chat-id :deleted-at-clock-value]))))))
|
||||
(testing "it adds the relevant rpc calls"
|
||||
|
@ -104,7 +102,8 @@
|
|||
|
||||
(deftest remove-chat-test
|
||||
(let [chat-id "1"
|
||||
cofx {:db {:chats {chat-id {:messages {"1" {:clock-value 1}
|
||||
cofx {:db {:chats {chat-id {:last-message {:clock-value 10}
|
||||
:messages {"1" {:clock-value 1}
|
||||
"2" {:clock-value 10}
|
||||
"3" {:clock-value 2}}}}}}]
|
||||
(testing "it deletes all the messages"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.utils.identicon :as identicon]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.datetime :as time]
|
||||
[status-im.transport.message.protocol :as protocol]
|
||||
[status-im.chat.models.message-list :as models.message-list]
|
||||
|
@ -49,51 +50,17 @@
|
|||
(testing "a message coming from you!"
|
||||
(let [actual (message/receive-one {:db db}
|
||||
{:from "me"
|
||||
:message-type :user-message
|
||||
:message-type constants/message-type-one-to-one
|
||||
:timestamp 0
|
||||
:whisper-timestamp 0
|
||||
:message-id "id"
|
||||
:chat-id "chat-id"
|
||||
:outgoing true
|
||||
:content "b"
|
||||
:clock-value 1})
|
||||
message (get-in actual [:db :chats "chat-id" :messages "id"])]
|
||||
(testing "it adds the message"
|
||||
(is message))
|
||||
(testing "it marks the message as outgoing"
|
||||
(is (= true (:outgoing message))))))))
|
||||
|
||||
(deftest receive-one-clock-value
|
||||
(let [db {:multiaccount {:public-key "me"}
|
||||
:view-id :chat
|
||||
:current-chat-id "chat-id"
|
||||
:chats {"chat-id" {:last-clock-value 10
|
||||
:messages {}}}}]
|
||||
(testing "a message with a higher clock value"
|
||||
(let [actual (message/receive-one {:db db}
|
||||
{:from "chat-id"
|
||||
:message-type :user-message
|
||||
:timestamp 0
|
||||
:whisper-timestamp 0
|
||||
:message-id "id"
|
||||
:chat-id "chat-id"
|
||||
:content "b"
|
||||
:clock-value 12})
|
||||
chat-clock-value (get-in actual [:db :chats "chat-id" :last-clock-value])]
|
||||
(testing "it sets last-clock-value"
|
||||
(is (= 12 chat-clock-value)))))
|
||||
(testing "a message with a lower clock value"
|
||||
(let [actual (message/receive-one {:db db}
|
||||
{:from "chat-id"
|
||||
:message-type :user-message
|
||||
:timestamp 0
|
||||
:whisper-timestamp 0
|
||||
:message-id "id"
|
||||
:chat-id "chat-id"
|
||||
:content "b"
|
||||
:clock-value 2})
|
||||
chat-clock-value (get-in actual [:db :chats "chat-id" :last-clock-value])]
|
||||
(testing "it sets last-clock-value"
|
||||
(is (= 10 chat-clock-value)))))))
|
||||
(is message))))))
|
||||
|
||||
(deftest receive-group-chats
|
||||
(let [cofx {:db {:chats {"chat-id" {:contacts #{"present"}
|
||||
|
@ -104,21 +71,21 @@
|
|||
cofx-without-member (update-in cofx [:db :chats "chat-id" :members-joined] disj "a")
|
||||
valid-message {:chat-id "chat-id"
|
||||
:from "present"
|
||||
:message-type :group-user-message
|
||||
:message-type constants/message-type-private-group
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
:timestamp 0}
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "present"
|
||||
:message-type :group-user-message
|
||||
:message-type constants/message-type-private-group
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
:timestamp 0}
|
||||
bad-from-message {:chat-id "chat-id"
|
||||
:from "not-present"
|
||||
:message-type :group-user-message
|
||||
:message-type constants/message-type-private-group
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
|
@ -139,14 +106,14 @@
|
|||
:view-id :chat}}
|
||||
valid-message {:chat-id "chat-id"
|
||||
:from "anyone"
|
||||
:message-type :public-group-user-message
|
||||
:message-type constants/message-type-public-group
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
:timestamp 0}
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "present"
|
||||
:message-type :public-group-user-message
|
||||
:message-type constants/message-type-public-group
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
|
@ -166,14 +133,14 @@
|
|||
:view-id :chat}}
|
||||
valid-message {:chat-id "matching"
|
||||
:from "matching"
|
||||
:message-type :user-message
|
||||
:message-type constants/message-type-one-to-one
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
:timestamp 0}
|
||||
own-message {:chat-id "matching"
|
||||
:from "me"
|
||||
:message-type :user-message
|
||||
:message-type constants/message-type-one-to-one
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
|
@ -181,7 +148,7 @@
|
|||
|
||||
bad-chat-id-message {:chat-id "bad-chat-id"
|
||||
:from "not-matching"
|
||||
:message-type :user-message
|
||||
:message-type constants/message-type-one-to-one
|
||||
:message-id "1"
|
||||
:clock-value 1
|
||||
:whisper-timestamp 0
|
||||
|
@ -229,38 +196,15 @@
|
|||
:clock-value 0
|
||||
:first-in-group? true
|
||||
:from nil
|
||||
:first-outgoing? nil
|
||||
:outgoing-seen? nil
|
||||
:first-outgoing? false
|
||||
:outgoing-seen? false
|
||||
:timestamp-str "timestamp"
|
||||
:first? true
|
||||
:display-username? true
|
||||
:outgoing nil}]
|
||||
:outgoing false}]
|
||||
(models.message-list/->seq
|
||||
(get-in fx1 [:db :chats "chat-id" :message-list]))))
|
||||
(is (= {}
|
||||
(get-in fx2 [:db :chats "chat-id" :messages])))
|
||||
(is (= nil
|
||||
(get-in fx2 [:db :chats "chat-id" :message-list])))))))
|
||||
|
||||
(deftest add-outgoing-status
|
||||
(testing "coming from us"
|
||||
(testing "system-message"
|
||||
(let [message (message/add-outgoing-status {:message-type :system-message
|
||||
:from "us"} "us")]
|
||||
(is (not (:outgoing message)))
|
||||
(is (not (:outgoing-status message)))))
|
||||
(testing "has already a an outgoing status"
|
||||
(testing "it does not override it"
|
||||
(let [message (message/add-outgoing-status {:outgoing-status :sending
|
||||
:from "us"} "us")]
|
||||
(is (:outgoing message))
|
||||
(is (= :sending (:outgoing-status message))))))
|
||||
(testing "does not have an outgoing status"
|
||||
(testing "it sets it to sent"
|
||||
(let [message (message/add-outgoing-status {:from "us"} "us")]
|
||||
(is (:outgoing message))
|
||||
(is (= :sent (:outgoing-status message)))))))
|
||||
(testing "not coming from us"
|
||||
(let [message (message/add-outgoing-status {:from "not-us"} "us")]
|
||||
(is (not (:outgoing message)))
|
||||
(is (not (:outgoing-status message))))))
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
:is-active true
|
||||
:messages {}
|
||||
:pagination-info {}
|
||||
:last-message-content "content"
|
||||
:last-message-content-type "type"
|
||||
:chat-id "chat-id"
|
||||
:loaded-unviewed-messages-ids []
|
||||
:timestamp 2
|
||||
|
@ -37,8 +35,7 @@
|
|||
:color "color"
|
||||
:name "name"
|
||||
:chatType 3
|
||||
:lastMessageContent "content"
|
||||
:lastMessageContentType "type"
|
||||
:lastMessage nil
|
||||
:members #{{:id "a"
|
||||
:admin true
|
||||
:joined true}
|
||||
|
@ -90,9 +87,6 @@
|
|||
:admin false
|
||||
:joined false}]
|
||||
:lastClockValue 10
|
||||
:lastMessageContent "\"content\"" ;; goes through edn/read-string
|
||||
:lastMessageContentType "type"
|
||||
|
||||
:membershipUpdates [{:type "chat-created"
|
||||
:name "test"
|
||||
:clockValue 1
|
||||
|
@ -111,11 +105,9 @@
|
|||
expected-chat {:public? false
|
||||
:group-chat true
|
||||
:color "color"
|
||||
:last-message-content "content"
|
||||
:last-message-content-type "type"
|
||||
|
||||
:contacts #{"a" "b" "c" "d"}
|
||||
:last-clock-value 10
|
||||
:last-message nil
|
||||
:admins #{"a" "b"}
|
||||
:members-joined #{"a" "c"}
|
||||
:name "name"
|
||||
|
|
|
@ -6,60 +6,45 @@
|
|||
(def chat-id "chat-id")
|
||||
(def from "0x0424a68f89ba5fcd5e0640c1e1f591d561fa4125ca4e2a43592bc4123eca10ce064e522c254bb83079ba404327f6eafc01ec90a1444331fe769d3f3a7f90b0dde1")
|
||||
|
||||
(deftest message->rpc
|
||||
(testing "message to rpc"
|
||||
(let [message {:message-id message-id
|
||||
:content {:chat-id chat-id
|
||||
:response-to "id-2"
|
||||
:text "hta"}
|
||||
:whisper-timestamp 1
|
||||
:dedup-id "ATIwMTkwODE0YTdkNWZhZGY1N2E0ZDU3MzUxZmJkNDZkZGM1ZTU4ZjRlYzUyYWYyMDA5NTc2NWYyYmIxOTQ2OTM3NGUwNjdiMvEpTIGEjHOTAyqsrN39wST4npnSAv1AR8jJWeubanjkoGIyJooD5RVRnx6ZMt+/JzBOD2hoZzlHQWA0bC6XbdU="
|
||||
:outgoing-status :sending
|
||||
:message-type :public-group-user-message
|
||||
:clock-value 2
|
||||
:from from
|
||||
:chat-id chat-id
|
||||
:content-type "text/plain"
|
||||
:timestamp 3}
|
||||
expected {:id message-id
|
||||
:whisperTimestamp 1
|
||||
:from from
|
||||
:chatId chat-id
|
||||
:replyTo "id-2"
|
||||
:content "{\"chat-id\":\"chat-id\",\"response-to\":\"id-2\",\"text\":\"hta\"}"
|
||||
:contentType "text/plain"
|
||||
:messageType "public-group-user-message"
|
||||
:clockValue 2
|
||||
:timestamp 3
|
||||
:outgoingStatus "sending"}]
|
||||
(is (= expected (m/->rpc message))))))
|
||||
|
||||
(deftest message<-rpc
|
||||
(testing "message to rpc"
|
||||
(let [expected {:message-id message-id
|
||||
:content {:chat-id chat-id
|
||||
:text "hta"}
|
||||
:sticker {:hash "hash" :pack 1}
|
||||
:text "hta"
|
||||
:line-count 1
|
||||
:ens-name "ens-name"
|
||||
:parsed-text "parsed-text"
|
||||
:rtl false
|
||||
:response-to "a"}
|
||||
:whisper-timestamp 1
|
||||
:outgoing-status :sending
|
||||
:outgoing :sending
|
||||
:message-type :public-group-user-message
|
||||
:outgoing true
|
||||
:message-type 0
|
||||
:clock-value 2
|
||||
:from from
|
||||
:chat-id chat-id
|
||||
:quoted-message {:from "from"
|
||||
:text "reply"}
|
||||
:content-type "text/plain"
|
||||
:content-type 1
|
||||
:timestamp 3}
|
||||
message {:id message-id
|
||||
:whisperTimestamp 1
|
||||
:parsedText "parsed-text"
|
||||
:ensName "ens-name"
|
||||
:localChatId chat-id
|
||||
:from from
|
||||
:text "hta"
|
||||
:rtl false
|
||||
:chatId chat-id
|
||||
:content "{\"chat-id\":\"chat-id\",\"text\":\"hta\"}"
|
||||
:contentType "text/plain"
|
||||
:messageType "public-group-user-message"
|
||||
:clockValue 2
|
||||
:lineCount 1
|
||||
:sticker {:hash "hash" :pack 1}
|
||||
:contentType 1
|
||||
:messageType 0
|
||||
:clock 2
|
||||
:responseTo "a"
|
||||
:quotedMessage {:from "from"
|
||||
:content "{\"chat-id\":\"chat-id\",\"text\":\"reply\"}"}
|
||||
:text "reply"}
|
||||
:timestamp 3
|
||||
:outgoingStatus "sending"}]
|
||||
(is (= expected (m/<-rpc message))))))
|
||||
|
|
|
@ -57,14 +57,7 @@
|
|||
(:membership-updates actual))))
|
||||
(testing "it sets the right admins"
|
||||
(is (= #{admin}
|
||||
(:admins actual))))
|
||||
(testing "it adds a system message"
|
||||
(is (= 3 (count (:messages actual)))))
|
||||
(testing "it adds the right text"
|
||||
(is (= ["group-chat-created"
|
||||
"group-chat-member-added"
|
||||
"group-chat-member-added"]
|
||||
(map (comp :text :content) (sort-by :clock-value (vals (:messages actual)))))))))
|
||||
(:admins actual))))))
|
||||
(testing "a chat with the wrong id"
|
||||
(let [bad-chat-id (str random-id member-2)
|
||||
actual (->
|
||||
|
@ -162,18 +155,7 @@
|
|||
(testing "members are updated"
|
||||
(is (= #{member-1 member-2 member-4} (:contacts actual-chat))))
|
||||
(testing "the name is updated"
|
||||
(is (= "new-name" (:name actual-chat))))
|
||||
(testing "it adds a system message"
|
||||
(is (= 7 (count (:messages actual-chat)))))
|
||||
(testing "it sets the right text"
|
||||
(is (= ["group-chat-created"
|
||||
"group-chat-member-added"
|
||||
"group-chat-member-added"
|
||||
"group-chat-admin-added"
|
||||
"group-chat-member-added"
|
||||
"group-chat-member-removed"
|
||||
"group-chat-name-changed"]
|
||||
(map (comp :text :content) (sort-by :clock-value (vals (:messages actual-chat)))))))))))))
|
||||
(is (= "new-name" (:name actual-chat))))))))))
|
||||
|
||||
(deftest build-group-test
|
||||
(testing "only adds"
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
[status-im.test.sign-in.flow]
|
||||
[status-im.test.stickers.core]
|
||||
[status-im.test.transport.core]
|
||||
[status-im.test.transport.utils]
|
||||
[status-im.test.tribute-to-talk.core]
|
||||
[status-im.test.tribute-to-talk.db]
|
||||
[status-im.test.tribute-to-talk.whitelist]
|
||||
|
@ -112,7 +111,6 @@
|
|||
'status-im.test.signing.core
|
||||
'status-im.test.signing.gas
|
||||
'status-im.test.transport.core
|
||||
'status-im.test.transport.utils
|
||||
'status-im.test.tribute-to-talk.core
|
||||
'status-im.test.tribute-to-talk.db
|
||||
'status-im.test.tribute-to-talk.whitelist
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
(ns status-im.test.transport.utils
|
||||
(:require [cljs.test :refer-macros [deftest is testing]]
|
||||
[status-im.utils.fx :as fx]
|
||||
[status-im.transport.utils :as transport]))
|
||||
|
||||
(deftest test-message-id
|
||||
(testing "test"
|
||||
(let [pk "0x03d0370306168850aa1f06a2f22c9a756c7dd00e35dd797fcdf351e53ff6ae7b9f"
|
||||
payload "0x74657374"
|
||||
expected-message-id "0x642b7f39873aab69d5aee686f4ed0ca02f82e025242ea57569a70640a94aea34"]
|
||||
(is (= expected-message-id (transport/message-id pk payload))))))
|
|
@ -1,6 +1,7 @@
|
|||
(ns status-im.test.tribute-to-talk.whitelist
|
||||
(:require [cljs.test :refer-macros [deftest testing is]]
|
||||
[status-im.utils.gfycat.core :as gfycat]
|
||||
[status-im.constants :as constants]
|
||||
[status-im.utils.identicon :as identicon]
|
||||
[status-im.tribute-to-talk.whitelist :as whitelist]))
|
||||
|
||||
|
@ -113,21 +114,21 @@
|
|||
(whitelist/filter-message
|
||||
(whitelist/enable-whitelist ttt-enabled-multiaccount)
|
||||
:unfiltered-fx
|
||||
:user-message
|
||||
constants/message-type-one-to-one
|
||||
nil
|
||||
"whitelisted because added"))
|
||||
(testing "tribute to talk is disabled"
|
||||
(whitelist/filter-message
|
||||
ttt-disabled-multiaccount
|
||||
:unfiltered-fx
|
||||
:user-message
|
||||
constants/message-type-one-to-one
|
||||
nil
|
||||
"public-key"))
|
||||
(testing "user is not whitelisted but transaction is valid"
|
||||
(let [result (whitelist/filter-message
|
||||
ttt-enabled-multiaccount
|
||||
#(assoc % :message-received true)
|
||||
:user-message
|
||||
constants/message-type-one-to-one
|
||||
"transaction-hash-1"
|
||||
sender-pk)]
|
||||
(is (contains? (get-in result [:db :contacts/whitelist])
|
||||
|
|
|
@ -492,14 +492,14 @@
|
|||
"got-it": "Got it",
|
||||
"group-chat": "Group chat",
|
||||
"group-chat-admin": "Admin",
|
||||
"group-chat-admin-added": "*{{member}}* has been made admin",
|
||||
"group-chat-created": "*{{member}}* created the group *{{name}}*",
|
||||
"group-chat-admin-added": "**{{member}}** has been made admin",
|
||||
"group-chat-created": "**{{member}}** created the group **{{name}}**",
|
||||
"group-chat-decline-invitation": "Decline invitation",
|
||||
"group-chat-member-added": "*{{member}}* has been invited",
|
||||
"group-chat-member-joined": "*{{member}}* has joined the group",
|
||||
"group-chat-member-removed": "*{{member}}* left the group",
|
||||
"group-chat-member-added": "**{{member}}** has been invited",
|
||||
"group-chat-member-joined": "**{{member}}** has joined the group",
|
||||
"group-chat-member-removed": "**{{member}}** left the group",
|
||||
"group-chat-members-count": "{{selected}}/{{max}} members",
|
||||
"group-chat-name-changed": "*{{member}}* changed the group's name to *{{name}}*",
|
||||
"group-chat-name-changed": "**{{member}}** changed the group's name to **{{name}}**",
|
||||
"group-chat-no-contacts": "You don't have any contacts yet.\nInvite your friends to start chatting",
|
||||
"group-info": "Group info",
|
||||
"gwei": "Gwei",
|
||||
|
|
Loading…
Reference in New Issue