Skip to content

Commit c32c696

Browse files
feat: expose sessionId in debugger module (electron#24397)
Co-authored-by: deepak1556 <hop2deep@gmail.com>
1 parent 2761be6 commit c32c696

File tree

5 files changed

+66
-3
lines changed

5 files changed

+66
-3
lines changed

docs/api/debugger.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ Returns:
5252
* `method` String - Method name.
5353
* `params` any - Event parameters defined by the 'parameters'
5454
attribute in the remote debugging protocol.
55+
* `sessionId` String - Unique identifier of attached debugging session,
56+
will match the value sent from `debugger.sendCommand`.
5557

5658
Emitted whenever the debugging target issues an instrumentation event.
5759

@@ -74,11 +76,16 @@ Returns `Boolean` - Whether a debugger is attached to the `webContents`.
7476

7577
Detaches the debugger from the `webContents`.
7678

77-
#### `debugger.sendCommand(method[, commandParams])`
79+
#### `debugger.sendCommand(method[, commandParams, sessionId])`
7880

7981
* `method` String - Method name, should be one of the methods defined by the
8082
[remote debugging protocol][rdp].
8183
* `commandParams` any (optional) - JSON object with request parameters.
84+
* `sessionId` String (optional) - send command to the target with associated
85+
debugging session id. The initial value can be obtained by sending
86+
[Target.attachToTarget][attachToTarget] message.
87+
88+
[attachToTarget]: https://chromedevtools.github.io/devtools-protocol/tot/Target/#method-attachToTarget
8289

8390
Returns `Promise<any>` - A promise that resolves with the response defined by
8491
the 'returns' attribute of the command description in the remote debugging protocol

shell/browser/api/electron_api_debugger.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
6060
std::string method;
6161
if (!dict->GetString("method", &method))
6262
return;
63+
std::string session_id;
64+
dict->GetString("sessionId", &session_id);
6365
base::DictionaryValue* params_value = nullptr;
6466
base::DictionaryValue params;
6567
if (dict->GetDictionary("params", &params_value))
6668
params.Swap(params_value);
67-
Emit("message", method, params);
69+
Emit("message", method, params, session_id);
6870
} else {
6971
auto it = pending_requests_.find(id);
7072
if (it == pending_requests_.end())
@@ -152,14 +154,25 @@ v8::Local<v8::Promise> Debugger::SendCommand(gin::Arguments* args) {
152154
base::DictionaryValue command_params;
153155
args->GetNext(&command_params);
154156

157+
std::string session_id;
158+
if (args->GetNext(&session_id) && session_id.empty()) {
159+
promise.RejectWithErrorMessage("Empty session id is not allowed");
160+
return handle;
161+
}
162+
155163
base::DictionaryValue request;
156164
int request_id = ++previous_request_id_;
157165
pending_requests_.emplace(request_id, std::move(promise));
158166
request.SetInteger("id", request_id);
159167
request.SetString("method", method);
160-
if (!command_params.empty())
168+
if (!command_params.empty()) {
161169
request.Set("params",
162170
base::Value::ToUniquePtrValue(command_params.Clone()));
171+
}
172+
173+
if (!session_id.empty()) {
174+
request.SetString("sessionId", session_id);
175+
}
163176

164177
std::string json_args;
165178
base::JSONWriter::Write(request, &json_args);

spec-main/api-debugger-spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,39 @@ describe('debugger module', () => {
193193
w.loadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}`);
194194
});
195195
});
196+
197+
it('uses empty sessionId by default', async () => {
198+
w.webContents.loadURL('about:blank');
199+
w.webContents.debugger.attach();
200+
const onMessage = emittedOnce(w.webContents.debugger, 'message');
201+
await w.webContents.debugger.sendCommand('Target.setDiscoverTargets', { discover: true });
202+
const [, method, params, sessionId] = await onMessage;
203+
expect(method).to.equal('Target.targetCreated');
204+
expect(params.targetInfo.targetId).to.not.be.empty();
205+
expect(sessionId).to.be.empty();
206+
w.webContents.debugger.detach();
207+
});
208+
209+
it('creates unique session id for each target', (done) => {
210+
w.webContents.loadFile(path.join(__dirname, 'fixtures', 'sub-frames', 'debug-frames.html'));
211+
w.webContents.debugger.attach();
212+
let session: String;
213+
214+
w.webContents.debugger.on('message', (event, ...args) => {
215+
const [method, params, sessionId] = args;
216+
if (method === 'Target.targetCreated') {
217+
w.webContents.debugger.sendCommand('Target.attachToTarget', { targetId: params.targetInfo.targetId, flatten: true }).then(result => {
218+
session = result.sessionId;
219+
w.webContents.debugger.sendCommand('Debugger.enable', {}, result.sessionId);
220+
});
221+
}
222+
if (method === 'Debugger.scriptParsed') {
223+
expect(sessionId).to.equal(session);
224+
w.webContents.debugger.detach();
225+
done();
226+
}
227+
});
228+
w.webContents.debugger.sendCommand('Target.setDiscoverTargets', { discover: true });
229+
});
196230
});
197231
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<body>
4+
This is a frame, is has one child
5+
<iframe src="./frame.html"></iframe>
6+
</body>
7+
<script src="./test.js"></script>
8+
</html>

spec-main/fixtures/sub-frames/test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('hello');

0 commit comments

Comments
 (0)