Keep username/photo-path synced across devices
We add syncing of account fields in pairing messages (only photo-path & name for now). Also a sync message is sent each time we send a contact-update, to keep other devices in sync. The change is compatible with previous clients as it's just an accretion of transit. Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
parent
6cf9e6136b
commit
08291a8396
|
@ -47,6 +47,13 @@
|
||||||
|
|
||||||
(def merge-contacts (partial merge-with merge-contact))
|
(def merge-contacts (partial merge-with merge-contact))
|
||||||
|
|
||||||
|
(def account-mergeable-keys [:name :photo-path :last-updated])
|
||||||
|
|
||||||
|
(defn merge-account [local remote]
|
||||||
|
(if (> (:last-updated remote) (:last-updated local))
|
||||||
|
(merge local (select-keys remote account-mergeable-keys))
|
||||||
|
local))
|
||||||
|
|
||||||
(fx/defn upsert-installation [{:keys [db]} {:keys [installation-id] :as new-installation}]
|
(fx/defn upsert-installation [{:keys [db]} {:keys [installation-id] :as new-installation}]
|
||||||
(let [old-installation (get-in db [:pairing/installations installation-id])
|
(let [old-installation (get-in db [:pairing/installations installation-id])
|
||||||
updated-installation (merge old-installation new-installation)]
|
updated-installation (merge old-installation new-installation)]
|
||||||
|
@ -68,18 +75,26 @@
|
||||||
(not (get-in db [:pairing/installations installation-id])))
|
(not (get-in db [:pairing/installations installation-id])))
|
||||||
(upsert-installation cofx new-installation))))))
|
(upsert-installation cofx new-installation))))))
|
||||||
|
|
||||||
(defn sync-installation-messages [{:keys [db]}]
|
(defn sync-installation-account-message [{:keys [db]}]
|
||||||
(let [contacts (:contacts/contacts db)]
|
(let [account (-> db
|
||||||
(map
|
:account/account
|
||||||
(fn [batch]
|
(select-keys account-mergeable-keys))]
|
||||||
(let [contacts-to-sync (reduce (fn [acc {:keys [public-key] :as contact}]
|
(transport.pairing/SyncInstallation. {} account)))
|
||||||
(assoc acc public-key (dissoc contact :photo-path)))
|
|
||||||
{}
|
(defn- contact-batch->sync-installation-message [batch]
|
||||||
batch)]
|
(let [contacts-to-sync (reduce (fn [acc {:keys [public-key] :as contact}]
|
||||||
(transport.pairing/SyncInstallation. contacts-to-sync)))
|
(assoc acc public-key (dissoc contact :photo-path)))
|
||||||
(partition-all contact-batch-n (->> contacts
|
{}
|
||||||
vals
|
batch)]
|
||||||
(remove :dapp?))))))
|
(transport.pairing/SyncInstallation. contacts-to-sync nil)))
|
||||||
|
|
||||||
|
(defn sync-installation-messages [{:keys [db] :as cofx}]
|
||||||
|
(let [contacts (:contacts/contacts db)
|
||||||
|
contact-batches (partition-all contact-batch-n (->> contacts
|
||||||
|
vals
|
||||||
|
(remove :dapp?)))]
|
||||||
|
(conj (mapv contact-batch->sync-installation-message contact-batches)
|
||||||
|
(sync-installation-account-message cofx))))
|
||||||
|
|
||||||
(defn enable [{:keys [db]} installation-id]
|
(defn enable [{:keys [db]} installation-id]
|
||||||
{:db (assoc-in db
|
{:db (assoc-in db
|
||||||
|
@ -167,12 +182,15 @@
|
||||||
{}
|
{}
|
||||||
contacts))
|
contacts))
|
||||||
|
|
||||||
(defn handle-sync-installation [{:keys [db] :as cofx} {:keys [contacts]} sender]
|
(defn handle-sync-installation [{:keys [db] :as cofx} {:keys [contacts account]} sender]
|
||||||
(let [dev-mode? (get-in db [:account/account :dev-mode?])]
|
(let [dev-mode? (get-in db [:account/account :dev-mode?])]
|
||||||
(when (and (config/pairing-enabled? dev-mode?)
|
(when (and (config/pairing-enabled? dev-mode?)
|
||||||
(= sender (accounts.db/current-public-key cofx)))
|
(= sender (accounts.db/current-public-key cofx)))
|
||||||
(let [new-contacts (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts))]
|
(let [new-contacts (merge-contacts (:contacts/contacts db) (ensure-photo-path contacts))
|
||||||
{:db (assoc db :contacts/contacts new-contacts)
|
new-account (merge-account (:account/account db) account)]
|
||||||
|
{:db (assoc db
|
||||||
|
:contacts/contacts new-contacts
|
||||||
|
:account/account new-account)
|
||||||
:data-store/tx [(data-store.contacts/save-contacts-tx (vals new-contacts))]}))))
|
:data-store/tx [(data-store.contacts/save-contacts-tx (vals new-contacts))]}))))
|
||||||
|
|
||||||
(defn handle-pair-installation [{:keys [db] :as cofx} {:keys [installation-id device-type]} timestamp sender]
|
(defn handle-pair-installation [{:keys [db] :as cofx} {:keys [installation-id device-type]} timestamp sender]
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
(let [sync-message (transport.pairing/SyncInstallation.
|
(let [sync-message (transport.pairing/SyncInstallation.
|
||||||
(select-keys
|
(select-keys
|
||||||
(get-in cofx [:db :contacts/contacts])
|
(get-in cofx [:db :contacts/contacts])
|
||||||
[chat-id]))]
|
[chat-id])
|
||||||
|
nil)]
|
||||||
(fx/merge cofx
|
(fx/merge cofx
|
||||||
(protocol/init-chat {:chat-id chat-id
|
(protocol/init-chat {:chat-id chat-id
|
||||||
:resend? "contact-request"})
|
:resend? "contact-request"})
|
||||||
|
@ -45,7 +46,8 @@
|
||||||
(let [sync-message (transport.pairing/SyncInstallation.
|
(let [sync-message (transport.pairing/SyncInstallation.
|
||||||
(select-keys
|
(select-keys
|
||||||
(get-in cofx [:db :contacts/contacts])
|
(get-in cofx [:db :contacts/contacts])
|
||||||
[chat-id]))
|
[chat-id])
|
||||||
|
nil)
|
||||||
success-event [:transport/contact-message-sent chat-id]
|
success-event [:transport/contact-message-sent chat-id]
|
||||||
chat (get-in db [:transport/chats chat-id])
|
chat (get-in db [:transport/chats chat-id])
|
||||||
updated-chat (if chat
|
updated-chat (if chat
|
||||||
|
@ -60,3 +62,35 @@
|
||||||
:payload this
|
:payload this
|
||||||
:success-event success-event})
|
:success-event success-event})
|
||||||
(pairing/send-installation-message-fx sync-message)))))
|
(pairing/send-installation-message-fx sync-message)))))
|
||||||
|
|
||||||
|
(fx/defn send-contact-update
|
||||||
|
[{:keys [db] :as cofx} chat-id payload]
|
||||||
|
(when-let [chat (get-in cofx [:db :transport/chats chat-id])]
|
||||||
|
(let [updated-chat (assoc chat :resend? "contact-update")
|
||||||
|
tx [(transport-store/save-transport-tx {:chat-id chat-id
|
||||||
|
:chat updated-chat})]
|
||||||
|
success-event [:transport/contact-message-sent chat-id]]
|
||||||
|
(fx/merge cofx
|
||||||
|
{:db (assoc-in db
|
||||||
|
[:transport/chats chat-id :resend?]
|
||||||
|
"contact-update")
|
||||||
|
:data-store/tx tx}
|
||||||
|
(protocol/send-with-pubkey {:chat-id chat-id
|
||||||
|
:payload payload
|
||||||
|
:success-event success-event})))))
|
||||||
|
(extend-type transport.contact/ContactUpdate
|
||||||
|
protocol/StatusMessage
|
||||||
|
(send [this _ {:keys [db] :as cofx}]
|
||||||
|
(let [contact-public-keys (reduce (fn [acc [_ {:keys [public-key dapp? pending?]}]]
|
||||||
|
(if (and (not dapp?)
|
||||||
|
(not pending?))
|
||||||
|
(conj acc public-key)
|
||||||
|
acc))
|
||||||
|
#{}
|
||||||
|
(:contacts/contacts db))
|
||||||
|
;;NOTE: chats with contacts use public-key as chat-id
|
||||||
|
send-contact-update-fxs (map #(send-contact-update % this) contact-public-keys)
|
||||||
|
sync-message (pairing/sync-installation-account-message cofx)
|
||||||
|
fxs (conj send-contact-update-fxs
|
||||||
|
(pairing/send-installation-message-fx sync-message))]
|
||||||
|
(apply fx/merge cofx fxs))))
|
||||||
|
|
|
@ -18,35 +18,8 @@
|
||||||
(when (spec/valid? :message/contact-request-confirmed this)
|
(when (spec/valid? :message/contact-request-confirmed this)
|
||||||
this)))
|
this)))
|
||||||
|
|
||||||
(fx/defn send-contact-update
|
|
||||||
[{:keys [db] :as cofx} chat-id payload]
|
|
||||||
(when-let [chat (get-in cofx [:db :transport/chats chat-id])]
|
|
||||||
(let [updated-chat (assoc chat :resend? "contact-update")
|
|
||||||
tx [(transport-store/save-transport-tx {:chat-id chat-id
|
|
||||||
:chat updated-chat})]
|
|
||||||
success-event [:transport/contact-message-sent chat-id]]
|
|
||||||
(fx/merge cofx
|
|
||||||
{:db (assoc-in db
|
|
||||||
[:transport/chats chat-id :resend?]
|
|
||||||
"contact-update")
|
|
||||||
:data-store/tx tx}
|
|
||||||
(protocol/send-with-pubkey {:chat-id chat-id
|
|
||||||
:payload payload
|
|
||||||
:success-event success-event})))))
|
|
||||||
|
|
||||||
(defrecord ContactUpdate [name profile-image address fcm-token]
|
(defrecord ContactUpdate [name profile-image address fcm-token]
|
||||||
protocol/StatusMessage
|
protocol/StatusMessage
|
||||||
(send [this _ {:keys [db] :as cofx}]
|
|
||||||
(let [contact-public-keys (reduce (fn [acc [_ {:keys [public-key dapp? pending?]}]]
|
|
||||||
(if (and (not dapp?)
|
|
||||||
(not pending?))
|
|
||||||
(conj acc public-key)
|
|
||||||
acc))
|
|
||||||
#{}
|
|
||||||
(:contacts/contacts db))
|
|
||||||
;;NOTE: chats with contacts use public-key as chat-id
|
|
||||||
send-contact-update-fxs (map #(send-contact-update % this) contact-public-keys)]
|
|
||||||
(apply fx/merge cofx send-contact-update-fxs)))
|
|
||||||
(validate [this]
|
(validate [this]
|
||||||
(when (spec/valid? :message/contact-update this)
|
(when (spec/valid? :message/contact-update this)
|
||||||
this)))
|
this)))
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
(log/warn "failed sync installation validation" (spec/explain :message/pair-installation this)))))
|
(log/warn "failed sync installation validation" (spec/explain :message/pair-installation this)))))
|
||||||
|
|
||||||
(defrecord SyncInstallation
|
(defrecord SyncInstallation
|
||||||
[contacts]
|
[contacts account]
|
||||||
protocol/StatusMessage
|
protocol/StatusMessage
|
||||||
(validate [this]
|
(validate [this]
|
||||||
(if (spec/valid? :message/sync-installation this)
|
(if (spec/valid? :message/sync-installation this)
|
||||||
|
|
|
@ -86,8 +86,8 @@
|
||||||
(deftype SyncInstallationHandler []
|
(deftype SyncInstallationHandler []
|
||||||
Object
|
Object
|
||||||
(tag [this v] "p1")
|
(tag [this v] "p1")
|
||||||
(rep [this {:keys [contacts]}]
|
(rep [this {:keys [contacts account]}]
|
||||||
#js [contacts]))
|
#js [contacts account]))
|
||||||
|
|
||||||
(deftype PairInstallationHandler []
|
(deftype PairInstallationHandler []
|
||||||
Object
|
Object
|
||||||
|
@ -154,8 +154,8 @@
|
||||||
(contact/ContactUpdate. name profile-image address fcm-token))
|
(contact/ContactUpdate. name profile-image address fcm-token))
|
||||||
"g5" (fn [[chat-id membership-updates message]]
|
"g5" (fn [[chat-id membership-updates message]]
|
||||||
(group-chat/GroupMembershipUpdate. chat-id membership-updates message))
|
(group-chat/GroupMembershipUpdate. chat-id membership-updates message))
|
||||||
"p1" (fn [[contacts]]
|
"p1" (fn [[contacts account]]
|
||||||
(pairing/SyncInstallation. contacts))
|
(pairing/SyncInstallation. contacts account))
|
||||||
"p2" (fn [[installation-id device-type]]
|
"p2" (fn [[installation-id device-type]]
|
||||||
(pairing/PairInstallation. installation-id device-type))}}))
|
(pairing/PairInstallation. installation-id device-type))}}))
|
||||||
|
|
||||||
|
|
|
@ -75,64 +75,85 @@
|
||||||
(deftest handle-sync-installation-test
|
(deftest handle-sync-installation-test
|
||||||
(with-redefs [config/pairing-enabled? (constantly true)
|
(with-redefs [config/pairing-enabled? (constantly true)
|
||||||
identicon/identicon (constantly "generated")]
|
identicon/identicon (constantly "generated")]
|
||||||
(let [old-contact-1 {:name "old-contact-one"
|
|
||||||
:public-key "contact-1"
|
(testing "syncing contacts"
|
||||||
:last-updated 0
|
(let [old-contact-1 {:name "old-contact-one"
|
||||||
:photo-path "old-contact-1"
|
:public-key "contact-1"
|
||||||
:pending? true}
|
:last-updated 0
|
||||||
new-contact-1 {:name "new-contact-one"
|
:photo-path "old-contact-1"
|
||||||
:public-key "contact-1"
|
:pending? true}
|
||||||
:last-updated 1
|
new-contact-1 {:name "new-contact-one"
|
||||||
:photo-path "new-contact-1"
|
:public-key "contact-1"
|
||||||
:pending? false}
|
:last-updated 1
|
||||||
old-contact-2 {:name "old-contact-2"
|
:photo-path "new-contact-1"
|
||||||
:public-key "contact-2"
|
:pending? false}
|
||||||
:last-updated 0
|
old-contact-2 {:name "old-contact-2"
|
||||||
:photo-path "old-contact-2"
|
:public-key "contact-2"
|
||||||
:pending? false}
|
:last-updated 0
|
||||||
new-contact-2 {:name "new-contact-2"
|
:photo-path "old-contact-2"
|
||||||
:public-key "contact-2"
|
:pending? false}
|
||||||
:last-updated 1
|
new-contact-2 {:name "new-contact-2"
|
||||||
:photo-path "new-contact-2"
|
:public-key "contact-2"
|
||||||
:pending? false}
|
:last-updated 1
|
||||||
contact-3 {:name "contact-3"
|
:photo-path "new-contact-2"
|
||||||
:public-key "contact-3"
|
:pending? false}
|
||||||
:photo-path "contact-3"
|
contact-3 {:name "contact-3"
|
||||||
:pending? false}
|
:public-key "contact-3"
|
||||||
contact-4 {:name "contact-4"
|
:photo-path "contact-3"
|
||||||
:public-key "contact-4"
|
:pending? false}
|
||||||
:pending? true}
|
contact-4 {:name "contact-4"
|
||||||
local-contact-5 {:name "contact-5"
|
:public-key "contact-4"
|
||||||
:photo-path "local"
|
:pending? true}
|
||||||
:public-key "contact-5"
|
local-contact-5 {:name "contact-5"
|
||||||
:pending? true
|
:photo-path "local"
|
||||||
:last-updated 1}
|
:public-key "contact-5"
|
||||||
remote-contact-5 {:name "contact-5"
|
:pending? true
|
||||||
:public-key "contact-5"
|
:last-updated 1}
|
||||||
:photo-path "remote"
|
remote-contact-5 {:name "contact-5"
|
||||||
:pending? true
|
:public-key "contact-5"
|
||||||
:last-updated 1}
|
:photo-path "remote"
|
||||||
cofx {:db {:account/account {:public-key "us"}
|
:pending? true
|
||||||
:contacts/contacts {"contact-1" old-contact-1
|
:last-updated 1}
|
||||||
"contact-2" new-contact-2
|
cofx {:db {:account/account {:public-key "us"}
|
||||||
"contact-3" contact-3
|
:contacts/contacts {"contact-1" old-contact-1
|
||||||
"contact-5" local-contact-5}}}
|
"contact-2" new-contact-2
|
||||||
sync-message {:contacts {"contact-1" new-contact-1
|
"contact-3" contact-3
|
||||||
"contact-2" old-contact-2
|
"contact-5" local-contact-5}}}
|
||||||
"contact-4" contact-4
|
sync-message {:contacts {"contact-1" new-contact-1
|
||||||
"contact-5" remote-contact-5}}
|
"contact-2" old-contact-2
|
||||||
expected {"contact-1" new-contact-1
|
"contact-4" contact-4
|
||||||
"contact-2" new-contact-2
|
"contact-5" remote-contact-5}}
|
||||||
"contact-3" contact-3
|
expected {"contact-1" new-contact-1
|
||||||
"contact-4" (assoc contact-4
|
"contact-2" new-contact-2
|
||||||
:photo-path "generated")
|
"contact-3" contact-3
|
||||||
"contact-5" local-contact-5}]
|
"contact-4" (assoc contact-4
|
||||||
(testing "not coming from us"
|
:photo-path "generated")
|
||||||
(is (not (pairing/handle-sync-installation cofx sync-message "not-us"))))
|
"contact-5" local-contact-5}]
|
||||||
(testing "coming from us"
|
(testing "not coming from us"
|
||||||
(is (= expected (get-in
|
(is (not (pairing/handle-sync-installation cofx sync-message "not-us"))))
|
||||||
(pairing/handle-sync-installation cofx sync-message "us")
|
(testing "coming from us"
|
||||||
[:db :contacts/contacts])))))))
|
(is (= expected (get-in
|
||||||
|
(pairing/handle-sync-installation cofx sync-message "us")
|
||||||
|
[:db :contacts/contacts]))))))
|
||||||
|
(testing "syncing account"
|
||||||
|
(let [old-account {:name "old-name"
|
||||||
|
:public-key "us"
|
||||||
|
:photo-path "old-photo-path"
|
||||||
|
:last-updated 0}
|
||||||
|
new-account {:name "new-name"
|
||||||
|
:public-key "us"
|
||||||
|
:photo-path "new-photo-path"
|
||||||
|
:last-updated 1}]
|
||||||
|
(testing "newer update"
|
||||||
|
(let [cofx {:db {:account/account old-account}}
|
||||||
|
sync-message {:account new-account}]
|
||||||
|
(is (= new-account (get-in (pairing/handle-sync-installation cofx sync-message "us")
|
||||||
|
[:db :account/account])))))
|
||||||
|
(testing "older update"
|
||||||
|
(let [cofx {:db {:account/account new-account}}
|
||||||
|
sync-message {:account old-account}]
|
||||||
|
(is (= new-account (get-in (pairing/handle-sync-installation cofx sync-message "us")
|
||||||
|
[:db :account/account])))))))))
|
||||||
|
|
||||||
(deftest handle-pair-installation-test
|
(deftest handle-pair-installation-test
|
||||||
(with-redefs [config/pairing-enabled? (constantly true)]
|
(with-redefs [config/pairing-enabled? (constantly true)]
|
||||||
|
@ -158,7 +179,10 @@
|
||||||
|
|
||||||
(deftest sync-installation-messages-test
|
(deftest sync-installation-messages-test
|
||||||
(testing "it creates a sync installation message"
|
(testing "it creates a sync installation message"
|
||||||
(let [cofx {:db {:account/account {:public-key "us"}
|
(let [cofx {:db {:account/account {:public-key "us"
|
||||||
|
:name "name"
|
||||||
|
:photo-path "photo-path"
|
||||||
|
:last-updated 1}
|
||||||
:contacts/contacts {"contact-1" {:name "contact-1"
|
:contacts/contacts {"contact-1" {:name "contact-1"
|
||||||
:public-key "contact-1"}
|
:public-key "contact-1"}
|
||||||
"contact-2" {:name "contact-2"
|
"contact-2" {:name "contact-2"
|
||||||
|
@ -176,9 +200,13 @@
|
||||||
"contact-3" {:name "contact-3"
|
"contact-3" {:name "contact-3"
|
||||||
:public-key "contact-3"}
|
:public-key "contact-3"}
|
||||||
"contact-4" {:name "contact-4"
|
"contact-4" {:name "contact-4"
|
||||||
:public-key "contact-4"}})
|
:public-key "contact-4"}}
|
||||||
|
nil)
|
||||||
(transport.pairing/SyncInstallation. {"contact-5" {:name "contact-5"
|
(transport.pairing/SyncInstallation. {"contact-5" {:name "contact-5"
|
||||||
:public-key "contact-5"}})]]
|
:public-key "contact-5"}} nil)
|
||||||
|
(transport.pairing/SyncInstallation. {} {:photo-path "photo-path"
|
||||||
|
:name "name"
|
||||||
|
:last-updated 1})]]
|
||||||
(is (= expected (pairing/sync-installation-messages cofx))))))
|
(is (= expected (pairing/sync-installation-messages cofx))))))
|
||||||
|
|
||||||
(deftest handle-bundles-added-test
|
(deftest handle-bundles-added-test
|
||||||
|
|
Loading…
Reference in New Issue