Merge pull request #359 from status-im/feature/#218

Rework transactions sending

Former-commit-id: 8011213ee9
This commit is contained in:
Roman Volosovskyi 2016-10-19 09:40:13 +03:00 committed by GitHub
commit 9cd0a61a29
20 changed files with 348 additions and 159 deletions

View File

@ -14,5 +14,5 @@ android {
dependencies { dependencies {
compile 'com.facebook.react:react-native:+' compile 'com.facebook.react:react-native:+'
compile(group: 'status-im', name: 'status-go', version: '0.1.1', ext: 'aar') compile(group: 'status-im', name: 'status-go', version: 'test-jcp6', ext: 'aar')
} }

View File

@ -5,12 +5,15 @@ import android.content.Intent;
import android.os.*; import android.os.*;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import java.util.concurrent.Callable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import com.github.status_im.status_go.cmd.Statusgo; import com.github.status_im.status_go.cmd.Statusgo;
import java.io.File; import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class StatusService extends Service { public class StatusService extends Service {
@ -19,6 +22,8 @@ public class StatusService extends Service {
private static boolean isNodeInitialized = false; private static boolean isNodeInitialized = false;
private final Handler handler = new Handler(); private final Handler handler = new Handler();
private ExecutorService executor = null;
private static String dataFolder; private static String dataFolder;
private static Messenger applicationMessenger = null; private static Messenger applicationMessenger = null;
@ -74,6 +79,9 @@ public class StatusService extends Service {
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (executor != null) {
executor.shutdownNow();
}
//TODO: stop geth //TODO: stop geth
stopNode(null); stopNode(null);
//isNodeInitialized = false; //isNodeInitialized = false;
@ -83,6 +91,9 @@ public class StatusService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if (executor == null) {
executor = Executors.newCachedThreadPool();
}
return Service.START_STICKY; return Service.START_STICKY;
} }
@ -155,7 +166,11 @@ public class StatusService extends Service {
Statusgo.StartNode(dataFolder); Statusgo.StartNode(dataFolder);
Log.d(TAG, "Geth node started"); Log.d(TAG, "Geth node started");
Log.w(TAG, "adding peer"); Log.w(TAG, "adding peer");
Statusgo.AddPeer("enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303");
Statusgo.AddPeer("enode://efe4e6899e05237180c0970aedb81cb5aecf5b200779c7c9e1f955783e8299b364c0b981c03f4c36ad5328ef972b417afde260bbf2c5a8db37ba7f5738033952@198.199.105.122:30303");
Statusgo.AddPeer("enode://5a5839435f48d1e3f2f907e4582f0a134e0b7857afe507073978ca32cf09ea54989dac433605047d0bc4cd19a8c80affac6876069014283aa7c7bb4954d0e623@95.85.40.211:30303");
Statusgo.AddPeer("enode://2f05d430b4cb1c0e2a0772d48da3a034f1b596ea7163ab80d3404802d10b7d55bde323897c2be0d36026181e1a68510ea1f42a646ef9494c27e61f61e4088b7d@188.166.229.119:30303");
Statusgo.AddPeer("enode://ad61a21f83f12b0ca494611650f5e4b6427784e7c62514dcb729a3d65106de6f12836813acf39bdc35c12ecfd0e230723678109fd4e7091ce389697bd7da39b4@139.59.212.114:30303");
isNodeInitialized = true; isNodeInitialized = true;
} }
createAndSendReply(message, StatusMessages.MSG_START_NODE, null); createAndSendReply(message, StatusMessages.MSG_START_NODE, null);
@ -256,12 +271,45 @@ public class StatusService extends Service {
String chatId = data.getString("chatId"); String chatId = data.getString("chatId");
String path = data.getString("path"); String path = data.getString("path");
String params = data.getString("params"); String params = data.getString("params");
String callbackIdentifier = data.getString(StatusConnector.CALLBACK_IDENTIFIER);
String result = Statusgo.Call(chatId, path, params); Log.d(TAG, "Before StatusGo.Call");
Callable<String> callable = new JailRequest(message.replyTo, chatId, path, params, callbackIdentifier);
executor.submit(callable);
}
public class JailRequest implements Callable<String> {
String chatId;
String path;
String params;
String callbackIdentifier;
Messenger messenger;
JailRequest(Messenger messenger, String chatId, String path, String params, String callbackIdentifier) {
this.messenger = messenger;
this.chatId = chatId;
this.path = path;
this.params = params;
this.callbackIdentifier = callbackIdentifier;
}
public String call() throws Exception {
Log.d(TAG, "StatusGo.Call");
String result = Statusgo.Call(chatId, path, params);
Bundle replyData = new Bundle();
replyData.putString("data", result);
Message replyMessage = Message.obtain(null, StatusMessages.MSG_JAIL_CALL, 0, 0, null);
Log.d(TAG, "Callback identifier: " + callbackIdentifier);
replyData.putString(StatusConnector.CALLBACK_IDENTIFIER, callbackIdentifier);
replyMessage.setData(replyData);
sendReply(messenger, replyMessage);
return result;
}
Bundle replyData = new Bundle();
replyData.putString("data", result);
createAndSendReply(message, StatusMessages.MSG_JAIL_CALL, replyData);
} }
public static boolean isNodeInitialized() { public static boolean isNodeInitialized() {

View File

@ -3,4 +3,4 @@
#import "RCTLog.h" #import "RCTLog.h"
@interface Status : NSObject <RCTBridgeModule> @interface Status : NSObject <RCTBridgeModule>
@end @end

View File

@ -1,12 +1,22 @@
#import "RCTStatus.h" #import "RCTStatus.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import <Statusgo/Statusgo.h> #import <Statusgo/Statusgo.h>
static bool isStatusInitialized; static bool isStatusInitialized;
static RCTBridge *bridge;
@implementation Status{ @implementation Status{
} }
-(RCTBridge *)bridge
{
return bridge;
}
-(void)setBridge:(RCTBridge *)newBridge
{
bridge = newBridge;
}
RCT_EXPORT_MODULE(); RCT_EXPORT_MODULE();
@ -41,8 +51,12 @@ RCT_EXPORT_METHOD(callJail:(NSString *)chatId
#if DEBUG #if DEBUG
NSLog(@"CallJail() method called"); NSLog(@"CallJail() method called");
#endif #endif
char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]); dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
callback(@[[NSString stringWithUTF8String: result]]); char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]);
dispatch_async( dispatch_get_main_queue(), ^{
callback(@[[NSString stringWithUTF8String: result]]);
});
});
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -68,8 +82,9 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
NSLog(@"error %@", error); NSLog(@"error %@", error);
}else }else
NSLog(@"folderName: %@", folderName); NSLog(@"folderName: %@", folderName);
NSString *peer = @"enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303"; NSString *peer1 = @"enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303";
NSString *peer2 = @"enode://ad61a21f83f12b0ca494611650f5e4b6427784e7c62514dcb729a3d65106de6f12836813acf39bdc35c12ecfd0e230723678109fd4e7091ce389697bd7da39b4@139.59.212.114:30303";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) { ^(void) {
StartNode((char *) [folderName.path UTF8String]); StartNode((char *) [folderName.path UTF8String]);
@ -77,7 +92,8 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) { ^(void) {
AddPeer((char *) [peer UTF8String]); AddPeer((char *) [peer1 UTF8String]);
AddPeer((char *) [peer2 UTF8String]);
}); });
onResultCallback(@[[NSNull null]]); onResultCallback(@[[NSNull null]]);
return; return;
@ -161,4 +177,15 @@ RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
#endif #endif
} }
+ (void)signalEvent:(char *) signal
{
NSString *sig = [NSString stringWithUTF8String:signal];
#if DEBUG
NSLog(@"SignalEvent");
NSLog(sig);
#endif
[bridge.eventDispatcher sendAppEventWithName:@"gethEvent"
body:@{@"jsonEvent": sig}];
}
@end @end

View File

@ -25,7 +25,7 @@
<artifactItem> <artifactItem>
<groupId>status-im</groupId> <groupId>status-im</groupId>
<artifactId>status-go-ios</artifactId> <artifactId>status-go-ios</artifactId>
<version>0.1.2</version> <version>ios-signals</version>
<type>zip</type> <type>zip</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory>./</outputDirectory> <outputDirectory>./</outputDirectory>

View File

@ -3,7 +3,7 @@
:url "http://example.com/FIXME" :url "http://example.com/FIXME"
:license {:name "Eclipse Public License" :license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"} :url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0-alpha12"] :dependencies [[org.clojure/clojure "1.9.0-alpha13"]
[org.clojure/clojurescript "1.9.229"] [org.clojure/clojurescript "1.9.229"]
[reagent "0.5.1" :exclusions [cljsjs/react]] [reagent "0.5.1" :exclusions [cljsjs/react]]
[re-frame "0.7.0"] [re-frame "0.7.0"]

View File

@ -62,8 +62,8 @@ status.command({
}] }]
}); });
function validateBalance(params) { function validateBalance(params, context) {
if(!params.value){ if (!params.amount) {
return { return {
errors: [ errors: [
status.components.validationMessage( status.components.validationMessage(
@ -75,19 +75,19 @@ function validateBalance(params) {
} }
try { try {
var val = web3.toWei(params.value, "ether"); var val = web3.toWei(params.amount, "ether");
} catch (err) { } catch (err) {
return { return {
errors: [ errors: [
status.components.validationMessage( status.components.validationMessage(
"Amount", "Amount",
"Amount is not valid number"//err.message "Amount is not valid number"
) )
] ]
}; };
} }
var balance = web3.eth.getBalance(params.command.address); var balance = web3.eth.getBalance(context.from);
if (bn(val).greaterThan(bn(balance))) { if (bn(val).greaterThan(bn(balance))) {
return { return {
errors: [ errors: [
@ -102,15 +102,18 @@ function validateBalance(params) {
} }
} }
function sendTransaction(params) { function sendTransaction(params, context) {
var data = { var data = {
from: params.command.from, from: context.from,
to: params.command.to, to: context.to,
value: web3.toWei(params.value, "ether") value: web3.toWei(params.amount, "ether")
}; };
var hash = web3.eth.sendTransaction(data);
return {"transaction-hash": hash}; try {
return web3.eth.sendTransaction(data);
} catch (err) {
return {error: err};
}
} }
status.command({ status.command({
@ -124,7 +127,7 @@ status.command({
preview: function (params) { preview: function (params) {
return status.components.text( return status.components.text(
{}, {},
params.value + " ETH" params.amount + " ETH"
); );
}, },
handler: sendTransaction, handler: sendTransaction,

View File

@ -1,7 +1,8 @@
var _status_catalog = { var _status_catalog = {
commands: {}, commands: {},
responses: {} responses: {}
}; },
status = {};
function Command() { function Command() {
} }
@ -44,10 +45,25 @@ Response.prototype.onReceiveResponse = function (handler) {
this.onReceive = handler; this.onReceive = handler;
}; };
var context = {}
function addContext(ns, key, value) {
context[ns][key] = value;
}
function call(pathStr, paramsStr) { function call(pathStr, paramsStr) {
var params = JSON.parse(paramsStr), var params = JSON.parse(paramsStr),
path = JSON.parse(pathStr), path = JSON.parse(pathStr),
fn, res; fn, callResult, message_id;
if (typeof params.context !== "undefined" &&
typeof params.context["message-id"] !== "undefined") {
message_id = params.context["message-id"];
} else {
message_id = null;
}
context[message_id] = {};
status.message_id = message_id;
fn = path.reduce(function (catalog, name) { fn = path.reduce(function (catalog, name) {
if (catalog && catalog[name]) { if (catalog && catalog[name]) {
@ -61,9 +77,13 @@ function call(pathStr, paramsStr) {
return null; return null;
} }
res = fn(params.parameters, params.context); callResult = fn(params.parameters, params.context);
result = {
returned: callResult,
context: context[message_id]
};
return JSON.stringify(res); return JSON.stringify(result);
} }
function text(options, s) { function text(options, s) {

View File

@ -275,11 +275,13 @@
[{:keys [current-chat-id] :as db} [_ _ id]] [{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id) (let [chat-id (or id current-chat-id)
messages (get-in db [:chats chat-id :messages]) messages (get-in db [:chats chat-id :messages])
db' (assoc db :current-chat-id chat-id)] db' (assoc db :current-chat-id chat-id)
commands-loaded? (get-in db [:chats chat-id :commands-loaded])]
(when (= current-chat-id wallet-chat-id) (when (= current-chat-id wallet-chat-id)
(dispatch [:cancel-command])) (dispatch [:cancel-command]))
(dispatch [:load-requests! chat-id]) (dispatch [:load-requests! chat-id])
(dispatch [:load-commands! chat-id]) (when-not commands-loaded?
(dispatch [:load-commands! chat-id]))
(if (and (seq messages) (if (and (seq messages)
(not= (count messages) 1)) (not= (count messages) 1))
db' db'

View File

@ -91,7 +91,7 @@
(fn [_ [_ {:keys [chat-id handler]} {:keys [error result]}]] (fn [_ [_ {:keys [chat-id handler]} {:keys [error result]}]]
;; todo handle error ;; todo handle error
(when-not error (when-not error
(let [{:keys [errors validationHandler parameters]} result] (let [{:keys [errors validationHandler parameters]} (:returned result)]
(cond errors (cond errors
(dispatch [::add-validation-errors chat-id errors]) (dispatch [::add-validation-errors chat-id errors])
@ -128,6 +128,7 @@
:id (random/id)}] :id (random/id)}]
(-> db (-> db
(commands/stage-command command-info) (commands/stage-command command-info)
(assoc-in [:command->chat (:id command-info)] chat-id)
(assoc :staged-command command-info) (assoc :staged-command command-info)
(assoc-in [:disable-staging chat-id] true))))) (assoc-in [:disable-staging chat-id] true)))))
@ -225,7 +226,7 @@
(register-handler ::start-command-validation! (register-handler ::start-command-validation!
(u/side-effect! (u/side-effect!
(fn [db [_ {:keys [command-input chat-id] :as data}]] (fn [db [_ {:keys [command-input chat-id address] :as data}]]
(let [command-input' (or command-input (commands/get-command-input db)) (let [command-input' (or command-input (commands/get-command-input db))
{:keys [parameter-idx params command]} command-input' {:keys [parameter-idx params command]} command-input'
{:keys [name type]} command {:keys [name type]} command
@ -233,7 +234,8 @@
:params :params
(get parameter-idx) (get parameter-idx)
:name) :name)
context {:current-parameter current-parameter} context {:current-parameter current-parameter
:from address}
path [(if (= :command type) :commands :responses) path [(if (= :command type) :commands :responses)
name name
:validator] :validator]

View File

@ -16,14 +16,16 @@
[taoensso.timbre :refer-macros [debug]])) [taoensso.timbre :refer-macros [debug]]))
(defn prepare-command (defn prepare-command
[identity chat-id {:keys [preview preview-string params command to-message]}] [identity chat-id
{:keys [id preview preview-string params command to-message handler-data]}]
(let [content {:command (command :name) (let [content {:command (command :name)
:params params}] :params params}]
{:message-id (random/id) {:message-id id
:from identity :from identity
:to chat-id :to chat-id
:timestamp (time/now-ms) :timestamp (time/now-ms)
:content (assoc content :preview preview-string) :content (assoc content :preview preview-string
:handler-data handler-data)
:content-type content-type-command :content-type content-type-command
:outgoing true :outgoing true
:preview preview-string :preview preview-string
@ -55,7 +57,9 @@
(fn [_ [_ {:keys [commands message] :as params}]] (fn [_ [_ {:keys [commands message] :as params}]]
(doseq [{:keys [command] :as message} commands] (doseq [{:keys [command] :as message} commands]
(let [params' (assoc params :staged-command message)] (let [params' (assoc params :staged-command message)]
(if (:sending message) (if (:sent-to-jail? message)
;; todo there could be other reasons for "long-running"
;; hanling of the command besides sendTransaction
(dispatch [:navigate-to :confirm]) (dispatch [:navigate-to :confirm])
(if (:has-handler command) (if (:has-handler command)
(dispatch [::invoke-command-handlers! params']) (dispatch [::invoke-command-handlers! params'])
@ -71,16 +75,18 @@
(register-handler :prepare-command! (register-handler :prepare-command!
(u/side-effect! (u/side-effect!
(fn [{:keys [current-public-key] :as db} (fn [{:keys [current-public-key] :as db}
[_ {:keys [chat-id staged-command] :as params}]] [_ {:keys [chat-id staged-command handler-data] :as params}]]
(let [command' (->> staged-command (let [command' (->> (assoc staged-command :handler-data handler-data)
(prepare-command current-public-key chat-id) (prepare-command current-public-key chat-id)
(cu/check-author-direction db chat-id))] (cu/check-author-direction db chat-id))]
(dispatch [::clear-command chat-id (:id staged-command)]) (dispatch [:clear-command chat-id (:id staged-command)])
(dispatch [::send-command! (assoc params :command command')]))))) (dispatch [::send-command! (assoc params :command command')])))))
(register-handler ::clear-command (register-handler :clear-command
(fn [db [_ chat-id id]] (fn [db [_ chat-id id]]
(update-in db [:chats chat-id :staged-commands] dissoc id))) (if chat-id
(update-in db [:chats chat-id :staged-commands] dissoc id)
db)))
(register-handler ::send-command! (register-handler ::send-command!
(u/side-effect! (u/side-effect!
@ -112,20 +118,28 @@
(register-handler ::invoke-command-handlers! (register-handler ::invoke-command-handlers!
(u/side-effect! (u/side-effect!
(fn [db [_ {:keys [chat-id address staged-command] :as parameters}]] (fn [db [_ {:keys [chat-id address staged-command]
(let [{:keys [command params]} staged-command :as parameters}]]
(let [{:keys [id command params]} staged-command
{:keys [type name]} command {:keys [type name]} command
path [(if (= :command type) :commands :responses) path [(if (= :command type) :commands :responses)
name name
:handler] :handler]
to (get-in db [:contacts chat-id :address]) to (get-in db [:contacts chat-id :address])
params {:parameters params params {:parameters params
:context {:from address :context {:from address
:to to}}] :to to
(status/call-jail chat-id :message-id id}}]
path (dispatch [::command-in-processing chat-id id])
params (status/call-jail
#(dispatch [:command-handler! chat-id parameters %])))))) chat-id
path
params
#(dispatch [:command-handler! chat-id parameters %]))))))
(register-handler ::command-in-processing
(fn [db [_ chat-id id]]
(assoc-in db [:chats chat-id :staged-commands id :sent-to-jail?] true)))
(register-handler ::prepare-message (register-handler ::prepare-message
(u/side-effect! (u/side-effect!

View File

@ -134,7 +134,7 @@
(defview messages-view [group-chat] (defview messages-view [group-chat]
[messages [:chat :messages] [messages [:chat :messages]
contacts [:chat :contacts] contacts [:chat :contacts]
loaded? [:all-messages-loaded?]] loaded? [:all-messages-loaded?]]
(let [contacts' (contacts-by-identity contacts) (let [contacts' (contacts-by-identity contacts)
messages (messages-with-timemarks messages)] messages (messages-with-timemarks messages)]
[list-view {:renderRow (fn [row _ index] [list-view {:renderRow (fn [row _ index]
@ -155,11 +155,11 @@
(anim/start (anim/spring val {:toValue @offset})))) (anim/start (anim/spring val {:toValue @offset}))))
(defn messages-container [messages] (defn messages-container [messages]
(let [offset (subscribe [:messages-offset]) (let [offset (subscribe [:messages-offset])
messages-offset (anim/create-value 0) messages-offset (anim/create-value 0)
context {:offset offset context {:offset offset
:val messages-offset} :val messages-offset}
on-update (messages-container-animation-logic context)] on-update (messages-container-animation-logic context)]
(r/create-class (r/create-class
{:component-did-mount {:component-did-mount
on-update on-update
@ -172,11 +172,11 @@
messages])}))) messages])})))
(defn chat [] (defn chat []
(let [group-chat (subscribe [:chat :group-chat]) (let [group-chat (subscribe [:chat :group-chat])
show-actions? (subscribe [:chat-ui-props :show-actions?]) show-actions? (subscribe [:chat-ui-props :show-actions?])
show-bottom-info? (subscribe [:chat-ui-props :show-bottom-info?]) show-bottom-info? (subscribe [:chat-ui-props :show-bottom-info?])
command? (subscribe [:command?]) command? (subscribe [:command?])
layout-height (subscribe [:get :layout-height])] layout-height (subscribe [:get :layout-height])]
(r/create-class (r/create-class
{:component-did-mount #(dispatch [:check-autorun]) {:component-did-mount #(dispatch [:check-autorun])
:reagent-render :reagent-render

View File

@ -10,11 +10,6 @@
[status-im.constants :refer [console-chat-id]] [status-im.constants :refer [console-chat-id]]
[taoensso.timbre :as log])) [taoensso.timbre :as log]))
(defn init-render-command!
[_ [chat-id command message-id data]]
(status/call-jail chat-id [command :render] data
#(dispatch [::render-command chat-id message-id %])))
(defn render-command (defn render-command
[db [chat-id message-id markup]] [db [chat-id message-id markup]]
(let [hiccup (generate-hiccup markup)] (let [hiccup (generate-hiccup markup)]
@ -31,28 +26,40 @@
(def regular-events {}) (def regular-events {})
(defn command-hadler! (defn command-hadler!
[_ [chat-id {:keys [command] :as parameters} {:keys [result error]}]] [_ [chat-id
(cond {:keys [staged-command] :as parameters}
result {:keys [result error]}]]
(let [{:keys [event params transaction-hash]} result (let [{:keys [context returned]} result
command' (assoc command :handler-data result) {:keys [event params]
parameters' (assoc parameters :command command')] handler-error :error} returned]
(if transaction-hash (cond
(dispatch [:wait-for-transaction transaction-hash parameters']) handler-error
(let [events (if (= console-chat-id chat-id) (log/debug :error-from-handler handler-error
(merge regular-events console-events) :chat-id chat-id
regular-events) :command staged-command)
parameters'' (if-let [handler (events (keyword event))]
(assoc parameters' :handler #(handler params command')) result
parameters')] (let [{:keys [event params]} returned
(dispatch [:prepare-command! parameters''])))) command' (assoc staged-command :handler-data returned)
(not error) parameters' (assoc parameters :command command')]
(dispatch [:prepare-command! parameters]) (if (:eth_sendTransaction context)
:else nil)) (dispatch [:wait-for-transaction (:id staged-command) parameters'])
(let [events (if (= console-chat-id chat-id)
(merge regular-events console-events)
regular-events)
parameters'' (if-let [handler (events (keyword event))]
(assoc parameters' :handler #(handler params command'))
parameters')]
(dispatch [:prepare-command! parameters'']))))
(not (or error handler-error))
(dispatch [:prepare-command! parameters])
:else nil)))
(defn suggestions-handler! (defn suggestions-handler!
[db [{:keys [chat-id]} {:keys [result]}]] [db [{:keys [chat-id]} {:keys [result]}]]
(let [{:keys [markup webViewUrl]} result (let [{:keys [markup webViewUrl]} (:returned result)
hiccup (generate-hiccup markup)] hiccup (generate-hiccup markup)]
(-> db (-> db
(assoc-in [:suggestions chat-id] (generate-hiccup markup)) (assoc-in [:suggestions chat-id] (generate-hiccup markup))
@ -68,12 +75,13 @@
(defn command-preview (defn command-preview
[db [chat-id command-id {:keys [result]}]] [db [chat-id command-id {:keys [result]}]]
(if result (let [result' (:returned result)]
(let [path [:chats chat-id :staged-commands command-id]] (if result'
(update-in db path assoc (let [path [:chats chat-id :staged-commands command-id]]
:preview (generate-hiccup result) (update-in db path assoc
:preview-string (str result))) :preview (generate-hiccup result')
db)) :preview-string (str result')))
db)))
(defn print-error-message! [message] (defn print-error-message! [message]
(fn [_ params] (fn [_ params]
@ -81,7 +89,6 @@
(show-popup "Error" (s/join "\n" [message params])) (show-popup "Error" (s/join "\n" [message params]))
(log/debug message params)))) (log/debug message params))))
(reg-handler :init-render-command! init-render-command!)
(reg-handler ::render-command render-command) (reg-handler ::render-command render-command)
(reg-handler :command-handler! (reg-handler :command-handler!
@ -93,6 +100,8 @@
(after (print-error-message! "Error on param suggestions")) (after (print-error-message! "Error on param suggestions"))
(after (fn [_ [{:keys [command]}]] (after (fn [_ [{:keys [command]}]]
(when (= :on-send (keyword (:suggestions-trigger command))) (when (= :on-send (keyword (:suggestions-trigger command)))
#_(when (:webViewUrl (:returned result))
(dispatch [:set-soft-input-mode :pan]))
(r/dismiss-keyboard!))))] (r/dismiss-keyboard!))))]
suggestions-handler!) suggestions-handler!)
(reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!)) (reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!))

View File

@ -35,6 +35,7 @@
(defn complete-transaction (defn complete-transaction
[hash password callback] [hash password callback]
(log/debug :complete-transaction (boolean status) hash password)
(when status (when status
(.completeTransaction status hash password callback))) (.completeTransaction status hash password callback)))

View File

@ -102,6 +102,7 @@
(register-handler :signal-event (register-handler :signal-event
(u/side-effect! (u/side-effect!
(fn [_ [_ event-str]] (fn [_ [_ event-str]]
(log/debug :event-str event-str)
(let [{:keys [type event]} (t/json->clj event-str)] (let [{:keys [type event]} (t/json->clj event-str)]
(case type (case type
"transaction.queued" (dispatch [:transaction-queued event]) "transaction.queued" (dispatch [:transaction-queued event])

View File

@ -15,6 +15,7 @@
[status-im.chat.screen :refer [chat]] [status-im.chat.screen :refer [chat]]
[status-im.accounts.login.screen :refer [login]] [status-im.accounts.login.screen :refer [login]]
[status-im.accounts.screen :refer [accounts]] [status-im.accounts.screen :refer [accounts]]
[status-im.transactions.screen :refer [confirm]]
[status-im.chats-list.screen :refer [chats-list]] [status-im.chats-list.screen :refer [chats-list]]
[status-im.new-group.screen :refer [new-group]] [status-im.new-group.screen :refer [new-group]]
[status-im.participants.views.add :refer [new-participants]] [status-im.participants.views.add :refer [new-participants]]
@ -83,6 +84,7 @@
:profile-photo-capture profile-photo-capture :profile-photo-capture profile-photo-capture
:accounts accounts :accounts accounts
:login login :login login
:confirm confirm
:my-profile my-profile)] :my-profile my-profile)]
[component]))))}))) [component]))))})))

View File

@ -6,45 +6,62 @@
[status-im.utils.types :as t] [status-im.utils.types :as t]
[status-im.components.status :as status] [status-im.components.status :as status]
cljsjs.web3 cljsjs.web3
[clojure.string :as s])) [clojure.string :as s]
[taoensso.timbre :as log]))
;; flow:
;; :accept-transactions
;; ↓
;; :transaction-completed
;; ↓
;; ::remove-transaction && [:set :wrong-password? false] <- on error
;; ::remove-transaction <- when transaction is
;; not from the jail
;; ::add-transactions-hash
;; && ::check-completed-transaction!
;; && :navigation-replace <- on success
(defmethod nav/preload-data! :confirm (defmethod nav/preload-data! :confirm
[{:keys [transactions-queue] :as db} _] [{:keys [transactions-queue] :as db} _]
(assoc db :transactions transactions-queue)) (assoc db :transactions transactions-queue))
(defn on-unlock (defn on-unlock
[hashes password] [ids password previous-view-id]
;; todo: add message about wrong password (dispatch [:set :wrong-password? false])
(do (doseq [id ids]
;(dispatch [:set :wrong-password? false]) (status/complete-transaction
(doseq [hash hashes] id
(status/complete-transaction password
hash #(dispatch [:transaction-completed
password {:id id
#(dispatch [:transaction-completed hash %]))) :response %
(dispatch [:navigate-back]))) :previous-view-id previous-view-id}]))))
;(dispatch [:set :wrong-password? true])
(register-handler :accept-transactions (register-handler :accept-transactions
(u/side-effect! (u/side-effect!
(fn [{:keys [transactions current-account-id]} [_ password]] (fn [{:keys [transactions navigation-stack]} [_ password]]
(let [hashes (keys transactions)] (let [ids (keys transactions)
(on-unlock hashes password))))) previous-view-id (second navigation-stack)]
(on-unlock ids password previous-view-id)))))
(register-handler :deny-transactions (register-handler :deny-transactions
(u/side-effect! (u/side-effect!
(fn [{:keys [transactions]}] (fn [{:keys [transactions]}]
(let [hashes (keys transactions)] (let [transactions' (vals transactions)
(dispatch [::remove-pending-messages hashes]) messages-ids (map :message-id transactions')
(dispatch [::remove-trqqansactions hashes]) ids (map :id transactions')]
(dispatch [::remove-pending-messages messages-ids])
(dispatch [::remove-transactions ids])
(dispatch [:navigate-back]))))) (dispatch [:navigate-back])))))
(register-handler :deny-transaction (register-handler :deny-transaction
(u/side-effect! (u/side-effect!
(fn [_ [_ hash]] (fn [{:keys [transactions]} [_ id]]
(dispatch [::remove-pending-message hash]) (let [{:keys [message-id] :as transaction} (get transactions id)]
(dispatch [::remove-transaction hash])))) (when transaction
(dispatch [::remove-pending-message message-id])
(dispatch [::remove-transaction id]))))))
(register-handler ::remove-transactions (register-handler ::remove-transactions
(fn [db [_ hashes]] (fn [db [_ hashes]]
@ -58,55 +75,101 @@
(update :transactions dissoc hash) (update :transactions dissoc hash)
(update :transactions-queue dissoc hash)))) (update :transactions-queue dissoc hash))))
(defn mark-command-as-pending [db chat-id id]
(let [path [:chats chat-id :staged-commands id]]
(if (get-in db path)
(update-in db path assoc :pending true)
db)))
(register-handler :wait-for-transaction (register-handler :wait-for-transaction
(fn [db [_ hash {:keys [chat-id command] :as params}]] (after (fn [_ [_ message-id]]
(dispatch [::check-completed-transaction!
{:message-id message-id}])))
(fn [db [_ message-id {:keys [chat-id command] :as params}]]
(let [id (:id command)] (let [id (:id command)]
(-> db (-> db
(update-in [:chats chat-id :staged-commands id] assoc :pending true) (mark-command-as-pending chat-id id)
(assoc-in [:transaction-subscribers hash] params))))) (assoc-in [:transaction-subscribers message-id] params)))))
(defn remove-pending-message [db hash] (defn remove-pending-message
(let [{:keys [chat-id command]} (get-in db [:transaction-subscribers hash]) [{:keys [command->chat] :as db} message-id]
path [:chats chat-id :staged-commands]] (let [chat-id (get command->chat message-id)
(-> db path [:chats chat-id :staged-commands]]
(update :transaction-subscribers dissoc hash) (if chat-id
(update-in path dissoc (:id command))))) (-> db
(update :transaction-subscribers dissoc message-id)
(update-in path dissoc message-id))
db)))
(register-handler ::remove-pending-messages (register-handler ::remove-pending-messages
(fn [db [_ hashes]] (fn [db [_ ids]]
(reduce remove-pending-message db hashes))) (log/debug :message-ids ids)
(reduce remove-pending-message db ids)))
(register-handler ::remove-pending-message (register-handler ::remove-pending-message
(fn [db [_ hash]] (fn [db [_ message-id]]
(remove-pending-message db hash))) (remove-pending-message db message-id)))
(register-handler :transaction-queued (register-handler :transaction-queued
(after #(dispatch [:navigate-to :confirm])) (after #(dispatch [:navigate-to :confirm]))
(fn [db [_ {:keys [hash args]}]] (fn [db [_ {:keys [id message_id args]}]]
(let [{:keys [from to value]} args (let [{:keys [from to value]} args
transaction {:hash hash transaction {:id id
:from from :from from
:to to :to to
:value (.toDecimal js/Web3.prototype value)}] :value (.toDecimal js/Web3.prototype value)
(assoc-in db [:transactions-queue hash] transaction)))) :message-id message_id}]
(assoc-in db [:transactions-queue id] transaction))))
(register-handler :transaction-completed (register-handler :transaction-completed
(u/side-effect! (u/side-effect!
(fn [db [_ old-hash result-str]] (fn [{:keys [transactions command->chat]} [_ {:keys [id response previous-view-id]}]]
(let [{:keys [hash error]} (t/json->clj result-str)] (let [{:keys [hash error] :as parsed-response} (t/json->clj response)
;; todo: handle error {:keys [message-id]} (transactions id)]
(when hash (log/debug :parsed-response parsed-response)
(dispatch [::send-pending-message old-hash hash]) (if (and error (string? error) (not (s/blank? error)))
(dispatch [::remove-transaction old-hash])))))) ;; todo: revisit this
;; currently transaction is removed after attempt
;; to complete it with wrong password
(do
(dispatch [::remove-transaction id])
(dispatch [:set :wrong-password? true])
(when-let [chat-id (get command->chat message-id)]
(dispatch [:clear-command chat-id message-id])))
(if message-id
(do (dispatch [::add-transactions-hash {:id id
:hash hash
:message-id message-id}])
(dispatch [::check-completed-transaction!
{:message-id message-id}])
(dispatch [:navigation-replace previous-view-id]))
(dispatch [::remove-transaction id])))))))
(register-handler ::add-transactions-hash
(fn [db [_ {:keys [id hash message-id]}]]
(-> db
(assoc-in [:transactions id :hash] hash)
(assoc-in [:message-id->transaction-id message-id] id))))
(register-handler ::send-pending-message (register-handler ::send-pending-message
(u/side-effect! (u/side-effect!
(fn [{:keys [transaction-subscribers] :as db} [_ old-hash new-hash]] (fn [{:keys [transaction-subscribers]} [_ message-id hash]]
(when-let [params (transaction-subscribers old-hash)] (when-let [params (transaction-subscribers message-id)]
(let [params' (assoc-in params [:handler-data :transaction-hash] new-hash)] (let [params' (assoc-in params [:handler-data :transaction-hash] hash)]
(dispatch [:prepare-command! params'])) (dispatch [:prepare-command! params']))
(dispatch [::remove-transaction-subscriber old-hash]))))) (dispatch [::remove-transaction-subscriber message-id])))))
(register-handler ::remove-transaction-subscriber (register-handler ::remove-transaction-subscriber
(fn [db [_ old-hash]] (fn [db [_ old-hash]]
(update db :transaction-subscribers dissoc old-hash))) (update db :transaction-subscribers dissoc old-hash)))
(register-handler ::check-completed-transaction!
(u/side-effect!
(fn [{:keys [message-id->transaction-id transactions transaction-subscribers]}
[_ {:keys [message-id]}]]
(let [id (get message-id->transaction-id message-id)
{:keys [hash]} (get transactions id)
pending-message (get transaction-subscribers message-id)]
(when (and pending-message id hash)
(dispatch [::send-pending-message message-id hash])
(dispatch [::remove-transaction id]))))))

View File

@ -57,6 +57,3 @@
:value password :value password
:label (label :t/password) :label (label :t/password)
:on-change-text #(dispatch [:set-in [:confirm-transactions :password] %])}]]]) :on-change-text #(dispatch [:set-in [:confirm-transactions :password] %])}]]])
;(re-frame.core/dispatch [:set :view-id :confirm])

View File

@ -14,11 +14,11 @@
[status-im.i18n :refer [label label-pluralize]] [status-im.i18n :refer [label label-pluralize]]
cljsjs.web3)) cljsjs.web3))
(defn title-bar [title hash] (defn title-bar [title id]
[view st/title-bar [view st/title-bar
[text {:style st/title-bar-text} title] [text {:style st/title-bar-text} title]
[touchable-highlight {:style st/icon-close-container [touchable-highlight {:style st/icon-close-container
:on-press #(dispatch [:deny-transaction hash])} :on-press #(dispatch [:deny-transaction id])}
[view [image {:source {:uri :icon_close_gray} [view [image {:source {:uri :icon_close_gray}
:style st/icon-close}]]]]) :style st/icon-close}]]]])
@ -31,7 +31,7 @@
[view st/transaction-info-column-value [view st/transaction-info-column-value
[text {:style st/transaction-info-value} value]]]]) [text {:style st/transaction-info-value} value]]]])
(defview transaction-page [{:keys [hash from to value] :as transaction}] (defview transaction-page [{:keys [id from to value] :as transaction}]
[{:keys [name] :as contact} [:contact-by-address to]] [{:keys [name] :as contact} [:contact-by-address to]]
(let [eth-value (.fromWei js/Web3.prototype value "ether") (let [eth-value (.fromWei js/Web3.prototype value "ether")
title (str eth-value " ETH to " name) title (str eth-value " ETH to " name)
@ -39,8 +39,8 @@
[(label :t/recipient) name] [(label :t/recipient) name]
[(label :t/value) (str eth-value " ETH")]]] [(label :t/value) (str eth-value " ETH")]]]
[view {:style st/transaction-page [view {:style st/transaction-page
:key hash} :key id}
[title-bar title hash] [title-bar title id]
[view st/scroll-view-container [view st/scroll-view-container
[scroll-view {:style st/scroll-view [scroll-view {:style st/scroll-view
:contentContainerStyle st/scroll-view-content :contentContainerStyle st/scroll-view-content

View File

@ -46,8 +46,8 @@
(let [diff (t/in-seconds (t/interval time (t/now)))] (let [diff (t/in-seconds (t/interval time (t/now)))]
(if (< diff 60) (if (< diff 60)
(label :t/active-online) (label :t/active-online)
(let [unit (first (drop-while #(or (>= diff (:limit %)) (let [unit (first (drop-while #(and (>= diff (:limit %))
(not (:limit %))) (:limit %))
units))] units))]
(-> (/ diff (:in-second unit)) (-> (/ diff (:in-second unit))
Math/floor Math/floor