JavaScriptCore jail as alternative for Otto vm

This commit is contained in:
Roman Volosovskyi 2017-10-09 11:34:29 +02:00
parent afd7fca6d8
commit 8886bfd5d0
No known key found for this signature in database
GPG Key ID: 37135489EAE4B2D7
24 changed files with 802 additions and 48 deletions

1
.env
View File

@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=1
ERC20_ENABLED=1
OFFLINE_INBOX_ENABLED=0
LOG_LEVEL=debug
JSC_ENABLED=1

View File

@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=1
ERC20_ENABLED=1
OFFLINE_INBOX_ENABLED=0
LOG_LEVEL=debug
JSC_ENABLED=1

View File

@ -7,3 +7,4 @@ MAINNET_NETWORKS_ENABLED=0
ERC20_ENABLED=0
OFFLINE_INBOX_ENABLED=0
LOG_LEVEL=info
JSC_ENABLED=0

View File

@ -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<String, String> callRPC = statusPackage.getCallRPC();
List<ReactPackage> packages = new ArrayList<ReactPackage>(Arrays.asList(
new MainReactPackage(),

View File

@ -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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
@ -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 */,

View File

@ -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')
}

View File

@ -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<String, Cell> 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<String, ScheduledExecutorService> 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();
}
}

View File

@ -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();
}

View File

@ -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() {
}
}

View File

@ -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);
}

View File

@ -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<NativeModule> 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;
}

View File

@ -0,0 +1,41 @@
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import <Statusgo/Statusgo.h>
#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 <JSExport>
- (void)log:(JSValue *)data;
- (NSString *)send:(JSValue *)payload;
- (void)sendAsync:(JSValue *)payload;
- (BOOL)isConnected;
- (void)sendSignal:(JSValue *)data;
@end
@interface HandlersJs : NSObject <HandlersJSExport>
@property (nonatomic) NSString * chatId;
@end

View File

@ -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

View File

@ -1,7 +1,13 @@
#import <Foundation/Foundation.h>
#import "RCTBridgeModule.h"
#import "RCTLog.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "Jail.h"
@interface Status : NSObject <RCTBridgeModule>
+ (void)signalEvent:(const char *) signal;
+ (void)signalEvent:(const char *)signal;
+ (void)jailEvent:(NSString *)chatId
data:(NSString *)data;
+ (BOOL)JSCEnabled;
@property (nonatomic) Jail * jail;
@end

View File

@ -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

View File

@ -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 = "<group>"; };
206C9F3F1D474E910063E3E6 /* RCTStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTStatus.m; sourceTree = "<group>"; };
4C0AB2211F8A2EC700CFD175 /* Jail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Jail.h; sourceTree = "<group>"; };
4C0AB2221F8A2ED700CFD175 /* Jail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Jail.m; sourceTree = "<group>"; };
4C16DE641F8A170500AA10DB /* TimerJSExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimerJSExport.h; sourceTree = "<group>"; };
4C16DE651F8A171B00AA10DB /* TimerJSExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimerJSExport.m; sourceTree = "<group>"; };
9E3F8AF21ED2CCBD0016D874 /* Instabug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Instabug.framework; path = ../../../../ios/Pods/Instabug/Instabug.framework; sourceTree = "<group>"; };
CE4E31B01D86951A0033ED64 /* Statusgo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Statusgo.framework; sourceTree = "<group>"; };
/* 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 = "<group>";
@ -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;

View File

@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
@protocol TimerJSExport <JSExport>
- (NSString *)setTimeout:(JSValue *)args;
- (void)clearInterval:(NSString *)id;
- (NSString *)setInterval:(JSValue *)args;
@end
@interface TimerJS : NSObject <TimerJSExport>
- (void)addToContext:(JSContext *)context;
- (void)stopTimers;
@property (nonatomic) NSMutableDictionary * timers;
@end

View File

@ -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

View File

@ -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);

View File

@ -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: '一覧の中から一つだけ選択してください',

View File

@ -63,8 +63,8 @@ status.command({
{
source: {uri: uri},
style: {
borderRadius: 5
marginTop: 12
borderRadius: 5,
marginTop: 12,
height: 58
}
}

View File

@ -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

View File

@ -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

View File

@ -31,3 +31,4 @@
string/lower-case
keyword))
(def jsc-enabled? (enabled? (get-config :JSC_ENABLED 0)))