From 8886bfd5d082abcc98ebb2eea49a220e7a00de1c Mon Sep 17 00:00:00 2001 From: Roman Volosovskyi Date: Mon, 9 Oct 2017 11:34:29 +0200 Subject: [PATCH] JavaScriptCore jail as alternative for Otto vm --- .env | 1 + .env.jenkins | 1 + .env.prod | 1 + .../im/status/ethereum/MainApplication.java | 7 +- ios/StatusIm.xcodeproj/project.pbxproj | 4 + .../react-native-status/android/build.gradle | 1 + .../im/status/ethereum/module/JSCJail.java | 271 ++++++++++++++++++ .../java/im/status/ethereum/module/Jail.java | 8 + .../im/status/ethereum/module/OttoJail.java | 25 ++ .../status/ethereum/module/StatusModule.java | 25 +- .../status/ethereum/module/StatusPackage.java | 6 +- .../react-native-status/ios/RCTStatus/Jail.h | 41 +++ .../react-native-status/ios/RCTStatus/Jail.m | 210 ++++++++++++++ .../ios/RCTStatus/RCTStatus.h | 8 +- .../ios/RCTStatus/RCTStatus.m | 87 +++++- .../RCTStatus.xcodeproj/project.pbxproj | 12 + .../ios/RCTStatus/TimerJSExport.h | 18 ++ .../ios/RCTStatus/TimerJSExport.m | 60 ++++ resources/js/bots/console/bot.js | 28 +- resources/js/bots/console/translations.js | 2 +- resources/js/bots/mailman/bot.js | 4 +- src/status_im/commands/events/loading.cljs | 6 +- src/status_im/native_module/impl/module.cljs | 23 +- src/status_im/utils/config.cljs | 1 + 24 files changed, 802 insertions(+), 48 deletions(-) create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/JSCJail.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/Jail.java create mode 100644 modules/react-native-status/android/src/main/java/im/status/ethereum/module/OttoJail.java create mode 100644 modules/react-native-status/ios/RCTStatus/Jail.h create mode 100644 modules/react-native-status/ios/RCTStatus/Jail.m create mode 100644 modules/react-native-status/ios/RCTStatus/TimerJSExport.h create mode 100644 modules/react-native-status/ios/RCTStatus/TimerJSExport.m diff --git a/.env b/.env index e5bd903e29..33205cce06 100644 --- a/.env +++ b/.env @@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=1 ERC20_ENABLED=1 OFFLINE_INBOX_ENABLED=0 LOG_LEVEL=debug +JSC_ENABLED=1 diff --git a/.env.jenkins b/.env.jenkins index fe9917e158..7a1321fe7c 100644 --- a/.env.jenkins +++ b/.env.jenkins @@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=1 ERC20_ENABLED=1 OFFLINE_INBOX_ENABLED=0 LOG_LEVEL=debug +JSC_ENABLED=1 diff --git a/.env.prod b/.env.prod index e4f4ac8a4f..005bdf1f75 100644 --- a/.env.prod +++ b/.env.prod @@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=0 ERC20_ENABLED=0 OFFLINE_INBOX_ENABLED=0 LOG_LEVEL=info +JSC_ENABLED=0 diff --git a/android/app/src/main/java/im/status/ethereum/MainApplication.java b/android/app/src/main/java/im/status/ethereum/MainApplication.java index 946374092f..baeb662c6f 100644 --- a/android/app/src/main/java/im/status/ethereum/MainApplication.java +++ b/android/app/src/main/java/im/status/ethereum/MainApplication.java @@ -49,7 +49,12 @@ public class MainApplication extends MultiDexApplication implements ReactApplica devCluster = true; } - StatusPackage statusPackage = new StatusPackage(BuildConfig.DEBUG, devCluster); + boolean jscEnabled = false; + if (BuildConfig.JSC_ENABLED == "1") { + jscEnabled = true; + } + + StatusPackage statusPackage = new StatusPackage(BuildConfig.DEBUG, devCluster, jscEnabled); Function callRPC = statusPackage.getCallRPC(); List packages = new ArrayList(Arrays.asList( new MainReactPackage(), diff --git a/ios/StatusIm.xcodeproj/project.pbxproj b/ios/StatusIm.xcodeproj/project.pbxproj index f1654258d8..bb70e9f886 100644 --- a/ios/StatusIm.xcodeproj/project.pbxproj +++ b/ios/StatusIm.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 22118DE1207A419FBFE7B62D /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD48A32459B64E96843BB238 /* libRealmReact.a */; }; 25DC9C9DC25846BD8D084888 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */; }; 3E15DFEC1F6F4D7CAE088F49 /* libTcpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A4E93F6B154AEFA3485B45 /* libTcpSockets.a */; }; + 4C16DE0C1F89508700AA10DB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */; }; 4D3D740D5EFA4F8592B048D7 /* libBVLinearGradient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF1CD4C3D1254774ACCAE4E8 /* libBVLinearGradient.a */; }; 4FFAE7B0414A463991039A2E /* libRNRandomBytes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C55F15EB4D4DAF9202A662 /* libRNRandomBytes.a */; }; 5974D2035B8B47E0946B63B6 /* libRNFIRMessaging.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F752F17B1E04216B1337A72 /* libRNFIRMessaging.a */; }; @@ -515,6 +516,7 @@ 43A6FA689D844B0BAF3AA8B4 /* RCTOrientation.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTOrientation.xcodeproj; path = "../node_modules/react-native-orientation/iOS/RCTOrientation.xcodeproj"; sourceTree = ""; }; 45FB5F523DE04BDE9877869C /* RNRandomBytes.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNRandomBytes.xcodeproj; path = "../node_modules/react-native-randombytes/RNRandomBytes.xcodeproj"; sourceTree = ""; }; 46E2F6052EB44C698C680894 /* RNI18n.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNI18n.xcodeproj; path = "../node_modules/react-native-i18n/RNI18n.xcodeproj"; sourceTree = ""; }; + 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 4E586E1B0E544F64AA9F5BD1 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 4EC426A98043452BB6F9C134 /* libRNInstabug.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNInstabug.a; sourceTree = ""; }; 52E205D210BC48B7A553BB62 /* Entypo.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Entypo.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Entypo.ttf"; sourceTree = ""; }; @@ -591,6 +593,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4C16DE0C1F89508700AA10DB /* JavaScriptCore.framework in Frameworks */, B2DEA0D01E49E33300FA28D6 /* libRCTHttpServer.a in Frameworks */, 925C1F481F7B73B20063DFA0 /* FirebaseCoreDiagnostics.framework in Frameworks */, 9EE89E271E03FCB7007D3C25 /* libSplashScreen.a in Frameworks */, @@ -1054,6 +1057,7 @@ A97BA941B2FB44B4B66EE6D3 /* Frameworks */ = { isa = PBXGroup; children = ( + 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */, 925C1F7F1F7B73C00063DFA0 /* FirebaseMessaging.framework */, 925C1F801F7B73C00063DFA0 /* Protobuf.framework */, 925C1F401F7B73B20063DFA0 /* FirebaseCore.framework */, diff --git a/modules/react-native-status/android/build.gradle b/modules/react-native-status/android/build.gradle index 4363385bf4..1c70bf6ddf 100644 --- a/modules/react-native-status/android/build.gradle +++ b/modules/react-native-status/android/build.gradle @@ -15,6 +15,7 @@ android { dependencies { compile 'com.facebook.react:react-native:+' compile 'com.instabug.library:instabug:3+' + compile 'com.github.ericwlange:AndroidJSCore:3.0.1' compile 'status-im:function:0.0.1' compile(group: 'status-im', name: 'status-go', version: 'develop-g6927638', ext: 'aar') } diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/JSCJail.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/JSCJail.java new file mode 100644 index 0000000000..bd723562e2 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/JSCJail.java @@ -0,0 +1,271 @@ +package im.status.ethereum.module; + +import android.util.Log; + +import com.github.status_im.status_go.Statusgo; + +import org.json.JSONException; +import org.json.JSONObject; +import org.liquidplayer.webkit.javascriptcore.JSContext; +import org.liquidplayer.webkit.javascriptcore.JSException; +import org.liquidplayer.webkit.javascriptcore.JSFunction; +import org.liquidplayer.webkit.javascriptcore.JSValue; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +class JSCJail implements Jail { + private static final String TAG = "JSCJail"; + private String initJs; + private Map cells = new HashMap<>(); + private StatusModule module; + + @Override + public void initJail(String initJs) { + this.initJs = initJs; + } + + JSCJail(StatusModule module) { + this.module = module; + } + + private class Cell { + JSContext context; + Timer timer; + } + + private class Timer { + private Map timers = new HashMap<>(); + + String setTimeout(JSValue callback, int interval) { + return this.scheduleTask(callback, interval, false); + } + + String setInterval(JSValue callback, int interval) { + return this.scheduleTask(callback, interval, true); + } + + private String scheduleTask(final JSValue callback, int interval, final boolean repeatable) { + final String id = UUID.randomUUID().toString(); + final ScheduledExecutorService scheduler = + Executors.newSingleThreadScheduledExecutor(); + + timers.put(id, scheduler); + + scheduler.scheduleAtFixedRate + (new Runnable() { + public void run() { + if (!repeatable) { + scheduler.shutdown(); + timers.remove(id); + } + callback.toFunction().call(); + } + }, interval, interval, TimeUnit.MILLISECONDS); + + return id; + } + + void clearInterval(String id) { + if (!timers.containsKey(id)) { + return; + } + ScheduledExecutorService scheduler = timers.get(id); + scheduler.shutdown(); + timers.remove(id); + } + + void reset() { + for (String entry : timers.keySet()) { + timers.get(entry).shutdown(); + } + timers.clear(); + } + + } + + + private void addHandlers(Cell cell, final String chatId) { + JSContext context = cell.context; + final Timer timer = cell.timer; + + JSFunction web3send = new JSFunction(context, "web3send") { + public String web3send(String payload) { + return Statusgo.CallRPC(payload); + } + }; + context.property("web3send", web3send); + + JSFunction web3sendAsync = new JSFunction(context, "web3sendAsync") { + public void web3sendAsync(final String payload, final JSValue callback) { + Thread thread = new Thread() { + @Override + public void run() { + String result = Statusgo.CallRPC(payload); + callback.toFunction().call(null, result); + } + }; + + thread.start(); + } + }; + context.property("web3sendAsync", web3sendAsync); + + JSFunction statusSendSignal = new JSFunction(context, "statusSendSignal") { + public void statusSendSignal(String data) { + JSONObject event = new JSONObject(); + JSONObject signal = new JSONObject(); + try { + event.put("chat_id", chatId); + event.put("data", data); + signal.put("type", "jail.signal"); + signal.put("event", event); + } catch (JSONException e) { + Log.d(TAG, "Failed to construct signal JSON object: " + e.getMessage()); + } + + module.signalEvent(signal.toString()); + } + }; + context.property("statusSendSignal", statusSendSignal); + + JSFunction setTimeout = new JSFunction(context, "setTimeout") { + public String setTimeout(final JSValue callback, final int ms) { + return timer.setTimeout(callback, ms); + } + }; + context.property("setTimeout", setTimeout); + + JSFunction setInterval = new JSFunction(context, "setInterval") { + public String setInterval(final JSValue callback, final int ms) { + return timer.setInterval(callback, ms); + } + }; + context.property("setInterval", setInterval); + + JSFunction clearInterval = new JSFunction(context, "clearInterval") { + public void clearInterval(String id) { + timer.clearInterval(id); + } + }; + context.property("clearInterval", clearInterval); + + JSFunction statusLog = new JSFunction(context, "statusLog") { + public void statusLog(String data) { + Log.d("statusJSLog", data); + } + }; + context.property("statusLog", statusLog); + } + + private JSException jsException; + + private void checkException(String label) { + if (jsException != null) { + jsException = null; + } + } + + @Override + public String parseJail(String chatId, String js) { + Cell cell = new Cell(); + JSContext context = new JSContext(); + cell.context = context; + cell.timer = new Timer(); + + context.setExceptionHandler(new JSContext.IJSExceptionHandler() { + @Override + public void handle(JSException exception) { + jsException = exception; + } + }); + String web3Js = "var statusSignals = {\n" + + " sendSignal: function (s) {statusSendSignal(s);}\n" + + " };\n" + + " var Web3 = require('web3');\n" + + " var provider = {\n" + + " send: function (payload) {\n" + + " var result = web3send(JSON.stringify(payload));\n" + + " return JSON.parse(result);\n" + + " },\n" + + " sendAsync: function (payload, callback) {\n" + + " var wrappedCallback = function (result) {\n" + + " //console.log(result);\n" + + " var error = null;\n" + + " try {\n" + + " result = JSON.parse(result);\n" + + " } catch (e) {\n" + + " error = result;\n" + + " }\n" + + " callback(error, result);\n" + + " };\n" + + " web3sendAsync(JSON.stringify(payload), wrappedCallback);\n" + + " }\n" + + " };\n" + + " var web3 = new Web3(provider);\n" + + " var console = {\n" + + " log: function (data) {\n" + + " statusLog(data);\n" + + " }\n" + + " };\n" + + " var Bignumber = require(\"bignumber.js\");\n" + + " function bn(val){\n" + + " return new Bignumber(val);\n" + + " }\n"; + addHandlers(cell, chatId); + context.evaluateScript(initJs); + context.evaluateScript(web3Js); + context.evaluateScript(js); + + context.evaluateScript("var catalog = JSON.stringify(_status_catalog);"); + JSValue catalog = context.property("catalog"); + cells.put(chatId, cell); + + JSONObject result = new JSONObject(); + try { + result.put("result", catalog.toString()); + if (jsException != null) { + result.put("error", jsException.toString()); + jsException = null; + } + } catch (JSONException e) { + Log.d(TAG, "Failed to construct JSON response for parseJail: " + e.getMessage()); + } + + return result.toString(); + } + + @Override + public String callJail(String chatId, String path, String params) { + if (!cells.containsKey(chatId)) { + return null; + } + JSContext context = cells.get(chatId).context; + JSValue call = context.property("call"); + JSValue callResult = call.toFunction().call(null, path, params); + + JSONObject result = new JSONObject(); + try { + result.put("result", callResult.toString()); + if (jsException != null) { + result.put("error", jsException.toString()); + } + } catch (JSONException e) { + Log.d(TAG, "Failed to construct JSON response for callJail: " + e.getMessage()); + } + + return result.toString(); + } + + @Override + public void reset() { + for (String entry : cells.keySet()) { + cells.get(entry).timer.reset(); + } + cells.clear(); + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Jail.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Jail.java new file mode 100644 index 0000000000..66a4238f0c --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/Jail.java @@ -0,0 +1,8 @@ +package im.status.ethereum.module; + +public interface Jail { + void initJail(String initJs); + String parseJail(String chatId, String js); + String callJail(String chatId, String path, String params); + void reset(); +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/OttoJail.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/OttoJail.java new file mode 100644 index 0000000000..6b9163a950 --- /dev/null +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/OttoJail.java @@ -0,0 +1,25 @@ +package im.status.ethereum.module; + +import com.github.status_im.status_go.Statusgo; + +public class OttoJail implements Jail { + @Override + public void initJail(String initJs) { + Statusgo.InitJail(initJs); + } + + @Override + public String parseJail(String chatId, String js) { + return Statusgo.Parse(chatId, js); + } + + @Override + public String callJail(String chatId, String path, String params) { + return Statusgo.Call(chatId, path, params); + } + + @Override + public void reset() { + + } +} diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java index 19fb578d10..241cb9986c 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusModule.java @@ -39,8 +39,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL private ExecutorService executor = null; private boolean debug; private boolean devCluster; + private Jail jail; - StatusModule(ReactApplicationContext reactContext, boolean debug, boolean devCluster) { + StatusModule(ReactApplicationContext reactContext, boolean debug, boolean devCluster, boolean jscEnabled) { super(reactContext); if (executor == null) { executor = Executors.newCachedThreadPool(); @@ -48,6 +49,11 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL this.debug = debug; this.devCluster = devCluster; reactContext.addLifecycleEventListener(this); + if(jscEnabled) { + jail = new JSCJail(this); + } else { + jail = new OttoJail(); + } } @Override @@ -97,8 +103,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL return true; } - // Geth - private void signalEvent(String jsonEvent) { + + void signalEvent(String jsonEvent) { Log.d(TAG, "Signal event: " + jsonEvent); WritableMap params = Arguments.createMap(); params.putString("jsonEvent", jsonEvent); @@ -342,6 +348,9 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL callback.invoke(false); return; } + + jail.reset(); + Thread thread = new Thread() { @Override public void run() { @@ -467,7 +476,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Thread thread = new Thread() { @Override public void run() { - Statusgo.InitJail(js); + jail.initJail(js); callback.invoke(false); } @@ -478,7 +487,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL @ReactMethod public void parseJail(final String chatId, final String js, final Callback callback) { - Log.d(TAG, "parseJail"); + Log.d(TAG, "parseJail chatId:" + chatId); + Log.d(TAG, js); if (!checkAvailability()) { callback.invoke(false); return; @@ -487,7 +497,8 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL Thread thread = new Thread() { @Override public void run() { - String res = Statusgo.Parse(chatId, js); + String res = jail.parseJail(chatId, js); + Log.d(TAG, res); Log.d(TAG, "endParseJail"); callback.invoke(res); } @@ -509,7 +520,7 @@ class StatusModule extends ReactContextBaseJavaModule implements LifecycleEventL @Override public void run() { Log.d(TAG, "startCallJail"); - String res = Statusgo.Call(chatId, path, params); + String res = jail.callJail(chatId, path, params); Log.d(TAG, "endCallJail"); callback.invoke(res); } diff --git a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java index 68c9df6d4c..ca16000d36 100644 --- a/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java +++ b/modules/react-native-status/android/src/main/java/im/status/ethereum/module/StatusPackage.java @@ -16,10 +16,12 @@ public class StatusPackage implements ReactPackage { private boolean debug; private boolean devCluster; + private boolean jscEnabled; - public StatusPackage (boolean debug, boolean devCluster) { + public StatusPackage (boolean debug, boolean devCluster, boolean jscEnabled) { this.debug = debug; this.devCluster = devCluster; + this.jscEnabled = jscEnabled; } @Override @@ -27,7 +29,7 @@ public class StatusPackage implements ReactPackage { List modules = new ArrayList<>(); System.loadLibrary("statusgoraw"); System.loadLibrary("statusgo"); - modules.add(new StatusModule(reactContext, this.debug, this.devCluster)); + modules.add(new StatusModule(reactContext, this.debug, this.devCluster, this.jscEnabled)); return modules; } diff --git a/modules/react-native-status/ios/RCTStatus/Jail.h b/modules/react-native-status/ios/RCTStatus/Jail.h new file mode 100644 index 0000000000..065bd9fe2d --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/Jail.h @@ -0,0 +1,41 @@ +#import +#import +#import +#import "TimerJSExport.h" + +@interface Jail : NSObject +- (void)initJail:(NSString *)js; + +- (NSDictionary *)parseJail:(NSString *)chatId + withCode:(NSString *)js; + +- (NSDictionary *)call:(NSString *)chatId + path:(NSString *)path + params:(NSString *)params; + +- (void)reset; + +@property (nonatomic) NSMutableDictionary * cells; +@property (nonatomic) NSString * initialJs; +@property (nonatomic) TimerJS * timer; + +@end + +@interface Cell : NSObject +@property (nonatomic)JSContext * context; +@property (nonatomic)TimerJS * timer; +@end + +@protocol HandlersJSExport + +- (void)log:(JSValue *)data; +- (NSString *)send:(JSValue *)payload; +- (void)sendAsync:(JSValue *)payload; +- (BOOL)isConnected; +- (void)sendSignal:(JSValue *)data; + +@end + +@interface HandlersJs : NSObject +@property (nonatomic) NSString * chatId; +@end diff --git a/modules/react-native-status/ios/RCTStatus/Jail.m b/modules/react-native-status/ios/RCTStatus/Jail.m new file mode 100644 index 0000000000..cb63af665c --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/Jail.m @@ -0,0 +1,210 @@ +#import "Jail.h" +#import "RCTStatus.h" + +//source: http://stackoverflow.com/a/23387659/828487 +#define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding] + +@implementation HandlersJs + +- (void)log:(JSValue *)data +{ + NSLog(@"jail log: %@", [data toString]); +} + +- (NSString *)send:(JSValue *)payload +{ + char * result = CallRPC((char *) [[payload toString] UTF8String]); + + return [NSString stringWithUTF8String: result]; +} + +- (void)sendAsync:(JSValue *)args +{ + // TODO(rasom): fix this black magic, need to figure how to pass more than one + // parameter to sendAsync + JSValue *payload = [args callWithArguments:@[@0]]; + JSValue *callback = [args callWithArguments:@[@1]]; + + dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *result = [self send:payload]; + dispatch_async( dispatch_get_main_queue(), ^{ + [callback callWithArguments:@[result]]; + }); + }); +} + +- (BOOL)isConnected +{ + return YES; +} + +- (void)sendSignal:(JSValue *)data +{ + [Status jailEvent:_chatId data:[data toString]]; +} + +- (void)setChatId:(NSString *)chatId +{ + _chatId = chatId; +} + +- (void)addToContext:(JSContext *)context +{ + [context setObject:self forKeyedSubscript:@"statusNativeHandlers"]; +} + +@end + +@implementation Cell +@end + +@implementation Jail + +- (void)initJail:(NSString *)js { + _initialJs = js; +} + +- (NSDictionary *)parseJail:(NSString *)chatId + withCode:(NSString *)js { + Cell *cell = [self createCell:chatId withCode:js]; + JSContext *context = cell.context; + [_cells setValue:cell forKey:chatId]; + + JSValue *catalog = context[@"catalog"];; + JSValue *exception = [context exception]; + NSString *error; + if(exception != nil) { + error = [exception toString]; + [context setException:nil]; + } + NSDictionary *result = [[NSDictionary alloc] initWithObjectsAndKeys:[catalog toString], @"result", error, @"error", nil]; + + return result; +} + +- (NSDictionary *)call:(NSString *)chatId + path:(NSString *)path + params:(NSString *)params { + Cell *cell = [_cells valueForKey:chatId]; + JSContext *context = cell.context; + if(cell == nil) { + return [[NSDictionary alloc] initWithObjectsAndKeys:nil, @"result", @"jail is not initialized", @"error", nil]; + } + JSValue *callResult = [context[@"call"] callWithArguments:@[path, params]]; + JSValue *exception = [context exception]; + NSString *error; + if(exception != nil) { + error = [exception toString]; + [context setException:nil]; + } + NSDictionary *result = [[NSDictionary alloc] initWithObjectsAndKeys:[callResult toString], @"result", error, @"error", nil]; + + return result; +} + +- (Cell *)createCell:(NSString *)chatId + withCode:(NSString *)js { + if(_cells == nil) { + _cells = [NSMutableDictionary dictionaryWithCapacity:1]; + } + + Cell * cell = [Cell new]; + JSContext *context = [JSContext new]; + cell.context = context; + + HandlersJs *handlers = [HandlersJs new]; + [handlers setChatId:chatId]; + [handlers addToContext:context]; + + [self addTimer:cell]; + [context evaluateScript:_initialJs]; + + JSValue *excep = [context exception]; + NSLog(@"err1 %@", [excep toString]); + + NSString *webJs = + NSStringMultiline + ( + var statusSignals = { + sendSignal: function (s) {statusNativeHandlers.sendSignal(s);} + }; + var setTimeout = function (fn, t) { + var args = [fn, t]; + var getItem = function(idx) {return args[idx];}; + return jsTimer.setTimeout(getItem); + }; + var setInterval = function (fn, t) { + var args = [fn, t]; + var getItem = function(idx) {return args[idx];}; + return jsTimer.setInterval(getItem); + }; + var clearInterval = function (id) { + jsTimer.clearInterval(id); + }; + var Web3 = require('web3'); + var provider = { + send: function (payload) { + var result = statusNativeHandlers.send(JSON.stringify(payload)); + return JSON.parse(result); + }, + sendAsync: function (payload, callback) { + var wrappedCallback = function (result) { + console.log(result); + var error = null; + try { + result = JSON.parse(result); + } catch (e) { + error = result; + } + callback(error, result); + }; + var args = [JSON.stringify(payload), wrappedCallback]; + var getItem = function(idx) {return args[idx];}; + statusNativeHandlers.sendAsync(getItem); + } + }; + var web3 = new Web3(provider); + var console = { + log: function (data) { + statusNativeHandlers.log(data); + } + }; + var Bignumber = require("bignumber.js"); + function bn(val){ + return new Bignumber(val); + } + + ); + + + [context evaluateScript:webJs]; + excep = [context exception]; + NSLog(@"err2 %@", [excep toString]); + [context evaluateScript:js]; + excep = [context exception]; + NSLog(@"err3 %@", [excep toString]); + [context evaluateScript:@"var catalog = JSON.stringify(_status_catalog);"]; + excep = [context exception]; + NSLog(@"err4 %@", [excep toString]); + + return cell; +} + +- (void)addTimer:(Cell *)cell { + TimerJS *timer = [TimerJS new]; + cell.timer = timer; + + [timer addToContext:cell.context]; +} + +-(void)reset { + NSArray *keys = [_cells allKeys]; + for (NSString *key in keys) { + Cell *cell = [_cells valueForKey:key]; + TimerJS *timer = cell.timer; + [timer stopTimers]; + [_cells removeObjectForKey:key]; + } +} + +@end diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.h b/modules/react-native-status/ios/RCTStatus/RCTStatus.h index 1bfd8ef8bd..2d53f4ebce 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.h +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.h @@ -1,7 +1,13 @@ #import #import "RCTBridgeModule.h" #import "RCTLog.h" +#import +#import "Jail.h" @interface Status : NSObject -+ (void)signalEvent:(const char *) signal; ++ (void)signalEvent:(const char *)signal; ++ (void)jailEvent:(NSString *)chatId + data:(NSString *)data; ++ (BOOL)JSCEnabled; +@property (nonatomic) Jail * jail; @end diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.m b/modules/react-native-status/ios/RCTStatus/RCTStatus.m index cba646c9ba..ff95fec08e 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.m +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.m @@ -63,6 +63,11 @@ static RCTBridge *bridge; RCT_EXPORT_MODULE(); ++ (BOOL)JSCEnabled +{ + return @"1" == [ReactNativeConfig envFor:@"JSC_ENABLED"]; +} + //////////////////////////////////////////////////////////////////// #pragma mark - Jails functions //////////////////////////////////////////////////////////////////// initJail @@ -71,7 +76,14 @@ RCT_EXPORT_METHOD(initJail: (NSString *) js #if DEBUG NSLog(@"InitJail() method called"); #endif - InitJail((char *) [js UTF8String]); + if([Status JSCEnabled]){ + if(_jail == nil) { + _jail = [Jail new]; + } + [_jail initJail:js]; + } else { + InitJail((char *) [js UTF8String]); + } callback(@[[NSNull null]]); } @@ -82,8 +94,19 @@ RCT_EXPORT_METHOD(parseJail:(NSString *)chatId #if DEBUG NSLog(@"ParseJail() method called"); #endif - char * result = Parse((char *) [chatId UTF8String], (char *) [js UTF8String]); - callback(@[[NSString stringWithUTF8String: result]]); + NSString *stringResult; + if([Status JSCEnabled]){ + if(_jail == nil) { + _jail = [Jail new]; + } + NSDictionary *result = [_jail parseJail:chatId withCode:js]; + stringResult = [result bv_jsonStringWithPrettyPrint:NO]; + } else { + char * result = Parse((char *) [chatId UTF8String], (char *) [js UTF8String]); + stringResult = [NSString stringWithUTF8String: result]; + } + + callback(@[stringResult]); } //////////////////////////////////////////////////////////////////// callJail @@ -95,9 +118,21 @@ RCT_EXPORT_METHOD(callJail:(NSString *)chatId NSLog(@"CallJail() method called"); #endif dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]); + + NSString *stringResult; + if([Status JSCEnabled]){ + if(_jail == nil) { + _jail = [Jail new]; + } + NSDictionary *result = [_jail call:chatId path:path params:params]; + stringResult = [result bv_jsonStringWithPrettyPrint:NO]; + } else { + char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]); + stringResult = [NSString stringWithUTF8String: result]; + } + dispatch_async( dispatch_get_main_queue(), ^{ - callback(@[[NSString stringWithUTF8String: result]]); + callback(@[stringResult]); }); }); } @@ -168,7 +203,7 @@ RCT_EXPORT_METHOD(startNode:(NSString *)configString) { [resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKey:@"LogEnabled"]; [resultingConfigJson setValue:logUrl.path forKey:@"LogFile"]; [resultingConfigJson setValue:@"DEBUG" forKey:@"LogLevel"]; - + if(upstreamURL != nil) { [resultingConfigJson setValue:[NSNumber numberWithBool:YES] forKeyPath:@"UpstreamConfig.Enabled"]; [resultingConfigJson setValue:upstreamURL forKeyPath:@"UpstreamConfig.URL"]; @@ -243,14 +278,14 @@ RCT_EXPORT_METHOD(createAccount:(NSString *)password } //////////////////////////////////////////////////////////////////// - #pragma mark - Notify method +#pragma mark - Notify method //////////////////////////////////////////////////////////////////// notify RCT_EXPORT_METHOD(notify:(NSString *)token - callback:(RCTResponseSenderBlock)callback) { - char * result = Notify((char *) [token UTF8String]); - callback(@[[NSString stringWithUTF8String: result]]); + callback:(RCTResponseSenderBlock)callback) { + char * result = Notify((char *) [token UTF8String]); + callback(@[[NSString stringWithUTF8String: result]]); #if DEBUG - NSLog(@"Notify() method called"); + NSLog(@"Notify() method called"); #endif } @@ -273,6 +308,9 @@ RCT_EXPORT_METHOD(login:(NSString *)address #if DEBUG NSLog(@"Login() method called"); #endif + if(_jail != nil) { + [_jail reset]; + } char * result = Login((char *) [address UTF8String], (char *) [password UTF8String]); callback(@[[NSString stringWithUTF8String: result]]); } @@ -331,13 +369,13 @@ RCT_EXPORT_METHOD(clearCookies) { RCT_EXPORT_METHOD(clearStorageAPIs) { [[NSURLCache sharedURLCache] removeAllCachedResponses]; - + NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]; for (NSString *string in array) { NSLog(@"Removing %@", [path stringByAppendingPathComponent:string]); - if ([[string pathExtension] isEqualToString:@"localstorage"]) - [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil]; + if ([[string pathExtension] isEqualToString:@"localstorage"]) + [[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil]; } } @@ -359,7 +397,7 @@ RCT_EXPORT_METHOD(closeApplication) { { if(!signal){ #if DEBUG - NSLog(@"SignalEvent nil"); + NSLog(@"SignalEvent nil"); #endif return; } @@ -375,4 +413,23 @@ RCT_EXPORT_METHOD(closeApplication) { return; } ++ (void)jailEvent:(NSString *)chatId + data:(NSString *)data +{ + NSData *signalData = [@"{}" dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:signalData options:NSJSONReadingMutableContainers error:nil]; + [dict setValue:@"jail.signal" forKey:@"type"]; + NSDictionary *event = [[NSDictionary alloc] initWithObjectsAndKeys:chatId, @"chat_id", data, @"data", nil]; + [dict setValue:event forKey:@"event"]; + NSString *signal = [dict bv_jsonStringWithPrettyPrint:NO]; +#if DEBUG + NSLog(@"SignalEventData"); + NSLog(signal); +#endif + [bridge.eventDispatcher sendAppEventWithName:@"gethEvent" + body:@{@"jsonEvent": signal}]; + + return; +} + @end diff --git a/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj b/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj index 93c252b03f..9cb56fc1a8 100644 --- a/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj +++ b/modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ 206C9F3E1D474E910063E3E6 /* RCTStatus.h in Copy Files */ = {isa = PBXBuildFile; fileRef = 206C9F3D1D474E910063E3E6 /* RCTStatus.h */; }; 206C9F401D474E910063E3E6 /* RCTStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 206C9F3F1D474E910063E3E6 /* RCTStatus.m */; }; + 4C0AB2231F8A2ED700CFD175 /* Jail.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0AB2221F8A2ED700CFD175 /* Jail.m */; }; + 4C16DE661F8A171B00AA10DB /* TimerJSExport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C16DE651F8A171B00AA10DB /* TimerJSExport.m */; }; CE4E31B11D86951A0033ED64 /* Statusgo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE4E31B01D86951A0033ED64 /* Statusgo.framework */; }; /* End PBXBuildFile section */ @@ -30,6 +32,10 @@ 206C9F3A1D474E910063E3E6 /* libRCTStatus.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTStatus.a; sourceTree = BUILT_PRODUCTS_DIR; }; 206C9F3D1D474E910063E3E6 /* RCTStatus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTStatus.h; sourceTree = ""; }; 206C9F3F1D474E910063E3E6 /* RCTStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTStatus.m; sourceTree = ""; }; + 4C0AB2211F8A2EC700CFD175 /* Jail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Jail.h; sourceTree = ""; }; + 4C0AB2221F8A2ED700CFD175 /* Jail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Jail.m; sourceTree = ""; }; + 4C16DE641F8A170500AA10DB /* TimerJSExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimerJSExport.h; sourceTree = ""; }; + 4C16DE651F8A171B00AA10DB /* TimerJSExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimerJSExport.m; sourceTree = ""; }; 9E3F8AF21ED2CCBD0016D874 /* Instabug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Instabug.framework; path = ../../../../ios/Pods/Instabug/Instabug.framework; sourceTree = ""; }; CE4E31B01D86951A0033ED64 /* Statusgo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Statusgo.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -69,6 +75,10 @@ children = ( 206C9F3D1D474E910063E3E6 /* RCTStatus.h */, 206C9F3F1D474E910063E3E6 /* RCTStatus.m */, + 4C16DE641F8A170500AA10DB /* TimerJSExport.h */, + 4C16DE651F8A171B00AA10DB /* TimerJSExport.m */, + 4C0AB2211F8A2EC700CFD175 /* Jail.h */, + 4C0AB2221F8A2ED700CFD175 /* Jail.m */, ); name = Status; sourceTree = ""; @@ -137,6 +147,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4C16DE661F8A171B00AA10DB /* TimerJSExport.m in Sources */, + 4C0AB2231F8A2ED700CFD175 /* Jail.m in Sources */, 206C9F401D474E910063E3E6 /* RCTStatus.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/modules/react-native-status/ios/RCTStatus/TimerJSExport.h b/modules/react-native-status/ios/RCTStatus/TimerJSExport.h new file mode 100644 index 0000000000..1e5806f02c --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/TimerJSExport.h @@ -0,0 +1,18 @@ +#import +#import + +@protocol TimerJSExport + +- (NSString *)setTimeout:(JSValue *)args; + +- (void)clearInterval:(NSString *)id; + +- (NSString *)setInterval:(JSValue *)args; + +@end + +@interface TimerJS : NSObject +- (void)addToContext:(JSContext *)context; +- (void)stopTimers; +@property (nonatomic) NSMutableDictionary * timers; +@end diff --git a/modules/react-native-status/ios/RCTStatus/TimerJSExport.m b/modules/react-native-status/ios/RCTStatus/TimerJSExport.m new file mode 100644 index 0000000000..74031de234 --- /dev/null +++ b/modules/react-native-status/ios/RCTStatus/TimerJSExport.m @@ -0,0 +1,60 @@ +#import "TimerJSExport.h" + +@implementation TimerJS + +- (NSString *)setTimeout:(JSValue *)args { + JSValue *callback = [args callWithArguments:@[@0]]; + double ms = [[args callWithArguments:@[@1]] toDouble]; + return [self createTimer:callback inteval:ms repeats:NO]; +} + +- (void)clearInterval:(NSString *)id { + NSTimer *timer = [_timers objectForKey:id]; + if(timer != nil) { + [timer invalidate]; + } +} + + +- (NSString *)setInterval:(JSValue *)args { + JSValue *callback = [args callWithArguments:@[@0]]; + double ms = [[args callWithArguments:@[@1]] toDouble]; + return [self createTimer:callback inteval:ms repeats:YES]; +} + +- (NSString *)createTimer:(JSValue *)callback + inteval:(double)ms + repeats:(BOOL)repeats { + if (_timers == nil) { + _timers = [NSMutableDictionary dictionaryWithCapacity:1]; + } + + double interval = ms/1000.0; + NSString *uuid = [[NSUUID UUID] UUIDString]; + + dispatch_async( dispatch_get_main_queue(), ^{ + NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:interval + repeats:repeats + block:^(NSTimer * _Nonnull timer) { + [callback callWithArguments:nil]; }]; + [_timers setObject:timer forKey:uuid]; + }); + + return uuid; +} + +- (void)addToContext:(JSContext *)context { + [context setObject:self forKeyedSubscript:@"jsTimer"]; +} + +- (void)stopTimers { + NSArray *keys = [_timers allKeys]; + for (NSString *key in keys) { + NSTimer *timer = [_timers valueForKey:key]; + [timer invalidate]; + + [_timers removeObjectForKey:key]; + } +} + +@end diff --git a/resources/js/bots/console/bot.js b/resources/js/bots/console/bot.js index 41e88413b9..82a24f0e0c 100644 --- a/resources/js/bots/console/bot.js +++ b/resources/js/bots/console/bot.js @@ -471,20 +471,24 @@ var phoneConfig = { placeholder: I18n.t('phone_placeholder') }], preview: function (params) { - return { - markup: status.components.text( - {}, - params.phone - ) - }; + if (params) { + return { + markup: status.components.text( + {}, + params.phone + ) + }; + } }, shortPreview: function (params) { - return { - markup: status.components.text( - {}, - params.phone - ) - }; + if (params) { + return { + markup: status.components.text( + {}, + params.phone + ) + }; + } } }; status.command(phoneConfig); diff --git a/resources/js/bots/console/translations.js b/resources/js/bots/console/translations.js index f4c486247f..bb02c0497f 100644 --- a/resources/js/bots/console/translations.js +++ b/resources/js/bots/console/translations.js @@ -300,7 +300,7 @@ I18n.translations = { password_placeholder2: '確認のためにパスワードを再入力してください', password_error: 'パスワードは6文字以上にしてください。', password_error1: 'パスワードが一致しません。', - password_validation_title: 'パスワード' + password_validation_title: 'パスワード', faucet_incorrect_title: 'フォーセットが違います', faucet_incorrect_description: '一覧の中から一つだけ選択してください', diff --git a/resources/js/bots/mailman/bot.js b/resources/js/bots/mailman/bot.js index d6ac3b1ca4..dccaa93c6e 100644 --- a/resources/js/bots/mailman/bot.js +++ b/resources/js/bots/mailman/bot.js @@ -63,8 +63,8 @@ status.command({ { source: {uri: uri}, style: { - borderRadius: 5 - marginTop: 12 + borderRadius: 5, + marginTop: 12, height: 58 } } diff --git a/src/status_im/commands/events/loading.cljs b/src/status_im/commands/events/loading.cljs index 65fe860619..ebee64c4dd 100644 --- a/src/status_im/commands/events/loading.cljs +++ b/src/status_im/commands/events/loading.cljs @@ -6,6 +6,7 @@ [status-im.utils.js-resources :as js-resources] [status-im.utils.types :as types] [status-im.utils.utils :as utils] + [status-im.utils.config :as config] [status-im.native-module.core :as status] [status-im.data-store.local-storage :as local-storage] [status-im.bots.events :as bots-events] @@ -25,7 +26,10 @@ (status/parse-jail jail-id jail-resource (fn [jail-response] - (re-frame/dispatch [::proceed-loading jail-id (types/json->clj jail-response)])))))) + (let [converted (types/json->clj jail-response)] + (re-frame/dispatch [::proceed-loading jail-id (if config/jsc-enabled? + (update converted :result types/json->clj) + converted)]))))))) (re-frame/reg-fx ::show-popup diff --git a/src/status_im/native_module/impl/module.cljs b/src/status_im/native_module/impl/module.cljs index 238344c8b5..a4068513c7 100644 --- a/src/status_im/native_module/impl/module.cljs +++ b/src/status_im/native_module/impl/module.cljs @@ -12,7 +12,8 @@ [status-im.utils.transducers :as transducers] [status-im.utils.async :as async-util] [status-im.react-native.js-dependencies :as rn-dependencies] - [status-im.native-module.module :as module])) + [status-im.native-module.module :as module] + [status-im.utils.config :as config])) ;; if StatusModule is not initialized better to store ;; calls and make them only when StatusModule is ready @@ -54,9 +55,16 @@ (defn init-jail [] (when status (call-module - (fn [] - (let [init-js (str js-res/status-js "I18n.locale = '" rn-dependencies/i18n.locale "';")] - (.initJail status init-js #(log/debug "jail initialized"))))))) + (fn [] + (let [init-js (str js-res/status-js "I18n.locale = '" rn-dependencies/i18n.locale "'; ") + init-js' (if config/jsc-enabled? + (str init-js js-res/web3) + init-js) + log-message (str (if config/jsc-enabled? + "JavaScriptCore" + "OttoVM") + " jail initialized")] + (.initJail status init-js' #(log/debug log-message))))))) (defonce listener-initialized (atom false)) @@ -138,8 +146,11 @@ cb (fn [jail-result] (let [result (-> jail-result types/json->clj - (assoc :bot-id jail-id))] - (callback result)))] + (assoc :bot-id jail-id)) + result' (if config/jsc-enabled? + (update result :result types/json->clj) + result)] + (callback result')))] (.callJail status jail-id (types/clj->json path) (types/clj->json params') cb)))))) ;; We want the mainting (time) windowed queue of all calls to the jail diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index f423b5faa2..15dc5c150d 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -31,3 +31,4 @@ string/lower-case keyword)) +(def jsc-enabled? (enabled? (get-config :JSC_ENABLED 0)))