|
1 | 1 | (ns status-im.contexts.wallet.collectible.events
|
2 | 2 | (:require [camel-snake-kebab.extras :as cske]
|
| 3 | + [clojure.set] |
3 | 4 | [clojure.string :as string]
|
4 | 5 | [react-native.platform :as platform]
|
5 | 6 | [status-im.contexts.network.data-store :as network.data-store]
|
6 | 7 | [status-im.contexts.wallet.collectible.utils :as collectible-utils]
|
| 8 | + [status-im.contexts.wallet.data-store :as data-store] |
7 | 9 | [taoensso.timbre :as log]
|
| 10 | + [utils.collection] |
8 | 11 | [utils.ethereum.chain :as chain]
|
| 12 | + [utils.number :as utils.number] |
9 | 13 | [utils.re-frame :as rf]
|
10 | 14 | [utils.transforms :as transforms]))
|
11 | 15 |
|
|
24 | 28 | (def max-cache-age-seconds 3600)
|
25 | 29 | (def collectibles-request-batch-size 25)
|
26 | 30 |
|
| 31 | +(def ownership-state |
| 32 | + {:idle 1 |
| 33 | + :delayed 2 |
| 34 | + :updating 3 |
| 35 | + :error 4}) |
| 36 | + |
27 | 37 | (defn- move-collectibles-to-accounts
|
28 | 38 | [accounts new-collectibles-per-account]
|
29 | 39 | (reduce-kv (fn [acc account new-collectibles]
|
|
84 | 94 | (rf/reg-event-fx
|
85 | 95 | :wallet/request-collectibles-for-all-accounts
|
86 | 96 | (fn [{:keys [db]} [{:keys [new-request?]}]]
|
87 |
| - (let [accounts (->> (get-in db [:wallet :accounts]) |
| 97 | + (let [updating-addresses (-> (get-in db [:wallet :ui :collectibles :updating]) |
| 98 | + keys |
| 99 | + set) |
| 100 | + accounts (->> (get-in db [:wallet :accounts]) |
88 | 101 | (filter (fn [[_ {:keys [has-more-collectibles?]}]]
|
89 | 102 | (or (nil? has-more-collectibles?)
|
90 | 103 | (true? has-more-collectibles?))))
|
91 | 104 | (keys))
|
92 |
| - num-accounts (count accounts) |
| 105 | + ;; filter the addresses which are requested before and the collectibles are updating |
| 106 | + requestable-addresses (clojure.set/difference (set accounts) |
| 107 | + updating-addresses) |
| 108 | + num-accounts (count requestable-addresses) |
93 | 109 | collectibles-per-account (quot collectibles-request-batch-size num-accounts)
|
94 | 110 | ;; We need to pass unique IDs for simultaneous requests, otherwise they'll fail
|
95 | 111 | request-ids (get-unique-collectible-request-id num-accounts)
|
|
100 | 116 | :account account
|
101 | 117 | :amount collectibles-per-account}]])
|
102 | 118 | request-ids
|
103 |
| - accounts)] |
| 119 | + requestable-addresses)] |
104 | 120 | {:db (cond-> db
|
105 | 121 | :always (assoc-in [:wallet :ui :collectibles :pending-requests] num-accounts)
|
106 | 122 | new-request? (update-in [:wallet :accounts] update-vals #(dissoc % :collectibles)))
|
107 | 123 | :fx collectible-requests})))
|
108 | 124 |
|
109 |
| -(defn request-new-collectibles-for-account-from-signal |
| 125 | +(defn request-collectibles-for-account |
110 | 126 | [{:keys [db]} [address]]
|
111 | 127 | (let [pending-requests (get-in db [:wallet :ui :collectibles :pending-requests] 0)
|
112 | 128 | [request-id] (get-unique-collectible-request-id 1)]
|
|
117 | 133 | :account address
|
118 | 134 | :amount collectibles-request-batch-size}]]]}))
|
119 | 135 |
|
120 |
| -(rf/reg-event-fx :wallet/request-new-collectibles-for-account-from-signal |
121 |
| - request-new-collectibles-for-account-from-signal) |
| 136 | +(rf/reg-event-fx :wallet/request-collectibles-for-account request-collectibles-for-account) |
122 | 137 |
|
123 | 138 | (rf/reg-event-fx
|
124 | 139 | :wallet/request-collectibles-for-current-viewing-account
|
125 | 140 | (fn [{:keys [db]} _]
|
126 | 141 | (when (network.data-store/online? db)
|
127 |
| - (let [current-viewing-account (-> db :wallet :current-viewing-account-address) |
128 |
| - [request-id] (get-unique-collectible-request-id 1)] |
129 |
| - {:db (assoc-in db [:wallet :ui :collectibles :pending-requests] 1) |
130 |
| - :fx [[:dispatch |
131 |
| - [:wallet/request-new-collectibles-for-account |
132 |
| - {:request-id request-id |
133 |
| - :account current-viewing-account |
134 |
| - :amount collectibles-request-batch-size}]]]})))) |
| 142 | + (let [current-viewing-account (-> db :wallet :current-viewing-account-address)] |
| 143 | + {:fx [[:dispatch [:wallet/request-collectibles-for-account current-viewing-account]]]})))) |
| 144 | + |
| 145 | +(rf/reg-event-fx |
| 146 | + :wallet/collectible-ownership-update-finished-with-error |
| 147 | + (fn [{:keys [db]} [{:keys [accounts message chainId]}]] |
| 148 | + (let [address (first accounts) |
| 149 | + pending-chain-ids (get-in db [:wallet :ui :collectibles :updating address]) |
| 150 | + updated-chain-ids (disj pending-chain-ids chainId) |
| 151 | + all-chain-updated? (and (some? pending-chain-ids) (empty? updated-chain-ids))] |
| 152 | + {:db (cond-> db |
| 153 | + (some? pending-chain-ids) |
| 154 | + (assoc-in [:wallet :ui :collectibles :updating address] updated-chain-ids)) |
| 155 | + :fx [[:dispatch |
| 156 | + [:wallet/log-rpc-error |
| 157 | + {:event :wallet/collectible-ownership-update-finished-with-error |
| 158 | + :params {:address address |
| 159 | + :chain-id chainId}} |
| 160 | + message]] |
| 161 | + (when all-chain-updated? |
| 162 | + [:dispatch [:wallet/request-collectibles-for-account address]])]}))) |
| 163 | + |
| 164 | +(rf/reg-event-fx |
| 165 | + :wallet/collectible-ownership-update-finished |
| 166 | + (fn [{:keys [db]} [{:keys [accounts chainId]}]] |
| 167 | + (let [address (first accounts) |
| 168 | + pending-chain-ids (get-in db [:wallet :ui :collectibles :updating address]) |
| 169 | + updated-chain-ids (disj pending-chain-ids chainId) |
| 170 | + all-chain-updated? (and (some? pending-chain-ids) (empty? updated-chain-ids))] |
| 171 | + {:db (cond-> db |
| 172 | + (some? pending-chain-ids) |
| 173 | + (assoc-in [:wallet :ui :collectibles :updating address] updated-chain-ids)) |
| 174 | + :fx [(when all-chain-updated? |
| 175 | + [:dispatch [:wallet/request-collectibles-for-account address]])]}))) |
| 176 | + |
| 177 | +(defn- update-collectibles-in-account |
| 178 | + [existing-collectibles updated-collectibles] |
| 179 | + (let [indexed-existing (utils.collection/index-by |
| 180 | + :unique-id |
| 181 | + existing-collectibles) |
| 182 | + existing-ids (-> indexed-existing keys vec) |
| 183 | + ;; pick collectibles only in the app-db |
| 184 | + indexed-updated (-> (utils.collection/index-by |
| 185 | + :unique-id |
| 186 | + updated-collectibles) |
| 187 | + (select-keys existing-ids))] |
| 188 | + (-> (merge-with |
| 189 | + merge |
| 190 | + indexed-existing |
| 191 | + indexed-updated) |
| 192 | + vals |
| 193 | + vec))) |
| 194 | + |
| 195 | +(rf/reg-event-fx |
| 196 | + :wallet/collectibles-data-updated |
| 197 | + (fn [{:keys [db]} [{:keys [message]}]] |
| 198 | + (let [collectibles-by-address (->> message |
| 199 | + transforms/json->clj |
| 200 | + data-store/rpc->collectibles |
| 201 | + (group-by #(-> % :ownership first :address)))] |
| 202 | + {:db (update-in db |
| 203 | + [:wallet :accounts] |
| 204 | + #(reduce-kv |
| 205 | + (fn [accounts address updated-collectibles] |
| 206 | + (if (contains? accounts address) |
| 207 | + (update-in accounts |
| 208 | + [address :collectibles] |
| 209 | + update-collectibles-in-account |
| 210 | + updated-collectibles) |
| 211 | + accounts)) |
| 212 | + % |
| 213 | + collectibles-by-address))}))) |
| 214 | + |
| 215 | +(rf/reg-event-fx |
| 216 | + :wallet/set-collectibles-updating-status |
| 217 | + (fn [{:keys [db]} [address chain-ids]] |
| 218 | + {:db (assoc-in db [:wallet :ui :collectibles :updating address] chain-ids)})) |
135 | 219 |
|
136 | 220 | (defn- update-fetched-collectibles-progress
|
137 | 221 | [db owner-address collectibles offset has-more?]
|
138 | 222 | (-> db
|
| 223 | + (update-in [:wallet :ui :collectibles :updating] dissoc owner-address) |
139 | 224 | (assoc-in [:wallet :ui :collectibles :fetched owner-address] collectibles)
|
140 | 225 | (assoc-in [:wallet :accounts owner-address :current-collectible-idx]
|
141 | 226 | (+ offset (count collectibles)))
|
142 | 227 | (assoc-in [:wallet :accounts owner-address :has-more-collectibles?] has-more?)))
|
143 | 228 |
|
| 229 | +(defn- updating-collectibles? |
| 230 | + [status] |
| 231 | + (and (= (:state status) (ownership-state :updating)) |
| 232 | + (= (:timestamp status) -1))) |
| 233 | + |
144 | 234 | (rf/reg-event-fx
|
145 | 235 | :wallet/owned-collectibles-filtering-done
|
146 | 236 | (fn [{:keys [db]} [{:keys [message]}]]
|
147 | 237 | (let [{:keys [offset ownershipStatus collectibles
|
148 |
| - hasMore]} (transforms/json->clj message) |
149 |
| - collectibles (cske/transform-keys transforms/->kebab-case-keyword collectibles) |
150 |
| - pending-requests (dec (get-in db [:wallet :ui :collectibles :pending-requests])) |
151 |
| - owner-address (some->> ownershipStatus |
152 |
| - first |
153 |
| - key |
154 |
| - name)] |
| 238 | + hasMore]} (transforms/json->clj message) |
| 239 | + ownership-status-by-address (-> ownershipStatus |
| 240 | + (update-keys name) |
| 241 | + (update-vals #(update-keys % |
| 242 | + (comp utils.number/parse-int name)))) |
| 243 | + owner-address (some-> ownership-status-by-address |
| 244 | + first |
| 245 | + key) |
| 246 | + ownership-status (get ownership-status-by-address owner-address) |
| 247 | + collectibles (data-store/rpc->collectibles collectibles) |
| 248 | + pending-requests (dec (get-in db [:wallet :ui :collectibles :pending-requests])) |
| 249 | + ;; check if collectibles are updating (never fetched and cached before) for this address |
| 250 | + updating-chains (-> (select-keys |
| 251 | + ownership-status |
| 252 | + (for [[k v] ownership-status |
| 253 | + :when (updating-collectibles? v)] |
| 254 | + k)) |
| 255 | + keys |
| 256 | + set) |
| 257 | + updating? (-> updating-chains count pos?)] |
155 | 258 | {:db (cond-> db
|
156 | 259 | :always (assoc-in [:wallet :ui :collectibles :pending-requests] pending-requests)
|
157 | 260 | owner-address (update-fetched-collectibles-progress owner-address
|
158 | 261 | collectibles
|
159 | 262 | offset
|
160 |
| - hasMore)) |
| 263 | + (when-not updating? hasMore))) |
161 | 264 | :fx [(when (zero? pending-requests)
|
162 |
| - [:dispatch [:wallet/flush-collectibles-fetched]])]}))) |
| 265 | + [:dispatch [:wallet/flush-collectibles-fetched]]) |
| 266 | + (when updating? |
| 267 | + [:dispatch [:wallet/set-collectibles-updating-status owner-address updating-chains]])]}))) |
163 | 268 |
|
164 | 269 | (rf/reg-event-fx
|
165 | 270 | :wallet/navigate-to-collectible-details
|
|
0 commit comments