-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
inspector: add inspector.waitForConnection method #22867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -833,7 +833,8 @@ bool Agent::IsActive() { | |
|
||
void Agent::WaitForConnect() { | ||
CHECK_NOT_NULL(client_); | ||
client_->waitForFrontend(); | ||
if (!client_->hasConnectedSessions()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure this change is needed. If I understand correctly, the goal here is to wait for a specific frontend to connect. This check will subvert this expectation. |
||
client_->waitForFrontend(); | ||
} | ||
|
||
SameThreadInspectorSession::~SameThreadInspectorSession() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -259,6 +259,16 @@ void Open(const FunctionCallbackInfo<Value>& args) { | |
agent->WaitForConnect(); | ||
} | ||
|
||
void WaitForConnection(const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args); | ||
Agent* agent = env->inspector_agent(); | ||
if (!agent->IsActive()) { | ||
env->ThrowError("inspector error, inspector.open should be called first"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this check be made from JavaScript code? I believe the guideline was not to throw exceptions from the native code. |
||
return; | ||
} | ||
agent->WaitForConnect(); | ||
} | ||
|
||
void Url(const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args); | ||
Agent* agent = env->inspector_agent(); | ||
|
@@ -291,6 +301,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, "waitForConnection", WaitForConnection); | ||
|
||
env->SetMethod(target, "asyncTaskScheduled", AsyncTaskScheduledWrapper); | ||
env->SetMethod(target, "asyncTaskCanceled", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -504,5 +504,6 @@ function fires(promise, error, timeoutMs) { | |
} | ||
|
||
module.exports = { | ||
NodeInstance | ||
NodeInstance, | ||
formatWSFrame | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// Flags: --expose-internals | ||
'use strict'; | ||
const common = require('../common'); | ||
common.skipIfInspectorDisabled(); | ||
|
||
// Test inspector waitForConnection() API. It uses ephemeral ports so can be | ||
// run safely in parallel. | ||
|
||
const assert = require('assert'); | ||
const fork = require('child_process').fork; | ||
const http = require('http'); | ||
const url = require('url'); | ||
|
||
if (process.env.BE_CHILD) | ||
return beChild(); | ||
|
||
const { formatWSFrame } = require('../common/inspector-helper.js'); | ||
|
||
function waitForMessage(child) { | ||
return new Promise(child.once.bind(child, 'message')); | ||
} | ||
|
||
async function connect(wsUrl) { | ||
const socket = await new Promise((resolve, reject) => { | ||
const parsedUrl = url.parse(wsUrl); | ||
const response = http.get({ | ||
port: parsedUrl.port, | ||
path: parsedUrl.path, | ||
headers: { | ||
'Connection': 'Upgrade', | ||
'Upgrade': 'websocket', | ||
'Sec-WebSocket-Version': 13, | ||
'Sec-WebSocket-Key': 'key==' | ||
} | ||
}); | ||
response.once('upgrade', (message, socket) => resolve(socket)); | ||
response.once('responce', () => reject('Upgrade was not received')); | ||
}); | ||
return socket; | ||
} | ||
|
||
function runIfWaitingForDebugger(socket) { | ||
return new Promise((resolve) => socket.write(formatWSFrame({ | ||
id: 1, | ||
method: 'Runtime.runIfWaitingForDebugger' | ||
}), resolve)); | ||
} | ||
|
||
(async function() { | ||
const child = fork(__filename, | ||
{ env: Object.assign({}, process.env, { BE_CHILD: 1 }) }); | ||
const started = await waitForMessage(child); | ||
assert.strictEqual(started.cmd, 'started'); | ||
|
||
child.send({ cmd: 'open', args: [0] }); | ||
const { url } = await waitForMessage(child); | ||
|
||
// Wait for connection first time.. | ||
child.send({ cmd: 'waitForConnection' }); | ||
// .. connect .. | ||
const socket = await connect(url); | ||
runIfWaitingForDebugger(socket); | ||
|
||
// .. check that waitForConnection method is finished. | ||
const awaited1 = await waitForMessage(child); | ||
assert.strictEqual(awaited1.cmd, 'awaited'); | ||
|
||
// Wait for connection with existing connection .. | ||
child.send({ cmd: 'waitForConnection' }); | ||
const awaited2 = await waitForMessage(child); | ||
// .. check that waitForConnection method is finished. | ||
assert.strictEqual(awaited2.cmd, 'awaited'); | ||
|
||
socket.end(); | ||
|
||
// Close connection .. | ||
child.send({ cmd: 'close' }); | ||
const closed = await waitForMessage(child); | ||
assert.strictEqual(closed.cmd, 'closed'); | ||
|
||
// .. call waitForConnection when inspector is closed .. | ||
child.send({ cmd: 'waitForConnection' }); | ||
const awaitedError = await waitForMessage(child); | ||
// .. check error message. | ||
assert.strictEqual(awaitedError.cmd, 'awaited'); | ||
assert.strictEqual(awaitedError.error, | ||
'inspector error, inspector.open should be called first'); | ||
|
||
child.send({ cmd: 'exit' }); | ||
})(); | ||
|
||
function beChild() { | ||
const inspector = require('inspector'); | ||
|
||
process.send({ cmd: 'started' }); | ||
|
||
process.on('message', (msg) => { | ||
if (msg.cmd === 'open') { | ||
inspector.open(...msg.args); | ||
process.send({ cmd: 'opened', url: inspector.url() }); | ||
} else if (msg.cmd === 'close') { | ||
inspector.close(); | ||
process.send({ cmd: 'closed' }); | ||
} else if (msg.cmd === 'waitForConnection') { | ||
try { | ||
inspector.waitForConnection(); | ||
process.send({ cmd: 'awaited' }); | ||
} catch (e) { | ||
process.send({ cmd: 'awaited', error: e.message }); | ||
} | ||
} else if (msg.cmd === 'exit') { | ||
process.exit(); | ||
} | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My reading of this patch is that this will wait until:
runIfWaitingForDebugger should be mentioned here to reduce confusion