Skip to content

Commit 67f9896

Browse files
atlowChemiRafaelGSS
authored andcommitted
inspector: open add SymbolDispose
PR-URL: #48765 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent e01cce5 commit 67f9896

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

doc/api/inspector.md

+9
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,20 @@ console.
419419

420420
### `inspector.open([port[, host[, wait]]])`
421421

422+
<!-- YAML
423+
changes:
424+
- version: REPLACEME
425+
pr-url: https://github.com/nodejs/node/pull/48765
426+
description: inspector.open() now returns a `Disposable` object.
427+
-->
428+
422429
* `port` {number} Port to listen on for inspector connections. Optional.
423430
**Default:** what was specified on the CLI.
424431
* `host` {string} Host to listen on for inspector connections. Optional.
425432
**Default:** what was specified on the CLI.
426433
* `wait` {boolean} Block until a client has connected. Optional.
427434
**Default:** `false`.
435+
* Returns: {Disposable} that calls [`inspector.close()`][].
428436

429437
Activate inspector on host and port. Equivalent to
430438
`node --inspect=[[host:]port]`, but can be done programmatically after node has
@@ -472,5 +480,6 @@ An exception will be thrown if there is no active inspector.
472480
[Chrome DevTools Protocol Viewer]: https://chromedevtools.github.io/devtools-protocol/v8/
473481
[Heap Profiler]: https://chromedevtools.github.io/devtools-protocol/v8/HeapProfiler
474482
[`'Debugger.paused'`]: https://chromedevtools.github.io/devtools-protocol/v8/Debugger#event-paused
483+
[`inspector.close()`]: #inspectorclose
475484
[`session.connect()`]: #sessionconnect
476485
[security warning]: cli.md#warning-binding-inspector-to-a-public-ipport-combination-is-insecure

lib/inspector.js

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const {
55
JSONStringify,
66
SafeMap,
77
Symbol,
8+
SymbolDispose,
89
} = primordials;
910

1011
const {
@@ -181,6 +182,8 @@ function inspectorOpen(port, host, wait) {
181182
open(port, host);
182183
if (wait)
183184
waitForDebugger();
185+
186+
return { __proto__: null, [SymbolDispose]() { _debugEnd(); } };
184187
}
185188

186189
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import * as common from '../common/index.mjs';
2+
import assert from 'node:assert';
3+
import net from 'node:net';
4+
import url from 'node:url';
5+
import { fork } from 'node:child_process';
6+
7+
common.skipIfInspectorDisabled();
8+
if (process.env.BE_CHILD) {
9+
await beChild();
10+
} else {
11+
let firstPort;
12+
13+
const filename = url.fileURLToPath(import.meta.url);
14+
const child = fork(filename, { env: { ...process.env, BE_CHILD: 1 } });
15+
16+
child.once('message', common.mustCall((msg) => {
17+
assert.strictEqual(msg.cmd, 'started');
18+
19+
child.send({ cmd: 'open', args: [] });
20+
child.once('message', common.mustCall(wasOpenedHandler));
21+
}));
22+
23+
function wasOpenedHandler(msg) {
24+
assert.strictEqual(msg.cmd, 'url');
25+
const port = url.parse(msg.url).port;
26+
ping(port, common.mustSucceed(() => {
27+
// Inspector is already open, and won't be reopened, so args don't matter.
28+
child.send({ cmd: 'dispose' });
29+
child.once('message', common.mustCall(wasDisposedWhenOpenHandler));
30+
firstPort = port;
31+
}));
32+
}
33+
34+
function wasDisposedWhenOpenHandler(msg) {
35+
assert.strictEqual(msg.cmd, 'url');
36+
assert.strictEqual(msg.url, undefined);
37+
ping(firstPort, (err) => {
38+
assert(err);
39+
child.send({ cmd: 'dispose' });
40+
child.once('message', common.mustCall(wasReDisposedHandler));
41+
});
42+
}
43+
44+
function wasReDisposedHandler(msg) {
45+
assert.strictEqual(msg.cmd, 'url');
46+
assert.strictEqual(msg.url, undefined);
47+
process.exit();
48+
}
49+
}
50+
51+
function ping(port, callback) {
52+
net.connect({ port, family: 4 })
53+
.on('connect', function() { close(this); })
54+
.on('error', function(err) { close(this, err); });
55+
56+
function close(self, err) {
57+
self.end();
58+
self.on('close', () => callback(err));
59+
}
60+
}
61+
62+
async function beChild() {
63+
const inspector = await import('node:inspector');
64+
let inspectorDisposer;
65+
process.send({ cmd: 'started' });
66+
67+
process.on('message', (msg) => {
68+
if (msg.cmd === 'open') {
69+
inspectorDisposer = inspector.open(0, false, undefined);
70+
}
71+
if (msg.cmd === 'dispose') {
72+
inspectorDisposer[Symbol.dispose]();
73+
}
74+
process.send({ cmd: 'url', url: inspector.url() });
75+
});
76+
}

0 commit comments

Comments
 (0)