Fix bot subscriptions

This commit is contained in:
janherich 2017-10-20 14:04:24 +02:00 committed by Roman Volosovskyi
parent abe7f0a42a
commit 0ccfefa6c3
8 changed files with 116 additions and 107 deletions

View File

@ -95,7 +95,7 @@ function amountParameterBox(params, context) {
sliderValue: sliderValue
});
}catch (err){
} catch (err) {
status.setDefaultDb({
transaction: txData,

View File

@ -35,7 +35,7 @@ status.defineSubscription(
function(params) {
return getFeeExplanation(params.value);
}
)
);
function amountParameterBox(params, context) {
if (!params["bot-db"]) {
@ -62,13 +62,25 @@ function amountParameterBox(params, context) {
var sliderValue = params["bot-db"]["sliderValue"] || 0;
status.setDefaultDb({
transaction: txData,
calculatedFee: calculateFee(sliderValue, txData),
feeExplanation: getFeeExplanation(sliderValue),
sliderValue: sliderValue
});
try {
status.setDefaultDb({
transaction: txData,
calculatedFee: calculateFee(sliderValue, txData),
feeExplanation: getFeeExplanation(sliderValue),
sliderValue: sliderValue
});
} catch (err) {
status.setDefaultDb({
transaction: txData,
calculatedFee: "0",
feeExplanation: "",
sliderValue: sliderValue
});
}
return {
title: I18n.t('send_title'),
showBack: true,

View File

@ -1,54 +1,45 @@
(ns status-im.bots.events
(:require [re-frame.core :as re-frame]
[status-im.utils.handlers :as handlers]))
[status-im.utils.handlers :as handlers]
[status-im.chat.models.input :as input-model]
[taoensso.timbre :as log]))
;;;; Helper fns
(defn- chats-with-bot [chats bot]
(reduce (fn [acc [_ {:keys [chat-id contacts]}]]
(let [contacts (map :identity contacts)]
(if (some #{bot} contacts)
(conj acc chat-id)
acc)))
[]
chats))
(defn- subscription-values [subscriptions current-bot-db]
(reduce (fn [sub-values [sub-name sub-path]]
(assoc sub-values sub-name (get-in current-bot-db sub-path)))
(defn- subscription-values [sub-params current-bot-db]
(reduce (fn [sub-values [sub-key sub-path]]
(assoc sub-values sub-key (get-in current-bot-db sub-path)))
{}
subscriptions))
sub-params))
;; TODO(janherich): optimze this, for sure we don't need to re-calculate all bot subscriptions every time something in bot db changes
;; TODO(janherich): do this properly instead of the ugly hack with hardcoded bot-db key
;; und uneffective lookup of the owner of selected-chat-command
(defn- check-subscriptions-fx
[db {:keys [bot path value]}]
(let [{:keys [bot-db chats]} db
subscriptions (get-in db [:bot-subscriptions path])]
{:call-jail-function-n
(for [{:keys [bot subscriptions name]} subscriptions
:let [subs-values (subscription-values subscriptions (get bot-db bot))]]
{:chat-id bot
:function :subscription
:parameters {:name name
:subscriptions subs-values}
:callback-events-creator (fn [jail-response]
(into [[::calculated-subscription
{:bot bot
:path [name]
:result jail-response}]]
(map (fn [chat-id]
[::calculated-subscription
{:bot chat-id
:path [name]
:result jail-response}])
(chats-with-bot chats bot))))})}))
[{:keys [bot-db bot-subscriptions chats current-chat-id] :as app-db} path]
(let [owner-id (some-> app-db
(input-model/selected-chat-command current-chat-id (get-in app-db [:chats current-chat-id :input-text]))
:command
:owner-id)]
(when-let [subscriptions (and owner-id (get-in bot-subscriptions (concat [owner-id] [path])))]
{:call-jail-function-n
(for [[sub-name sub-params] subscriptions]
{:chat-id owner-id
:function :subscription
:parameters {:name sub-name
:subscriptions (subscription-values sub-params
(get bot-db current-chat-id))}
:callback-events-creator (fn [jail-response]
[[::calculated-subscription
{:bot current-chat-id
:path [sub-name]
:result jail-response}]])})})))
(defn set-in-bot-db
[{:keys [current-chat-id] :as app-db} {:keys [bot path value] :as params}]
(let [bot (or bot current-chat-id)
new-db (assoc-in app-db (concat [:bot-db bot] path) value)]
(merge {:db new-db}
(check-subscriptions-fx new-db params))))
(check-subscriptions-fx new-db path))))
(defn update-bot-db
[{:keys [current-chat-id] :as app-db} {:keys [bot db]}]
@ -59,6 +50,28 @@
[{:keys [current-chat-id] :as app-db}]
(assoc-in app-db [:bot-db current-chat-id] nil))
(def ^:private keywordize-vector (partial mapv keyword))
;; TODO(janherich): do something with this horrible triple nested reduce so it's more readable
(defn add-active-bot-subscriptions
[app-db bot-identities]
(let [relevant-bots (select-keys (:contacts/contacts app-db) bot-identities)
active-subscriptions (reduce (fn [acc [bot-id {:keys [subscriptions]}]]
(reduce (fn [acc [sub-key {:keys [subscriptions]}]]
(reduce (fn [acc [sub-param-key sub-param-path]]
(update-in acc [bot-id (keywordize-vector sub-param-path)]
assoc sub-key (into {}
(map (fn [[k v]]
[k (keywordize-vector v)]))
subscriptions)))
acc
subscriptions))
acc
subscriptions))
{}
relevant-bots)]
(assoc app-db :bot-subscriptions active-subscriptions)))
;;;; Handlers
(handlers/register-handler-fx
@ -73,21 +86,6 @@
(fn [db [params]]
(update-bot-db db params)))
(handlers/register-handler-db
:register-bot-subscription
[re-frame/trim-v]
(fn [db [{:keys [bot subscriptions] :as opts}]]
(reduce
(fn [db [sub-name sub-path]]
(let [keywordized-sub-path (mapv keyword
(if (coll? sub-path)
sub-path
[sub-path]))]
(update-in db [:bot-subscriptions keywordized-sub-path] conj
(assoc-in opts [:subscriptions sub-name] keywordized-sub-path))))
db
subscriptions)))
(handlers/register-handler-db
::calculated-subscription
[re-frame/trim-v]

View File

@ -1,12 +1,6 @@
(ns status-im.bots.subs
(:require [re-frame.core :refer [reg-sub subscribe]]))
(reg-sub
:bot-subscription
(fn [db [_ path]]
(let [chat-id (subscribe [:get-current-chat-id])]
(get-in db (concat [:bot-db @chat-id] path)))))
(reg-sub
:current-bot-db
(fn [db]

View File

@ -46,6 +46,10 @@
;;;; Helper functions
(defn- extract-command-request-owners [commands requests]
[commands requests]
(into #{} (keep :owner-id) (concat commands requests)))
(defn update-suggestions
"Update suggestions for current chat input, takes db as the only argument
and returns map with keys :db (new db with up-to-date suggestions) and (optionally)
@ -58,9 +62,14 @@
(= type :grant-permissions))))
commands (commands-model/commands-for-chat db current-chat-id)
{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])
new-db (cond-> db
true (assoc-in [:chats current-chat-id :possible-requests] requests)
true (assoc-in [:chats current-chat-id :possible-commands] commands)
;; TODO(janherich) surely there is a better place to merge in possible commands/request/subscriptions into current chat
;; then in `:update-suggestions` which is called whenever commands for chat are loaded, chat view is opened
;; or new message is received from network - it's unnecessary to call it as a response to last two events
new-db (cond-> (-> db
(update-in [:chats current-chat-id] merge {:possible-commands commands
:possible-requests requests})
(bots-events/add-active-bot-subscriptions (extract-command-request-owners
commands requests)))
(and dapp?
(str/blank? chat-text))
(assoc-in [:chats current-chat-id :parameter-boxes :message] nil))]
@ -90,12 +99,12 @@
(let [chat-text (str/trim (or (get-in chats [current-chat-id :input-text]) ""))
{:keys [dapp?]} (get-in db [:contacts/contacts current-chat-id])]
(cond-> {:db db}
(and dapp? (not (str/blank? chat-text)))
(assoc :call-jail-function {:chat-id current-chat-id
:function :on-message-input-change
:parameters {:message chat-text}
:context {:data (get local-storage current-chat-id)
:from current-account-id}}))))
(and dapp? (not (str/blank? chat-text)))
(assoc :call-jail-function {:chat-id current-chat-id
:function :on-message-input-change
:parameters {:message chat-text}
:context {:data (get local-storage current-chat-id)
:from current-account-id}}))))
(defn set-chat-input-metadata
"Set input metadata for active chat. Takes db and metadata and returns updated db."
@ -193,14 +202,14 @@
(load-chat-parameter-box new-db (:command command)))]
(cond-> {:db new-db}
chat-parameter-box-fx
(merge chat-parameter-box-fx)
chat-parameter-box-fx
(merge chat-parameter-box-fx)
(and (= selection (+ (count const/command-char)
(count (get-in command [:command :name]))
(count const/spacing-char)))
(get-in command [:command :sequential-params]))
(merge (chat-input-focus new-db :seq-input-ref)))))
(and (= selection (+ (count const/command-char)
(count (get-in command [:command :name]))
(count const/spacing-char)))
(get-in command [:command :sequential-params]))
(merge (chat-input-focus new-db :seq-input-ref)))))
(defn select-chat-input-command
"Selects command + (optional) arguments as input for active chat"
@ -221,19 +230,19 @@
(input-model/join-command-args prefill)))))
fx (assoc (load-chat-parameter-box db' command) :db db')]
(cond-> fx
prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db})
prefill-bot-db (update :db bots-events/update-bot-db {:db prefill-bot-db})
(not (and sequential-params
prevent-auto-focus?))
(merge (chat-input-focus (:db fx) :input-ref))
(not (and sequential-params
prevent-auto-focus?))
(merge (chat-input-focus (:db fx) :input-ref))
sequential-params
(as-> fx'
(cond-> (update fx' :db
set-chat-seq-arg-input-text
(str/join const/spacing-char prefill))
(not prevent-auto-focus?)
(merge fx' (chat-input-focus (:db fx') :seq-input-ref)))))))
sequential-params
(as-> fx'
(cond-> (update fx' :db
set-chat-seq-arg-input-text
(str/join const/spacing-char prefill))
(not prevent-auto-focus?)
(merge fx' (chat-input-focus (:db fx') :seq-input-ref)))))))
(defn set-contact-as-command-argument
"Sets contact as command argument for active chat"

View File

@ -3,7 +3,7 @@
[status-im.utils.handlers :as handlers]
[status-im.utils.utils :refer [show-popup]]
[status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [generate-hiccup reg-handler]]
[status-im.commands.utils :refer [reg-handler]]
[clojure.string :as s]
[status-im.components.react :as r]
[status-im.constants :refer [console-chat-id]]

View File

@ -182,13 +182,7 @@
(reg-handler ::add-commands
[(after (fn [_ [id]]
(dispatch [:invoke-commands-loading-callbacks id])
(dispatch [:invoke-chat-loaded-callbacks id])))
(after (fn [{:contacts/keys [contacts]} [id]]
(let [subscriptions (get-in contacts [id :subscriptions])]
(doseq [[name opts] subscriptions]
(dispatch [:register-bot-subscription
(assoc opts :bot id
:name name)])))))
(dispatch [:invoke-chat-loaded-callbacks id])))
(after #(dispatch [:update-suggestions]))]
add-commands)

View File

@ -4,7 +4,7 @@
(:require [status-im.components.react :as r]
[re-frame.core :refer [dispatch]]
[taoensso.timbre :as log]
[cljs.core.async :refer [<! timeout]]
[cljs.core.async :as async :refer [<! timeout]]
[status-im.utils.js-resources :as js-res]
[status-im.utils.platform :as p]
[status-im.utils.scheduler :as scheduler]
@ -126,9 +126,10 @@
(defn execute-call [{:keys [jail-id path params callback]}]
(when status
(call-module
#(do
#(do
(log/debug :call-jail :jail-id jail-id)
(log/debug :call-jail :path path)
(log/debug :call-jail :params params)
;; this debug message can contain sensitive info
#_(log/debug :call-jail :params params)
(let [params' (update params :context assoc
@ -154,7 +155,8 @@
(defn remove-duplicate-calls
"Removes duplicates by [jail path] keys, remains the last one."
[[all-keys calls] {:keys [jail-id path] :as call}]
(if (contains? all-keys [jail-id path])
(if (and (contains? all-keys [jail-id path])
(not= (second path) :subscription))
[all-keys calls]
[(conj all-keys [jail-id path])
(conj calls call)]))
@ -167,7 +169,7 @@
(let [[_ new-calls] (reduce remove-duplicate-calls [#{} '()] @raw-jail-calls)]
(reset! raw-jail-calls '())
(swap! jail-calls (fn [old-calls]
(concat new-calls old-calls))))
(concat new-calls old-calls))))
(recur (<! (timeout check-raw-calls-interval)))))
(defn execute-calls-loop!
@ -175,8 +177,8 @@
which reduces chances of response shuffling"
[]
(go-loop [_ nil]
(let [next-call (last @jail-calls)]
(swap! jail-calls butlast)
(let [next-call (first @jail-calls)]
(swap! jail-calls rest)
(when next-call
(execute-call next-call)))
(recur (<! (timeout interval-between-calls)))))