remote js executor block io on 'loadJS' added

This commit is contained in:
王劲鹏 2019-10-22 10:25:10 +08:00 committed by unknown
parent 9c7c6a411e
commit 5d2ef87325
8 changed files with 174 additions and 11 deletions

View File

@ -47,11 +47,13 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.appcompat:appcompat:1.1.0'
api 'com.github.pengfeizhou:jsc4a:0.1.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.1'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:1.0.1'
api 'org.nanohttpd:nanohttpd:2.3.1'
implementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api 'com.github.pengfeizhou:jsc4a:0.1.0'
implementation "com.squareup.okhttp3:okhttp:3.11.0"
implementation 'com.github.penfeizhou.android.animation:glide-plugin:1.0.1'
api 'org.nanohttpd:nanohttpd:2.3.1'
} }

View File

@ -67,7 +67,8 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
private void initJSExecutor() { private void initJSExecutor() {
mDoricJSE = new DoricNativeJSExecutor(); // mDoricJSE = new DoricNativeJSExecutor();
mDoricJSE = new DoricRemoteJSExecutor();
mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() { mDoricJSE.injectGlobalJSFunction(DoricConstant.INJECT_LOG, new JavaFunction() {
@Override @Override
public JavaValue exec(JSDecoder[] args) { public JavaValue exec(JSDecoder[] args) {

View File

@ -20,35 +20,43 @@ import com.github.pengfeizhou.jscore.JSRuntimeException;
import com.github.pengfeizhou.jscore.JavaFunction; import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue; import com.github.pengfeizhou.jscore.JavaValue;
import pub.doric.engine.remote.RemoteJSExecutor;
public class DoricRemoteJSExecutor implements IDoricJSE { public class DoricRemoteJSExecutor implements IDoricJSE {
private final RemoteJSExecutor mRemoteJSExecutor;
public DoricRemoteJSExecutor() {
this.mRemoteJSExecutor = new RemoteJSExecutor();
}
@Override @Override
public String loadJS(String script, String source) throws JSRuntimeException { public String loadJS(String script, String source) throws JSRuntimeException {
return null; return mRemoteJSExecutor.loadJS(script, source);
} }
@Override @Override
public JSDecoder evaluateJS(String script, String source, boolean hashKey) throws JSRuntimeException { public JSDecoder evaluateJS(String script, String source, boolean hashKey) throws JSRuntimeException {
return null; return mRemoteJSExecutor.evaluateJS(script, source, hashKey);
} }
@Override @Override
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) { public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
mRemoteJSExecutor.injectGlobalJSFunction(name, javaFunction);
} }
@Override @Override
public void injectGlobalJSObject(String name, JavaValue javaValue) { public void injectGlobalJSObject(String name, JavaValue javaValue) {
mRemoteJSExecutor.injectGlobalJSObject(name, javaValue);
} }
@Override @Override
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) throws JSRuntimeException { public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) throws JSRuntimeException {
return null; return mRemoteJSExecutor.invokeMethod(objectName, functionName, javaValues, hashKey);
} }
@Override @Override
public void teardown() { public void teardown() {
mRemoteJSExecutor.destroy();
} }
} }

View File

@ -0,0 +1,100 @@
package pub.doric.engine.remote;
import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;
import java.io.EOFException;
import java.net.ConnectException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
public class RemoteJSExecutor {
private final WebSocket webSocket;
private final Gson gson = new Gson();
public RemoteJSExecutor() {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
Request request = new Request.Builder().url("ws://192.168.24.166:2080").build();
final Thread current = Thread.currentThread();
webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
LockSupport.unpark(current);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
if (t instanceof ConnectException) {
// 连接remote异常
LockSupport.unpark(current);
throw new RuntimeException("remote js executor cannot connect");
} else if (t instanceof EOFException) {
// 被远端强制断开
throw new RuntimeException("remote js executor eof");
}
}
@Override
public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
JsonElement je = gson.fromJson(text, JsonElement.class);
System.out.println(je);
LockSupport.unpark(current);
}
});
LockSupport.park(current);
}
public String loadJS(String script, String source) {
JsonObject jo = new JsonObject();
jo.addProperty("cmd", "loadJS");
jo.addProperty("script", script);
jo.addProperty("source", source);
webSocket.send(gson.toJson(jo));
LockSupport.park(Thread.currentThread());
return null;
}
public JSDecoder evaluateJS(String script, String source, boolean hashKey) {
JsonObject jo = new JsonObject();
jo.addProperty("cmd", "evaluateJS");
jo.addProperty("script", script);
jo.addProperty("source", source);
jo.addProperty("hashKey", hashKey);
webSocket.send(gson.toJson(jo));
return null;
}
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
}
public void injectGlobalJSObject(String name, JavaValue javaValue) {
}
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) {
return null;
}
public void destroy() {
webSocket.close(0, "destroy");
}
}

1
remote/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

20
remote/index.js Normal file
View File

@ -0,0 +1,20 @@
const WebSocket = require('ws')
const vm = require("vm")
const wss = new WebSocket.Server({ port: 2080 })
var sandbox = {}
var context = vm.createContext(sandbox)
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
let messageObject = JSON.parse(message)
switch(messageObject.cmd) {
case "loadJS":
let result = vm.runInContext(messageObject.script, sandbox)
ws.send(JSON.stringify({cmd: 'loadJS', result: String(result)}))
break
case "evaluateJS":
break
}
})
})

21
remote/package-lock.json generated Normal file
View File

@ -0,0 +1,21 @@
{
"name": "remote",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"ws": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.0.tgz",
"integrity": "sha512-+SqNqFbwTm/0DC18KYzIsMTnEWpLwJsiasW/O17la4iDRRIO9uaHbvKiAS3AHgTiuuWerK/brj4O6MYZkei9xg==",
"requires": {
"async-limiter": "^1.0.0"
}
}
}
}

10
remote/package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "remote",
"version": "0.1.0",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"ws": "^7.2.0"
}
}