debugger:complete android part

This commit is contained in:
pengfeizhou 2021-02-21 01:51:59 +08:00 committed by osborn
parent 4c0237aec6
commit af31014e2e
16 changed files with 526 additions and 561 deletions

View File

@ -2,6 +2,8 @@ package pub.doric.devkit;
import android.widget.Toast;
import com.github.pengfeizhou.jscore.JSONBuilder;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@ -15,13 +17,12 @@ import pub.doric.devkit.event.ConnectExceptionEvent;
import pub.doric.devkit.event.EOFExceptionEvent;
import pub.doric.devkit.event.OpenEvent;
import pub.doric.devkit.event.StopDebugEvent;
import pub.doric.utils.DoricLog;
public class DevKit implements IDevKit {
public static boolean isRunningInEmulator = false;
public static String ip = "";
private static class Inner {
private static final DevKit sInstance = new DevKit();
}
@ -38,6 +39,10 @@ public class DevKit implements IDevKit {
private WSClient wsClient;
boolean devKitConnected = false;
private DoricContextDebuggable debuggable;
@Override
public void connectDevKit(String url) {
wsClient = new WSClient(url);
@ -54,9 +59,39 @@ public class DevKit implements IDevKit {
wsClient = null;
}
boolean devKitConnected = false;
@Override
public void startDebugging(String source) {
if (debuggable != null) {
debuggable.stopDebug(true);
}
DoricContext context = matchContext(source);
if (context == null) {
DoricLog.d("Cannot find context source %s for debugging", source);
wsClient.sendToDebugger("DEBUG_STOP", new JSONBuilder()
.put("msg", "Cannot find suitable alive context for debugging")
.toJSONObject());
} else {
wsClient.sendToDebugger(
"DEBUG_RES",
new JSONBuilder()
.put("contextId", context.getContextId())
.toJSONObject());
debuggable = new DoricContextDebuggable(wsClient, context);
debuggable.startDebug();
}
}
@Override
public void stopDebugging(boolean resume) {
wsClient.sendToDebugger("DEBUG_STOP", new JSONBuilder()
.put("msg", "Stop debugging")
.toJSONObject());
if (debuggable != null) {
debuggable.stopDebug(resume);
debuggable = null;
}
}
private DoricContextDebuggable doricContextDebuggable;
@Subscribe(threadMode = ThreadMode.MAIN)
public void onOpenEvent(OpenEvent openEvent) {
@ -78,10 +113,10 @@ public class DevKit implements IDevKit {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onQuitDebugEvent(StopDebugEvent quitDebugEvent) {
doricContextDebuggable.stopDebug();
stopDebugging(true);
}
public DoricContext requestDebugContext(String source) {
public DoricContext matchContext(String source) {
for (DoricContext context : DoricContextManager.aliveContexts()) {
if (source.contains(context.getSource()) || context.getSource().equals("__dev__")) {
return context;
@ -91,16 +126,14 @@ public class DevKit implements IDevKit {
}
public void reload(String source, String script) {
for (DoricContext context : DoricContextManager.aliveContexts()) {
if (doricContextDebuggable != null &&
doricContextDebuggable.isDebugging &&
doricContextDebuggable.getContext().getContextId().equals(context.getContextId())) {
System.out.println("is debugging context id: " + context.getContextId());
DoricContext context = matchContext(source);
if (context == null) {
DoricLog.d("Cannot find context source %s for reload", source);
} else if (context.getDriver() instanceof DoricDebugDriver) {
DoricLog.d("Context source %s in debugging,skip reload", source);
} else {
if (source.contains(context.getSource()) || context.getSource().equals("__dev__")) {
DoricLog.d("Context reload :id %s,source %s ", context.getContextId(), source);
context.reload(script);
}
}
}
}
}

View File

@ -5,34 +5,28 @@ import pub.doric.IDoricDriver;
public class DoricContextDebuggable {
private final DoricContext doricContext;
private DoricDebugDriver debugDriver;
private final IDoricDriver nativeDriver;
public boolean isDebugging = false;
private final WSClient wsClient;
public DoricContextDebuggable(DoricContext doricContext) {
public DoricContextDebuggable(WSClient wsClient, DoricContext doricContext) {
this.wsClient = wsClient;
this.doricContext = doricContext;
this.isDebugging = true;
this.nativeDriver = this.doricContext.getDriver();
}
public void startDebug() {
debugDriver = new DoricDebugDriver(new IStatusCallback() {
@Override
public void start() {
doricContext.setDriver(debugDriver);
doricContext.setDriver(new DoricDebugDriver(this.wsClient));
doricContext.reload(doricContext.getScript());
}
});
}
public void stopDebug() {
isDebugging = false;
public void stopDebug(boolean resume) {
IDoricDriver doricDriver = doricContext.getDriver();
if (doricDriver instanceof DoricDebugDriver) {
((DoricDebugDriver) doricDriver).destroy();
}
if (resume) {
doricContext.setDriver(nativeDriver);
debugDriver.destroy();
doricContext.reload(doricContext.getScript());
}
public DoricContext getContext() {
return doricContext;
}
}

View File

@ -28,7 +28,6 @@ import pub.doric.DoricRegistry;
import pub.doric.IDoricDriver;
import pub.doric.async.AsyncCall;
import pub.doric.async.AsyncResult;
import pub.doric.engine.DoricJSEngine;
import pub.doric.utils.DoricConstant;
import pub.doric.utils.DoricLog;
import pub.doric.utils.ThreadMode;
@ -39,17 +38,17 @@ import pub.doric.utils.ThreadMode;
* @CreateDate: 2019-07-18
*/
public class DoricDebugDriver implements IDoricDriver {
private final DoricJSEngine doricJSEngine;
private final DoricDebugJSEngine doricDebugJSEngine;
private final ExecutorService mBridgeExecutor;
private final Handler mUIHandler;
private final Handler mJSHandler;
private String theContextId = null;
public DoricDebugDriver(IStatusCallback statusCallback) {
doricJSEngine = new DoricDebugJSEngine(statusCallback);
public DoricDebugDriver(WSClient wsClient) {
doricDebugJSEngine = new DoricDebugJSEngine(wsClient);
mBridgeExecutor = Executors.newCachedThreadPool();
mUIHandler = new Handler(Looper.getMainLooper());
mJSHandler = doricJSEngine.getJSHandler();
mJSHandler = doricDebugJSEngine.getJSHandler();
}
@Override
@ -69,7 +68,7 @@ public class DoricDebugDriver implements IDoricDriver {
@Override
public JSDecoder call() {
try {
return doricJSEngine.invokeDoricMethod(method, args);
return doricDebugJSEngine.invokeDoricMethod(method, args);
} catch (Exception e) {
DoricLog.e("invokeDoricMethod(%s,...),error is %s", method, e.getLocalizedMessage());
return new JSDecoder(null);
@ -97,7 +96,7 @@ public class DoricDebugDriver implements IDoricDriver {
@Override
public Boolean call() {
try {
doricJSEngine.prepareContext(contextId, script, source);
theContextId = contextId;
return true;
} catch (Exception e) {
DoricLog.e("createContext %s error is %s", source, e.getLocalizedMessage());
@ -113,7 +112,9 @@ public class DoricDebugDriver implements IDoricDriver {
@Override
public Boolean call() {
try {
doricJSEngine.destroyContext(contextId);
if (contextId.equals(theContextId)) {
DevKit.getInstance().stopDebugging(false);
}
return true;
} catch (Exception e) {
DoricLog.e("destroyContext %s error is %s", contextId, e.getLocalizedMessage());
@ -125,11 +126,11 @@ public class DoricDebugDriver implements IDoricDriver {
@Override
public DoricRegistry getRegistry() {
return doricJSEngine.getRegistry();
return doricDebugJSEngine.getRegistry();
}
public void destroy() {
doricJSEngine.teardown();
doricDebugJSEngine.teardown();
mBridgeExecutor.shutdown();
}
}

View File

@ -4,16 +4,15 @@ import pub.doric.devkit.remote.DoricRemoteJSExecutor;
import pub.doric.engine.DoricJSEngine;
public class DoricDebugJSEngine extends DoricJSEngine {
private final WSClient wsClient;
private IStatusCallback statusCallback;
public DoricDebugJSEngine(IStatusCallback statusCallback) {
public DoricDebugJSEngine(WSClient wsClient) {
super();
this.statusCallback = statusCallback;
this.wsClient = wsClient;
}
@Override
protected void initJSEngine() {
mDoricJSE = new DoricRemoteJSExecutor(statusCallback);
mDoricJSE = new DoricRemoteJSExecutor(this.wsClient);
}
}

View File

@ -14,4 +14,8 @@ public interface IDevKit {
void sendDevCommand(IDevKit.Command command, JSONObject jsonObject);
void disconnectDevKit();
void startDebugging(String source);
void stopDebugging(boolean resume);
}

View File

@ -1,5 +0,0 @@
package pub.doric.devkit;
public interface IStatusCallback {
void start();
}

View File

@ -23,6 +23,8 @@ import org.json.JSONObject;
import java.io.EOFException;
import java.net.ConnectException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
@ -43,6 +45,12 @@ import pub.doric.devkit.event.OpenEvent;
public class WSClient extends WebSocketListener {
private final WebSocket webSocket;
public interface Interceptor {
boolean intercept(String type, String command, JSONObject payload) throws JSONException;
}
private Set<Interceptor> interceptors = new HashSet<>();
public WSClient(String url) {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
@ -53,6 +61,15 @@ public class WSClient extends WebSocketListener {
webSocket = okHttpClient.newWebSocket(request, this);
}
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
public void removeInterceptor(Interceptor interceptor) {
interceptors.remove(interceptor);
}
public void close() {
webSocket.close(1000, "Close");
}
@ -72,23 +89,21 @@ public class WSClient extends WebSocketListener {
String type = jsonObject.optString("type");
String cmd = jsonObject.optString("cmd");
JSONObject payload = jsonObject.optJSONObject("payload");
if ("D2C".equals(type)) {
for (Interceptor interceptor : interceptors) {
if (interceptor.intercept(type, cmd, payload)) {
return;
}
}
if ("DEBUG_REQ".equals(cmd)) {
String source = payload.optString("source");
DoricContext context = DevKit.getInstance().requestDebugContext(source);
sendToDebugger("DEBUG_RES", new JSONBuilder()
.put("contextId", context == null ? "" : context.getContextId())
.toJSONObject());
}
} else if ("S2C".equals(type)) {
if ("RELOAD".equals(cmd)) {
DevKit.getInstance().startDebugging(source);
} else if ("DEBUG_STOP".equals(cmd)) {
DevKit.getInstance().stopDebugging(true);
} else if ("RELOAD".equals(cmd)) {
String source = payload.optString("source");
String script = payload.optString("script");
DevKit.getInstance().reload(source, script);
}
}
} catch (JSONException e) {
e.printStackTrace();
}

View File

@ -20,15 +20,15 @@ import com.github.pengfeizhou.jscore.JSRuntimeException;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import pub.doric.devkit.IStatusCallback;
import pub.doric.devkit.WSClient;
import pub.doric.engine.IDoricJSE;
public class DoricRemoteJSExecutor implements IDoricJSE {
private final RemoteJSExecutor mRemoteJSExecutor;
public DoricRemoteJSExecutor(IStatusCallback statusCallback) {
this.mRemoteJSExecutor = new RemoteJSExecutor(statusCallback);
public DoricRemoteJSExecutor(WSClient wsClient) {
this.mRemoteJSExecutor = new RemoteJSExecutor(wsClient);
}
@Override

View File

@ -5,102 +5,26 @@ import com.github.pengfeizhou.jscore.JSONBuilder;
import com.github.pengfeizhou.jscore.JavaFunction;
import com.github.pengfeizhou.jscore.JavaValue;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.EOFException;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.Map;
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;
import pub.doric.devkit.DevKit;
import pub.doric.devkit.IStatusCallback;
import pub.doric.devkit.event.StopDebugEvent;
import pub.doric.devkit.WSClient;
public class RemoteJSExecutor {
private final WebSocket webSocket;
public class RemoteJSExecutor implements WSClient.Interceptor {
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
private JSDecoder temp;
private final WSClient wsClient;
private final Thread currentThread;
public RemoteJSExecutor(final IStatusCallback statusCallback) {
OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.build();
final Request request = new Request.Builder().url("ws://" + DevKit.ip + ":2080").build();
final Thread current = Thread.currentThread();
webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
LockSupport.unpark(current);
statusCallback.start();
}
@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) {
// 被远端强制断开
System.out.println("remote js executor eof");
LockSupport.unpark(current);
EventBus.getDefault().post(new StopDebugEvent());
}
}
@Override
public void onMessage(WebSocket webSocket, String text) {
try {
JSONObject jsonObject = new JSONObject(text);
String cmd = jsonObject.optString("cmd");
switch (cmd) {
case "injectGlobalJSFunction": {
String name = jsonObject.optString("name");
JSONArray arguments = jsonObject.optJSONArray("arguments");
assert arguments != null;
JSDecoder[] decoders = new JSDecoder[arguments.length()];
for (int i = 0; i < arguments.length(); i++) {
Object o = arguments.get(i);
decoders[i] = new JSDecoder(new ValueBuilder(o).build());
}
globalFunctions.get(name).exec(decoders);
}
break;
case "invokeMethod": {
try {
Object result = jsonObject.opt("result");
ValueBuilder vb = new ValueBuilder(result);
temp = new JSDecoder(vb.build());
System.out.println(result);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
LockSupport.unpark(current);
}
}
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
LockSupport.park(current);
public RemoteJSExecutor(WSClient wsClient) {
this.wsClient = wsClient;
this.wsClient.addInterceptor(this);
currentThread = Thread.currentThread();
}
public String loadJS(String script, String source) {
@ -113,17 +37,22 @@ public class RemoteJSExecutor {
public void injectGlobalJSFunction(String name, JavaFunction javaFunction) {
globalFunctions.put(name, javaFunction);
webSocket.send(new JSONBuilder().put("cmd", "injectGlobalJSFunction")
.put("name", name).toString()
);
wsClient.sendToDebugger(
"injectGlobalJSFunction",
new JSONBuilder()
.put("cmd", "injectGlobalJSFunction")
.put("name", name)
.toJSONObject());
}
public void injectGlobalJSObject(String name, JavaValue javaValue) {
webSocket.send(new JSONBuilder().put("cmd", "injectGlobalJSObject")
wsClient.sendToDebugger(
"injectGlobalJSObject",
new JSONBuilder()
.put("name", name)
.put("type", javaValue.getType())
.put("value", javaValue.getValue()).toString()
);
.put("value", javaValue.getValue())
.toJSONObject());
}
public JSDecoder invokeMethod(String objectName, String functionName, JavaValue[] javaValues, boolean hashKey) {
@ -134,19 +63,60 @@ public class RemoteJSExecutor {
.put("value", javaValue.getValue())
.toJSONObject());
}
webSocket.send(new JSONBuilder()
wsClient.sendToDebugger(
"invokeMethod",
new JSONBuilder()
.put("cmd", "invokeMethod")
.put("objectName", objectName)
.put("functionName", functionName)
.put("values", jsonArray)
.put("hashKey", hashKey)
.toString());
.toJSONObject());
LockSupport.park(Thread.currentThread());
return temp;
}
public void destroy() {
webSocket.close(1000, "destroy");
wsClient.sendToDebugger("DEBUG_STOP", null);
wsClient.removeInterceptor(this);
}
@Override
public boolean intercept(String type, String cmd, JSONObject payload) throws JSONException {
if ("D2C".equals(type)) {
switch (cmd) {
case "injectGlobalJSFunction": {
String name = payload.optString("name");
JSONArray arguments = payload.optJSONArray("arguments");
assert arguments != null;
JSDecoder[] decoders = new JSDecoder[arguments.length()];
for (int i = 0; i < arguments.length(); i++) {
Object o = arguments.get(i);
decoders[i] = new JSDecoder(new ValueBuilder(o).build());
}
globalFunctions.get(name).exec(decoders);
}
break;
case "invokeMethod": {
try {
Object result = payload.opt("result");
ValueBuilder vb = new ValueBuilder(result);
temp = new JSDecoder(vb.build());
System.out.println(result);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
LockSupport.unpark(currentThread);
}
}
break;
default:
break;
}
return true;
}
return false;
}
}

View File

@ -19,6 +19,8 @@ import android.animation.AnimatorSet;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
@ -209,6 +211,7 @@ public class DoricContext {
mPluginMap.clear();
this.script = script;
this.mRootNode.setId("");
this.mRootNode.clearSubModel();
getDriver().createContext(mContextId, script, source);
init(this.extra);
callEntity(DoricConstant.DORIC_ENTITY_CREATE);

View File

@ -6,13 +6,7 @@
"request": "launch",
"name": "Doric Debugger",
"program": "${workspaceFolder}/${relativeFile}",
"preLaunchTask": "Doric Build",
"sourceMaps": true,
"serverReadyAction": {
"pattern": "listening on port ([0-9]+)",
"uriFormat": "http://localhost:%s",
"action": "openExternally"
},
"outFiles": [
"${workspaceFolder}/bundle/**/*.js"
]

View File

@ -1,10 +1,5 @@
import fs from "fs";
import WebSocket from "ws"
import "colors";
import path from "path";
import { delay, glob } from "./util";
import { Shell } from "./shell";
export type MSG = {
type: "D2C" | "C2D" | "C2S" | "D2S" | "S2C" | "S2D",
@ -13,59 +8,43 @@ export type MSG = {
}
export async function createServer() {
let contextId: string = "0"
let clientConnection: WebSocket | undefined = undefined
let debuggerConnection: WebSocket | undefined = undefined
let client: WebSocket | undefined = undefined;
let debug: WebSocket | undefined = undefined;
let deviceId = 0
return new WebSocket.Server({ port: 7777 })
const wss = new WebSocket.Server({ port: 7777 })
.on("connection", (ws, request) => {
let thisDeviceId: string
console.log('Connected', request.headers.host)
if (request.headers.host?.startsWith("localhost")) {
thisDeviceId = `Debugger#${deviceId++}`
console.log(`Debugger ${thisDeviceId} attached to dev kit`.green)
debuggerConnection = ws
clientConnection?.send(JSON.stringify({
cmd: 'SWITCH_TO_DEBUG',
contextId: contextId
}))
console.log(`${thisDeviceId} attached to dev kit`.green)
debug = ws;
} else {
thisDeviceId = `Client#${deviceId++}`
console.log(`${thisDeviceId} attached to dev kit`.green)
}
ws.on('message', async function (result: string) {
const resultObject = JSON.parse(result) as MSG
if (resultObject.type === "D2C" || resultObject.type === "C2D") {
ws.send(result);
if (resultObject.type === "D2C") {
if (client === undefined) {
wss?.clients.forEach(e => {
e.send(result);
})
} else {
client.send(result);
}
} else if (resultObject.type === "C2D") {
if (resultObject.cmd === "DEBUG_STOP") {
client = undefined;
}
if (client === undefined) {
client = ws;
} else if (client !== ws) {
console.log("Can only debugging one client at the same time.".red);
}
debug?.send(result);
} else if (resultObject.type === "C2S") {
switch (resultObject.cmd) {
case 'DEBUG':
clientConnection = ws;
(ws as any).debugging = true;
console.log("Enter debugging");
contextId = resultObject.payload.contextId;
const projectHome = '.';
await fs.promises.writeFile(path.resolve(projectHome, "build", "context"), contextId, "utf-8");
let source = resultObject.payload.source as string;
if (source.startsWith(".js")) {
source = source.replace(".js", ".ts");
} else if (!source.startsWith(".ts")) {
source = source + ".ts"
}
let sourceFile = path.resolve(projectHome, "src", source);
if (!fs.existsSync(sourceFile)) {
const tsFiles = await glob(source, {
cwd: path.resolve(projectHome, "src")
})
if (!!!tsFiles || tsFiles.length === 0) {
console.error(`Cannot find ${source} in ${path.resolve(projectHome)}`);
}
sourceFile = tsFiles[0];
}
console.log(thisDeviceId + " request debug, project home: " + projectHome);
await Shell.exec("code", [projectHome, sourceFile]);
await delay(1500);
break;
case 'EXCEPTION':
console.log(resultObject.payload.source.red);
console.log(resultObject.payload.exception.red);
@ -87,19 +66,38 @@ export async function createServer() {
break
}
}
})
ws.on('connect', function (code: number) {
console.log('connect', code)
})
});
ws.on('close', function (code: number) {
console.log('close: code = ' + code, thisDeviceId)
console.log('close: code = ' + code, thisDeviceId);
(ws as any).debugging = false;
if (ws === debug) {
console.log("quit debugging");
(ws as any).debugging = false
})
client?.send(JSON.stringify({
type: "S2C",
cmd: "DEBUG_STOP"
} as MSG));
}
if (ws === client) {
console.log("quit debugging");
client = undefined
}
});
ws.on('error', function (code: number) {
console.log('error', code)
})
})
if (ws === debug) {
console.log("quit debugging");
client?.send(JSON.stringify({
type: "S2C",
cmd: "DEBUG_STOP"
} as MSG));
}
if (ws === client) {
console.log("quit debugging");
client = undefined
}
});
});
return wss;
}

View File

@ -9,13 +9,7 @@
"request": "launch",
"name": "Doric Debugger",
"program": "${workspaceFolder}/${relativeFile}",
"preLaunchTask": "Doric Build",
"sourceMaps": true,
"serverReadyAction": {
"pattern": "listening on port ([0-9]+)",
"uriFormat": "http://localhost:%s",
"action": "openExternally"
},
"outFiles": [
"${workspaceFolder}/bundle/**/*.js"
]

View File

@ -4236,33 +4236,111 @@ function initNativeEnvironment(source) {
return __awaiter$1(this, void 0, void 0, function* () {
// dev kit client
return new Promise((resolve, reject) => {
const devClient = new WebSocket__default['default']('ws://localhost:7777');
devClient.on('open', () => {
const ws = new WebSocket__default['default']('ws://localhost:7777')
.on('open', () => {
console.log('Connectted Devkit on port', '7777');
devClient.send(JSON.stringify({
ws.send(JSON.stringify({
type: "D2C",
payload: {
cmd: "DEBUG_REQ",
payload: {
source,
},
}));
});
devClient.on('message', (data) => {
console.log(data);
})
.on('message', (data) => {
var _a;
const msg = JSON.parse(data);
switch (msg.cwd) {
const payload = msg.payload;
switch (msg.cmd) {
case "DEBUG_RES":
const contextId = msg.contextId;
if ((contextId === null || contextId === void 0 ? void 0 : contextId.length) > 0) {
const contextId = msg.payload.contextId;
resolve(contextId);
break;
case "injectGlobalJSObject":
console.log("injectGlobalJSObject", payload);
const type = payload.type;
const value = payload.value;
let arg;
if (type === 0) {
arg = null;
}
else {
reject(`Cannot find applicable context in client for source ${source}`);
else if (type === 1) {
arg = parseFloat(value);
}
else if (type === 2) {
arg = (value == 'true');
}
else if (type === 3) {
arg = value.toString();
}
else if (type === 4) {
arg = JSON.parse(value);
}
else if (type === 5) {
arg = JSON.parse(value);
}
Reflect.set(global$2, payload.name, arg);
break;
case "injectGlobalJSFunction":
console.log("injectGlobalJSFunction", payload);
Reflect.set(global$2, payload.name, function () {
let args = [].slice.call(arguments);
console.log(args);
console.log("injected", payload.name, args);
ws.send(JSON.stringify({
type: "D2C",
cmd: 'injectGlobalJSFunction',
payload: {
name: payload.name,
arguments: args
}
}));
});
break;
case "invokeMethod":
console.log("invokeMethod", payload);
const values = payload.values;
let args = [];
for (let i = 0; i < values.length; i++) {
let value = values[i];
if (value.type === 0) {
args.push(null);
}
else if (value.type === 1) {
args.push(parseFloat(value.value));
}
else if (value.type === 2) {
args.push((value.value == 'true'));
}
else if (value.type === 3) {
args.push(value.value.toString());
}
else if (value.type === 4) {
args.push(JSON.parse(value.value));
}
else if (value.type === 5) {
args.push(JSON.parse(value.value));
}
}
const object = Reflect.get(global$2, payload.objectName);
const method = Reflect.get(object, payload.functionName);
const result = Reflect.apply(method, undefined, args);
console.log(result);
ws.send(JSON.stringify({
type: "D2C",
cmd: 'invokeMethod',
payload: {
result
}
}));
break;
case "DEBUG_STOP":
console.log(((_a = msg.payload) === null || _a === void 0 ? void 0 : _a.msg) || "Stop debugging");
process.exit(0);
break;
}
});
devClient.on('error', (error) => {
})
.on('error', (error) => {
console.log(error);
reject(error);
});
@ -4287,98 +4365,10 @@ global$2.Entry = function () {
console.log("debugging context id: " + contextId);
global$2.context = jsObtainContext(contextId);
Reflect.apply(jsObtainEntry(contextId), doric, args);
}).catch(error => console.error(error));
});
return arguments[0];
}
};
// debug server
const debugServer = new WebSocket__default['default'].Server({ port: 2080 });
debugServer.on('connection', (ws) => {
console.log('connected');
ws.on('message', (message) => {
let messageObject = JSON.parse(message);
switch (messageObject.cmd) {
case "injectGlobalJSObject":
console.log(messageObject.name);
let type = messageObject.type;
let value = messageObject.value;
let arg;
if (type.type === 0) {
arg = null;
}
else if (type === 1) {
arg = parseFloat(value);
}
else if (type === 2) {
arg = (value == 'true');
}
else if (type === 3) {
arg = value.toString();
}
else if (type === 4) {
arg = JSON.parse(value);
}
else if (type === 5) {
arg = JSON.parse(value);
}
Reflect.set(global$2, messageObject.name, arg);
break;
case "injectGlobalJSFunction":
console.log(messageObject.name);
Reflect.set(global$2, messageObject.name, function () {
let args = [].slice.call(arguments);
console.log("===============================");
console.log(args);
console.log("===============================");
ws.send(JSON.stringify({
cmd: 'injectGlobalJSFunction',
name: messageObject.name,
arguments: args
}));
});
break;
case "invokeMethod":
console.log(messageObject.objectName);
console.log(messageObject.functionName);
let args = [];
for (let i = 0; i < messageObject.values.length; i++) {
let value = messageObject.values[i];
if (value.type === 0) {
args.push(null);
}
else if (value.type === 1) {
args.push(parseFloat(value.value));
}
else if (value.type === 2) {
args.push((value.value == 'true'));
}
else if (value.type === 3) {
args.push(value.value.toString());
}
else if (value.type === 4) {
args.push(JSON.parse(value.value));
}
else if (value.type === 5) {
args.push(JSON.parse(value.value));
}
}
console.log(args);
console.log(messageObject.hashKey);
let object = Reflect.get(global$2, messageObject.objectName);
let method = Reflect.get(object, messageObject.functionName);
let result = Reflect.apply(method, undefined, args);
console.log(result);
ws.send(JSON.stringify({
cmd: 'invokeMethod',
result: result
}));
break;
}
});
});
debugServer.on('listening', function connection(ws) {
console.log('debugger server started on 2080');
});
global$2.injectGlobal = (objName, obj) => {
Reflect.set(global$2, objName, JSON.parse(obj));
};

View File

@ -20,7 +20,7 @@ import path from 'path'
type MSG = {
type: "D2C" | "C2D" | "C2S" | "D2S" | "S2C" | "S2D",
cmd: string,
payload: { [index: string]: string }
payload: { [index: string]: string | number | { type: number, value: string }[] }
}
let contextId: string | undefined = undefined;
@ -36,32 +36,100 @@ global.doric = doric
async function initNativeEnvironment(source: string) {
// dev kit client
return new Promise<string>((resolve, reject) => {
const devClient = new WebSocket('ws://localhost:7777')
devClient.on('open', () => {
const ws = new WebSocket('ws://localhost:7777')
.on('open', () => {
console.log('Connectted Devkit on port', '7777')
devClient.send(JSON.stringify({
ws.send(JSON.stringify({
type: "D2C",
payload: {
cmd: "DEBUG_REQ",
payload: {
source,
},
}))
} as MSG))
})
devClient.on('message', (data) => {
console.log(data)
const msg = JSON.parse(data as string) as { type: string, cwd: string, [idx: string]: string }
switch (msg.cwd) {
.on('message', (data) => {
const msg = JSON.parse(data as string) as MSG
const payload = msg.payload
switch (msg.cmd) {
case "DEBUG_RES":
const contextId = msg.contextId;
if (contextId?.length > 0) {
resolve(contextId)
} else {
reject(`Cannot find applicable context in client for source ${source}`)
const contextId = msg.payload.contextId as string;
resolve(contextId);
break;
case "injectGlobalJSObject":
console.log("injectGlobalJSObject", payload);
const type = payload.type as number
const value = payload.value as string
let arg
if (type === 0) {
arg = null
} else if (type === 1) {
arg = parseFloat(value)
} else if (type === 2) {
arg = (value == 'true')
} else if (type === 3) {
arg = value.toString()
} else if (type === 4) {
arg = JSON.parse(value)
} else if (type === 5) {
arg = JSON.parse(value)
}
Reflect.set(global, payload.name as string, arg)
break
case "injectGlobalJSFunction":
console.log("injectGlobalJSFunction", payload);
Reflect.set(global, payload.name as string, function () {
let args = [].slice.call(arguments)
console.log(args)
console.log("injected", payload.name, args)
ws.send(JSON.stringify({
type: "D2C",
cmd: 'injectGlobalJSFunction',
payload: {
name: payload.name,
arguments: args
}
} as MSG))
})
break
case "invokeMethod":
console.log("invokeMethod", payload)
const values = payload.values as { type: number, value: string }[]
let args = []
for (let i = 0; i < values.length; i++) {
let value = values[i]
if (value.type === 0) {
args.push(null)
} else if (value.type === 1) {
args.push(parseFloat(value.value))
} else if (value.type === 2) {
args.push((value.value == 'true'))
} else if (value.type === 3) {
args.push(value.value.toString())
} else if (value.type === 4) {
args.push(JSON.parse(value.value))
} else if (value.type === 5) {
args.push(JSON.parse(value.value))
}
}
const object = Reflect.get(global, payload.objectName as string)
const method = Reflect.get(object, payload.functionName as string)
const result = Reflect.apply(method, undefined, args)
console.log(result)
ws.send(JSON.stringify({
type: "D2C",
cmd: 'invokeMethod',
payload: {
result
}
} as MSG))
break;
case "DEBUG_STOP":
console.log(msg.payload?.msg || "Stop debugging");
process.exit(0);
break;
}
})
devClient.on('error', (error) => {
.on('error', (error) => {
console.log(error)
reject(error)
})
@ -87,94 +155,11 @@ global.Entry = function () {
console.log("debugging context id: " + contextId);
global.context = doric.jsObtainContext(contextId);
Reflect.apply(doric.jsObtainEntry(contextId), doric, args);
}).catch(error => console.error(error));
});
return arguments[0];
}
}
// debug server
const debugServer = new WebSocket.Server({ port: 2080 })
debugServer.on('connection', (ws) => {
console.log('connected')
ws.on('message', (message: string) => {
let messageObject = JSON.parse(message)
switch (messageObject.cmd) {
case "injectGlobalJSObject":
console.log(messageObject.name)
let type = messageObject.type
let value = messageObject.value
let arg
if (type.type === 0) {
arg = null
} else if (type === 1) {
arg = parseFloat(value)
} else if (type === 2) {
arg = (value == 'true')
} else if (type === 3) {
arg = value.toString()
} else if (type === 4) {
arg = JSON.parse(value)
} else if (type === 5) {
arg = JSON.parse(value)
}
Reflect.set(global, messageObject.name, arg)
break
case "injectGlobalJSFunction":
console.log(messageObject.name)
Reflect.set(global, messageObject.name, function () {
let args = [].slice.call(arguments)
console.log("===============================")
console.log(args)
console.log("===============================")
ws.send(JSON.stringify({
cmd: 'injectGlobalJSFunction',
name: messageObject.name,
arguments: args
}))
})
break
case "invokeMethod":
console.log(messageObject.objectName)
console.log(messageObject.functionName)
let args = []
for (let i = 0; i < messageObject.values.length; i++) {
let value = messageObject.values[i]
if (value.type === 0) {
args.push(null)
} else if (value.type === 1) {
args.push(parseFloat(value.value))
} else if (value.type === 2) {
args.push((value.value == 'true'))
} else if (value.type === 3) {
args.push(value.value.toString())
} else if (value.type === 4) {
args.push(JSON.parse(value.value))
} else if (value.type === 5) {
args.push(JSON.parse(value.value))
}
}
console.log(args)
console.log(messageObject.hashKey)
let object = Reflect.get(global, messageObject.objectName)
let method = Reflect.get(object, messageObject.functionName)
let result = Reflect.apply(method, undefined, args)
console.log(result)
ws.send(JSON.stringify({
cmd: 'invokeMethod',
result: result
}))
break
}
})
})
debugServer.on('listening', function connection(ws: WebSocket) {
console.log('debugger server started on 2080')
})
global.injectGlobal = (objName: string, obj: string) => {
Reflect.set(global, objName, JSON.parse(obj))
}

View File

@ -36,33 +36,111 @@ function initNativeEnvironment(source) {
return __awaiter(this, void 0, void 0, function* () {
// dev kit client
return new Promise((resolve, reject) => {
const devClient = new WebSocket('ws://localhost:7777');
devClient.on('open', () => {
const ws = new WebSocket('ws://localhost:7777')
.on('open', () => {
console.log('Connectted Devkit on port', '7777');
devClient.send(JSON.stringify({
ws.send(JSON.stringify({
type: "D2C",
payload: {
cmd: "DEBUG_REQ",
payload: {
source,
},
}));
});
devClient.on('message', (data) => {
console.log(data);
})
.on('message', (data) => {
var _a;
const msg = JSON.parse(data);
switch (msg.cwd) {
const payload = msg.payload;
switch (msg.cmd) {
case "DEBUG_RES":
const contextId = msg.contextId;
if ((contextId === null || contextId === void 0 ? void 0 : contextId.length) > 0) {
const contextId = msg.payload.contextId;
resolve(contextId);
break;
case "injectGlobalJSObject":
console.log("injectGlobalJSObject", payload);
const type = payload.type;
const value = payload.value;
let arg;
if (type === 0) {
arg = null;
}
else {
reject(`Cannot find applicable context in client for source ${source}`);
else if (type === 1) {
arg = parseFloat(value);
}
else if (type === 2) {
arg = (value == 'true');
}
else if (type === 3) {
arg = value.toString();
}
else if (type === 4) {
arg = JSON.parse(value);
}
else if (type === 5) {
arg = JSON.parse(value);
}
Reflect.set(global, payload.name, arg);
break;
case "injectGlobalJSFunction":
console.log("injectGlobalJSFunction", payload);
Reflect.set(global, payload.name, function () {
let args = [].slice.call(arguments);
console.log(args);
console.log("injected", payload.name, args);
ws.send(JSON.stringify({
type: "D2C",
cmd: 'injectGlobalJSFunction',
payload: {
name: payload.name,
arguments: args
}
}));
});
break;
case "invokeMethod":
console.log("invokeMethod", payload);
const values = payload.values;
let args = [];
for (let i = 0; i < values.length; i++) {
let value = values[i];
if (value.type === 0) {
args.push(null);
}
else if (value.type === 1) {
args.push(parseFloat(value.value));
}
else if (value.type === 2) {
args.push((value.value == 'true'));
}
else if (value.type === 3) {
args.push(value.value.toString());
}
else if (value.type === 4) {
args.push(JSON.parse(value.value));
}
else if (value.type === 5) {
args.push(JSON.parse(value.value));
}
}
const object = Reflect.get(global, payload.objectName);
const method = Reflect.get(object, payload.functionName);
const result = Reflect.apply(method, undefined, args);
console.log(result);
ws.send(JSON.stringify({
type: "D2C",
cmd: 'invokeMethod',
payload: {
result
}
}));
break;
case "DEBUG_STOP":
console.log(((_a = msg.payload) === null || _a === void 0 ? void 0 : _a.msg) || "Stop debugging");
process.exit(0);
break;
}
});
devClient.on('error', (error) => {
})
.on('error', (error) => {
console.log(error);
reject(error);
});
@ -87,98 +165,10 @@ global.Entry = function () {
console.log("debugging context id: " + contextId);
global.context = doric.jsObtainContext(contextId);
Reflect.apply(doric.jsObtainEntry(contextId), doric, args);
}).catch(error => console.error(error));
});
return arguments[0];
}
};
// debug server
const debugServer = new WebSocket.Server({ port: 2080 });
debugServer.on('connection', (ws) => {
console.log('connected');
ws.on('message', (message) => {
let messageObject = JSON.parse(message);
switch (messageObject.cmd) {
case "injectGlobalJSObject":
console.log(messageObject.name);
let type = messageObject.type;
let value = messageObject.value;
let arg;
if (type.type === 0) {
arg = null;
}
else if (type === 1) {
arg = parseFloat(value);
}
else if (type === 2) {
arg = (value == 'true');
}
else if (type === 3) {
arg = value.toString();
}
else if (type === 4) {
arg = JSON.parse(value);
}
else if (type === 5) {
arg = JSON.parse(value);
}
Reflect.set(global, messageObject.name, arg);
break;
case "injectGlobalJSFunction":
console.log(messageObject.name);
Reflect.set(global, messageObject.name, function () {
let args = [].slice.call(arguments);
console.log("===============================");
console.log(args);
console.log("===============================");
ws.send(JSON.stringify({
cmd: 'injectGlobalJSFunction',
name: messageObject.name,
arguments: args
}));
});
break;
case "invokeMethod":
console.log(messageObject.objectName);
console.log(messageObject.functionName);
let args = [];
for (let i = 0; i < messageObject.values.length; i++) {
let value = messageObject.values[i];
if (value.type === 0) {
args.push(null);
}
else if (value.type === 1) {
args.push(parseFloat(value.value));
}
else if (value.type === 2) {
args.push((value.value == 'true'));
}
else if (value.type === 3) {
args.push(value.value.toString());
}
else if (value.type === 4) {
args.push(JSON.parse(value.value));
}
else if (value.type === 5) {
args.push(JSON.parse(value.value));
}
}
console.log(args);
console.log(messageObject.hashKey);
let object = Reflect.get(global, messageObject.objectName);
let method = Reflect.get(object, messageObject.functionName);
let result = Reflect.apply(method, undefined, args);
console.log(result);
ws.send(JSON.stringify({
cmd: 'invokeMethod',
result: result
}));
break;
}
});
});
debugServer.on('listening', function connection(ws) {
console.log('debugger server started on 2080');
});
global.injectGlobal = (objName, obj) => {
Reflect.set(global, objName, JSON.parse(obj));
};