0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/lib/inspector.js
Joyee Cheung dd5f209213 inspector: throw error when activating an already active inspector
When the user tries to activate the inspector that is already active
on a different port and host, we previously just silently reset
the port and host stored in the Environment without actually doing
anything for that to be effective. After this patch, we throw
an error telling the user to close the active inspector before invoking
`inspector.open()` again.

PR-URL: https://github.com/nodejs/node/pull/33015
Fixes: https://github.com/nodejs/node/issues/33012
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
2020-05-24 03:43:05 +02:00

159 lines
4.2 KiB
JavaScript

'use strict';
const {
JSONParse,
JSONStringify,
Map,
Symbol,
} = primordials;
const {
ERR_INSPECTOR_ALREADY_ACTIVATED,
ERR_INSPECTOR_ALREADY_CONNECTED,
ERR_INSPECTOR_CLOSED,
ERR_INSPECTOR_COMMAND,
ERR_INSPECTOR_NOT_AVAILABLE,
ERR_INSPECTOR_NOT_CONNECTED,
ERR_INSPECTOR_NOT_ACTIVE,
ERR_INSPECTOR_NOT_WORKER,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_CALLBACK
} = require('internal/errors').codes;
const { hasInspector } = internalBinding('config');
if (!hasInspector)
throw new ERR_INSPECTOR_NOT_AVAILABLE();
const EventEmitter = require('events');
const { queueMicrotask } = require('internal/process/task_queues');
const { validateString } = require('internal/validators');
const { isMainThread } = require('worker_threads');
const {
Connection,
MainThreadConnection,
open,
url,
isEnabled,
waitForDebugger
} = internalBinding('inspector');
const connectionSymbol = Symbol('connectionProperty');
const messageCallbacksSymbol = Symbol('messageCallbacks');
const nextIdSymbol = Symbol('nextId');
const onMessageSymbol = Symbol('onMessage');
class Session extends EventEmitter {
constructor() {
super();
this[connectionSymbol] = null;
this[nextIdSymbol] = 1;
this[messageCallbacksSymbol] = new Map();
}
connect() {
if (this[connectionSymbol])
throw new ERR_INSPECTOR_ALREADY_CONNECTED('The inspector session');
this[connectionSymbol] =
new Connection((message) => this[onMessageSymbol](message));
}
connectToMainThread() {
if (isMainThread)
throw new ERR_INSPECTOR_NOT_WORKER();
if (this[connectionSymbol])
throw new ERR_INSPECTOR_ALREADY_CONNECTED('The inspector session');
this[connectionSymbol] =
new MainThreadConnection(
(message) => queueMicrotask(() => this[onMessageSymbol](message)));
}
[onMessageSymbol](message) {
const parsed = JSONParse(message);
try {
if (parsed.id) {
const callback = this[messageCallbacksSymbol].get(parsed.id);
this[messageCallbacksSymbol].delete(parsed.id);
if (callback) {
if (parsed.error) {
return callback(new ERR_INSPECTOR_COMMAND(parsed.error.code,
parsed.error.message));
}
callback(null, parsed.result);
}
} else {
this.emit(parsed.method, parsed);
this.emit('inspectorNotification', parsed);
}
} catch (error) {
process.emitWarning(error);
}
}
post(method, params, callback) {
validateString(method, 'method');
if (!callback && typeof params === 'function') {
callback = params;
params = null;
}
if (params && typeof params !== 'object') {
throw new ERR_INVALID_ARG_TYPE('params', 'Object', params);
}
if (callback && typeof callback !== 'function') {
throw new ERR_INVALID_CALLBACK(callback);
}
if (!this[connectionSymbol]) {
throw new ERR_INSPECTOR_NOT_CONNECTED();
}
const id = this[nextIdSymbol]++;
const message = { id, method };
if (params) {
message.params = params;
}
if (callback) {
this[messageCallbacksSymbol].set(id, callback);
}
this[connectionSymbol].dispatch(JSONStringify(message));
}
disconnect() {
if (!this[connectionSymbol])
return;
this[connectionSymbol].disconnect();
this[connectionSymbol] = null;
const remainingCallbacks = this[messageCallbacksSymbol].values();
for (const callback of remainingCallbacks) {
process.nextTick(callback, new ERR_INSPECTOR_CLOSED());
}
this[messageCallbacksSymbol].clear();
this[nextIdSymbol] = 1;
}
}
function inspectorOpen(port, host, wait) {
if (isEnabled()) {
throw new ERR_INSPECTOR_ALREADY_ACTIVATED();
}
open(port, host);
if (wait)
waitForDebugger();
}
function inspectorWaitForDebugger() {
if (!waitForDebugger())
throw new ERR_INSPECTOR_NOT_ACTIVE();
}
module.exports = {
open: inspectorOpen,
close: process._debugEnd,
url: url,
waitForDebugger: inspectorWaitForDebugger,
// This is dynamically added during bootstrap,
// where the console from the VM is still available
console: require('internal/util/inspector').consoleFromVM,
Session
};