summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksei Koziatinskii <ak239spb@gmail.com>2019-06-25 15:28:56 -0700
committerMichaƫl Zasso <targos@protonmail.com>2019-07-22 21:20:43 +0200
commit77bdbc5f0d1bd7caada99d0097bca2a9bb1f4cee (patch)
tree1d7f1b9f8fb9ca9b308f496683d7130218a42549
parent49e4d72b5a7fcf643e1476b0f382ed08cacd6c0a (diff)
downloadandroid-node-v8-77bdbc5f0d1bd7caada99d0097bca2a9bb1f4cee.tar.gz
android-node-v8-77bdbc5f0d1bd7caada99d0097bca2a9bb1f4cee.tar.bz2
android-node-v8-77bdbc5f0d1bd7caada99d0097bca2a9bb1f4cee.zip
inspector: add inspector.waitForDebugger()
This method blocks current node process until a client sends Runtime.runifWaitingForDebugger. It can be useful when we need to report inspector.url() before waiting for connection: ``` inspector.open(0, undefined, false); fs.writeFileSync(someFileName, inspector.url()); inspector.waitForDebugger(); ``` PR-URL: https://github.com/nodejs/node/pull/28453 Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com>
-rw-r--r--doc/api/errors.md5
-rw-r--r--doc/api/inspector.md10
-rw-r--r--lib/inspector.js22
-rw-r--r--lib/internal/errors.js1
-rw-r--r--src/inspector_js_api.cc13
-rw-r--r--test/parallel/test-inspector-wait-for-connection.js63
6 files changed, 107 insertions, 7 deletions
diff --git a/doc/api/errors.md b/doc/api/errors.md
index fe81168e40..6147f768c8 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1186,6 +1186,11 @@ after the session had already closed.
An error occurred while issuing a command via the `inspector` module.
+<a id="ERR_INSPECTOR_NOT_ACTIVE"></a>
+### ERR_INSPECTOR_NOT_ACTIVE
+
+The `inspector` is not active when `inspector.waitForDebugger()` is called.
+
<a id="ERR_INSPECTOR_NOT_AVAILABLE"></a>
### ERR_INSPECTOR_NOT_AVAILABLE
diff --git a/doc/api/inspector.md b/doc/api/inspector.md
index 63d2a70272..e2980a278d 100644
--- a/doc/api/inspector.md
+++ b/doc/api/inspector.md
@@ -52,6 +52,16 @@ parameter usage.
Return the URL of the active inspector, or `undefined` if there is none.
+## inspector.waitForDebugger()
+<!-- YAML
+added: REPLACEME
+-->
+
+Blocks until a client (existing or connected later) has sent
+`Runtime.runIfWaitingForDebugger` command.
+
+An exception will be thrown if there is no active inspector.
+
## Class: inspector.Session
The `inspector.Session` is used for dispatching messages to the V8 inspector
diff --git a/lib/inspector.js b/lib/inspector.js
index 4bec628b7d..198d87ae44 100644
--- a/lib/inspector.js
+++ b/lib/inspector.js
@@ -8,6 +8,7 @@ const {
ERR_INSPECTOR_COMMAND,
ERR_INSPECTOR_NOT_AVAILABLE,
ERR_INSPECTOR_NOT_CONNECTED,
+ ERR_INSPECTOR_NOT_ACTIVE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_CALLBACK
} = require('internal/errors').codes;
@@ -19,7 +20,12 @@ if (!hasInspector)
const EventEmitter = require('events');
const { validateString } = require('internal/validators');
const util = require('util');
-const { Connection, open, url } = internalBinding('inspector');
+const {
+ Connection,
+ open,
+ url,
+ waitForDebugger
+} = internalBinding('inspector');
const connectionSymbol = Symbol('connectionProperty');
const messageCallbacksSymbol = Symbol('messageCallbacks');
@@ -105,10 +111,22 @@ class Session extends EventEmitter {
}
}
+function inspectorOpen(port, host, wait) {
+ open(port, host);
+ if (wait)
+ waitForDebugger();
+}
+
+function inspectorWaitForDebugger() {
+ if (!waitForDebugger())
+ throw new ERR_INSPECTOR_NOT_ACTIVE();
+}
+
module.exports = {
- open: (port, host, wait) => open(port, host, !!wait),
+ 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,
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 8fa56e315e..23dbb79196 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -882,6 +882,7 @@ E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' +
E('ERR_INSPECTOR_ALREADY_CONNECTED', '%s is already connected', Error);
E('ERR_INSPECTOR_CLOSED', 'Session was closed', Error);
E('ERR_INSPECTOR_COMMAND', 'Inspector error %d: %s', Error);
+E('ERR_INSPECTOR_NOT_ACTIVE', 'Inspector is not active', Error);
E('ERR_INSPECTOR_NOT_AVAILABLE', 'Inspector is not available', Error);
E('ERR_INSPECTOR_NOT_CONNECTED', 'Session is not connected', Error);
E('ERR_INTERNAL_ASSERTION', (message) => {
diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc
index 3131c6ad37..8b891a2d61 100644
--- a/src/inspector_js_api.cc
+++ b/src/inspector_js_api.cc
@@ -237,7 +237,6 @@ void IsEnabled(const FunctionCallbackInfo<Value>& args) {
void Open(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Agent* agent = env->inspector_agent();
- bool wait_for_connect = false;
if (args.Length() > 0 && args[0]->IsUint32()) {
uint32_t port = args[0].As<Uint32>()->Value();
@@ -249,12 +248,15 @@ void Open(const FunctionCallbackInfo<Value>& args) {
agent->host_port()->set_host(*host);
}
- if (args.Length() > 2 && args[2]->IsBoolean()) {
- wait_for_connect = args[2]->BooleanValue(args.GetIsolate());
- }
agent->StartIoThread();
- if (wait_for_connect)
+}
+
+void WaitForDebugger(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ Agent* agent = env->inspector_agent();
+ if (agent->IsActive())
agent->WaitForConnect();
+ args.GetReturnValue().Set(agent->IsActive());
}
void Url(const FunctionCallbackInfo<Value>& args) {
@@ -285,6 +287,7 @@ void Initialize(Local<Object> target, Local<Value> unused,
env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
env->SetMethod(target, "open", Open);
env->SetMethodNoSideEffect(target, "url", Url);
+ env->SetMethod(target, "waitForDebugger", WaitForDebugger);
env->SetMethod(target, "asyncTaskScheduled", AsyncTaskScheduledWrapper);
env->SetMethod(target, "asyncTaskCanceled",
diff --git a/test/parallel/test-inspector-wait-for-connection.js b/test/parallel/test-inspector-wait-for-connection.js
new file mode 100644
index 0000000000..e6cfd81deb
--- /dev/null
+++ b/test/parallel/test-inspector-wait-for-connection.js
@@ -0,0 +1,63 @@
+// Flags: --expose-internals
+
+'use strict';
+const common = require('../common');
+
+common.skipIfInspectorDisabled();
+
+const assert = require('assert');
+const { NodeInstance } = require('../common/inspector-helper.js');
+
+async function runTests() {
+ const child = new NodeInstance(['-e', `(${main.toString()})()`], '', '');
+ const session = await child.connectInspectorSession();
+ await session.send({ method: 'Runtime.enable' });
+ // Check that there is only one console message received.
+ await session.waitForConsoleOutput('log', 'before wait for debugger');
+ assert.ok(!session.unprocessedNotifications()
+ .some((n) => n.method === 'Runtime.consoleAPICalled'));
+ // Check that inspector.url() is available between inspector.open() and
+ // inspector.waitForDebugger()
+ const { result: { value } } = await session.send({
+ method: 'Runtime.evaluate',
+ params: {
+ expression: 'process._ws',
+ includeCommandLineAPI: true
+ }
+ });
+ assert.ok(value.startsWith('ws://'));
+ session.send({ method: 'Runtime.runIfWaitingForDebugger' });
+ // Check that messages after first and before second waitForDebugger are
+ // received
+ await session.waitForConsoleOutput('log', 'after wait for debugger');
+ await session.waitForConsoleOutput('log', 'before second wait for debugger');
+ assert.ok(!session.unprocessedNotifications()
+ .some((n) => n.method === 'Runtime.consoleAPICalled'));
+ const secondSession = await child.connectInspectorSession();
+ // Check that inspector.waitForDebugger can be resumed from another session
+ secondSession.send({ method: 'Runtime.runIfWaitingForDebugger' });
+ await session.waitForConsoleOutput('log', 'after second wait for debugger');
+ assert.ok(!session.unprocessedNotifications()
+ .some((n) => n.method === 'Runtime.consoleAPICalled'));
+ secondSession.disconnect();
+ session.disconnect();
+
+ function main(prefix) {
+ const inspector = require('inspector');
+ inspector.open(0, undefined, false);
+ process._ws = inspector.url();
+ console.log('before wait for debugger');
+ inspector.waitForDebugger();
+ console.log('after wait for debugger');
+ console.log('before second wait for debugger');
+ inspector.waitForDebugger();
+ console.log('after second wait for debugger');
+ }
+
+ // Check that inspector.waitForDebugger throws if there is no active
+ // inspector
+ const re = /^Error \[ERR_INSPECTOR_NOT_ACTIVE\]: Inspector is not active$/;
+ assert.throws(() => require('inspector').waitForDebugger(), re);
+}
+
+runTests();