Skip to content
This repository has been archived by the owner on Jul 28, 2023. It is now read-only.

feat(frontend): added node worker support #281

Merged
merged 1 commit into from
Jul 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions front_end/ndb.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"modules" : [
{ "name": "ndb_sdk", "type": "autostart" },
{ "name": "ndb", "type": "autostart" },
{ "name": "layer_viewer" },
{ "name": "timeline_model" },
Expand Down
22 changes: 17 additions & 5 deletions front_end/ndb/NdbMain.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ Ndb.NdbMain = class extends Common.Object {
const {cwd} = await Ndb.processInfo();
await Ndb.nodeProcessManager.addFileSystem(cwd);

// TODO(ak239): we do not want to create this model for workers, so we need a way to add custom capabilities.
SDK.SDKModel.register(NdbSdk.NodeWorkerModel, SDK.Target.Capability.JS, true);
SDK.SDKModel.register(NdbSdk.NodeRuntimeModel, SDK.Target.Capability.JS, true);

await new Promise(resolve => SDK.initMainConnection(resolve));
SDK.targetManager.createTarget('<root>', ls`Root`, SDK.Target.Type.Browser, null);
if (Common.moduleSetting('autoStartMain').get()) {
Expand Down Expand Up @@ -151,6 +155,8 @@ Ndb.NodeProcessManager = class extends Common.Object {
this._cpuProfiles = [];
this._targetManager.addModelListener(
SDK.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, this._onExecutionContextDestroyed, this);
this._targetManager.addModelListener(
NdbSdk.NodeRuntimeModel, NdbSdk.NodeRuntimeModel.Events.WaitingForDisconnect, this._onWaitingForDisconnect, this);
}

static async create(targetManager) {
Expand Down Expand Up @@ -191,7 +197,7 @@ Ndb.NodeProcessManager = class extends Common.Object {
const target = this._targetManager.createTarget(
info.id, userFriendlyName(info), SDK.Target.Type.Node,
this._targetManager.targetById(info.ppid) || this._targetManager.mainTarget(), undefined, false, connection);
target[Ndb._connectionSymbol] = connection;
target[NdbSdk.connectionSymbol] = connection;
await this.addFileSystem(info.cwd, info.scriptName);
if (info.scriptName) {
const scriptURL = Common.ParsedURL.platformPathToURL(info.scriptName);
Expand Down Expand Up @@ -234,10 +240,14 @@ Ndb.NodeProcessManager = class extends Common.Object {
const executionContext = event.data;
if (!executionContext.isDefault)
return;
const target = executionContext.target();
return this._onWaitingForDisconnect({data: executionContext.target()});
}

async _onWaitingForDisconnect(event) {
const target = event.data;
if (target.name() === 'repl')
this.startRepl();
if (this._profiling && this._profiling.has(target.id())) {
if (this._profiling && (this._profiling.has(target.id()) || this._profiling.has(target.parentTarget().id()))) {
this._cpuProfiles.push({
profile: await target.model(SDK.CPUProfilerModel).stopRecording(),
name: target.name(),
Expand All @@ -247,7 +257,7 @@ Ndb.NodeProcessManager = class extends Common.Object {
if (this._profiling.size === 0)
this._finishProfiling();
}
const connection = target[Ndb._connectionSymbol];
const connection = target[NdbSdk.connectionSymbol];
if (connection)
await connection.disconnect();
}
Expand Down Expand Up @@ -280,6 +290,7 @@ Ndb.NodeProcessManager = class extends Common.Object {
}

async profile(execPath, args, options) {
// TODO(ak239): move it out here.
await UI.viewManager.showView('timeline');
const action = UI.actionRegistry.action('timeline.toggle-recording');
await action.execute();
Expand All @@ -290,10 +301,11 @@ Ndb.NodeProcessManager = class extends Common.Object {
this._profilingNddData = '';
await Promise.all(SDK.targetManager.models(SDK.CPUProfilerModel).map(profiler => profiler.stopRecording()));
const controller = Timeline.TimelinePanel.instance()._controller;
const mainProfile = this._cpuProfiles.find(data => !data.id.includes('#'));
controller.traceEventsCollected([{
cat: SDK.TracingModel.DevToolsMetadataEventCategory,
name: TimelineModel.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage,
ph: 'M', pid: 1, tid: this._cpuProfiles[0].id, ts: 0,
ph: 'M', pid: 1, tid: mainProfile.id, ts: 0,
args: {data: {sessionId: 1}}
}]);
for (const {profile, name, id} of this._cpuProfiles) {
Expand Down
2 changes: 1 addition & 1 deletion front_end/ndb/module.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
"className": "Ndb.ContextMenuProvider"
}
],
"dependencies": ["common", "sdk", "bindings", "persistence", "components"],
"dependencies": ["common", "sdk", "ndb_sdk", "bindings", "persistence", "components"],
"scripts": [
"InspectorFrontendHostOverrides.js",
"Connection.js",
Expand Down
39 changes: 39 additions & 0 deletions front_end/ndb_sdk/NodeRuntime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Protocol.inspectorBackend.registerCommand('NodeRuntime.notifyWhenWaitingForDisconnect', [{'name': 'enabled', 'type': 'boolean', 'optional': false}], [], false);
Protocol.inspectorBackend.registerEvent('NodeRuntime.waitingForDisconnect', []);

NdbSdk.NodeRuntimeModel = class extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);

this._agent = target.nodeRuntimeAgent();
this.target().registerNodeRuntimeDispatcher(new NdbSdk.NodeRuntimeDispatcher(this));
this._agent.notifyWhenWaitingForDisconnect(true);
}

/**
* @param {string} sessionId
* @param {!Object} workerInfo
* @param {boolean} waitingForDebugger
*/
_waitingForDisconnect() {
this.dispatchEventToListeners(NdbSdk.NodeRuntimeModel.Events.WaitingForDisconnect, this.target());
}
};

/** @enum {symbol} */
NdbSdk.NodeRuntimeModel.Events = {
WaitingForDisconnect: Symbol('WaitingForDisconnect')
};

NdbSdk.NodeRuntimeDispatcher = class {
constructor(nodeRuntimeModel) {
this._nodeRuntimeModel = nodeRuntimeModel;
}

waitingForDisconnect() {
this._nodeRuntimeModel._waitingForDisconnect();
}
};
179 changes: 179 additions & 0 deletions front_end/ndb_sdk/NodeWorker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
Protocol.inspectorBackend.registerCommand('NodeWorker.enable', [{'name': 'waitForDebuggerOnStart', 'type': 'boolean', 'optional': false}], [], false);
Protocol.inspectorBackend.registerCommand('NodeWorker.disable', [], [], false);
Protocol.inspectorBackend.registerCommand('NodeWorker.sendMessageToWorker', [{'name': 'message', 'type': 'string', 'optional': false}, {'name': 'sessionId', 'type': 'string', 'optional': false}], [], false);
Protocol.inspectorBackend.registerCommand('NodeWorker.detach', [{'name': 'sessionId', 'type': 'string', 'optional': false}], [], false);
Protocol.inspectorBackend.registerEvent('NodeWorker.attachedToWorker', ['sessionId', 'workerInfo', 'waitingForDebugger']);
Protocol.inspectorBackend.registerEvent('NodeWorker.detachedFromWorker', ['sessionId']);
Protocol.inspectorBackend.registerEvent('NodeWorker.receivedMessageFromWorker', ['sessionId', 'message']);

NdbSdk.connectionSymbol = Symbol('connection');

NdbSdk.NodeWorkerModel = class extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);

this._sessions = new Map();
this._targets = new Map();
this._agent = target.nodeWorkerAgent();
this.target().registerNodeWorkerDispatcher(new NdbSdk.NodeWorkerDispatcher(this));
this._agent.invoke_enable({waitForDebuggerOnStart: true});
}

/**
* @param {string} message
* @param {string} sessionId
* @return {!Promise}
*/
sendMessageToWorker(message, sessionId) {
return this._agent.sendMessageToWorker(message, sessionId);
}

/**
* @param {string} sessionId
* @return {!Promise}
*/
detach(sessionId) {
return this._agent.detach(sessionId);
}

/**
* @override
*/
dispose() {
this._sessions.clear();
for (const target of this._targets.values()) {
SDK.targetManager.removeTarget(target);
target.dispose();
}
this._targets.clear();
}

/**
* @param {string} sessionId
* @param {!Object} workerInfo
* @param {boolean} waitingForDebugger
*/
_attachedToWorker(sessionId, workerInfo, waitingForDebugger) {
const id = this.target().id() + '#' + workerInfo.workerId;
const connection = new NdbSdk.NodeWorkerConnection(sessionId, this);
this._sessions.set(sessionId, connection);
const target = SDK.targetManager.createTarget(
id, workerInfo.title, SDK.Target.Type.Node, this.target(),
undefined, false, connection);
target[NdbSdk.connectionSymbol] = connection;
this._targets.set(sessionId, target);
target.runtimeAgent().runIfWaitingForDebugger();
}

/**
* @param {string} sessionId
*/
_detachedFromWorker(sessionId) {
const session = this._sessions.get(sessionId);
if (session) {
this._sessions.delete(sessionId);
const target = this._targets.get(sessionId);
if (target) {
SDK.targetManager.removeTarget(target);
target.dispose();
this._targets.delete(sessionId);
}
}
}

/**
* @param {string} sessionId
* @param {string} message
*/
_receivedMessageFromWorker(sessionId, message) {
const session = this._sessions.get(sessionId);
if (session)
session.receivedMessageFromWorker(message);
}
};

NdbSdk.NodeWorkerConnection = class {
constructor(sessionId, nodeWorkerModel) {
this._onMessage = null;
this._onDisconnect = null;
this._sessionId = sessionId;
this._nodeWorkerModel = nodeWorkerModel;
}

/**
* @param {function((!Object|string))} onMessage
*/
setOnMessage(onMessage) {
this._onMessage = onMessage;
}

/**
* @param {function(string)} onDisconnect
*/
setOnDisconnect(onDisconnect) {
this._onDisconnect = onDisconnect;
}

/**
* @param {string} message
*/
sendRawMessage(message) {
this._nodeWorkerModel.sendMessageToWorker(message, this._sessionId);
}

/**
* @return {!Promise}
*/
disconnect() {
return this._nodeWorkerModel.detach(this._sessionId);
}

/**
* @param {string} message
*/
receivedMessageFromWorker(message) {
if (this._onMessage)
this._onMessage(message);
}

detachedFromWorker() {
if (this._onDisconnect)
this._onDisconnect();
}
};

NdbSdk.NodeWorkerDispatcher = class {
/**
* @param {!NdbSdk.NodeWorkerModel}
*/
constructor(nodeWorkerModel) {
this._nodeWorkerModel = nodeWorkerModel;
}

/**
* @param {string} sessionId
* @param {!Object} workerInfo
* @param {boolean} waitingForDebugger
*/
attachedToWorker(sessionId, workerInfo, waitingForDebugger) {
this._nodeWorkerModel._attachedToWorker(sessionId, workerInfo, waitingForDebugger);
}

/**
* @param {string} sessionId
*/
detachedFromWorker(sessionId) {
this._nodeWorkerModel._detachedFromWorker(sessionId);
}

/**
* @param {string} sessionId
* @param {string} message
*/
receivedMessageFromWorker(sessionId, message) {
this._nodeWorkerModel._receivedMessageFromWorker(sessionId, message);
}
};
7 changes: 7 additions & 0 deletions front_end/ndb_sdk/module.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"dependencies": ["sdk"],
"scripts": [
"NodeRuntime.js",
"NodeWorker.js"
]
}
6 changes: 6 additions & 0 deletions lib/preload/ndb/preload.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion services/ndd_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class NddService {
process.disconnect();
}

async _startSession(info, frontend, resumeTarget) {
async _startSession(info, frontend) {
const ws = new WebSocket(info.inspectorUrl);
const openPromise = new Promise(resolve => ws.once('open', () => resolve(DebugState.WS_OPEN)));
const errorPromise = new Promise(resolve => ws.once('error', () => resolve(DebugState.WS_ERROR)));
Expand Down