Skip to content

Commit 2281a04

Browse files
authored
inspector: support for worker inspection in chrome devtools
Fixes: #56343 PR-URL: #56759 Reviewed-By: Chengzhong Wu <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent cfd2021 commit 2281a04

13 files changed

+443
-23
lines changed

doc/api/cli.md

+11
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,17 @@ added: v22.4.0
12051205

12061206
Enable experimental [`Web Storage`][] support.
12071207

1208+
### `--experimental-worker-inspection`
1209+
1210+
<!-- YAML
1211+
added:
1212+
- REPLACEME
1213+
-->
1214+
1215+
> Stability: 1.1 - Active Development
1216+
1217+
Enable experimental support for the worker inspection with Chrome DevTools.
1218+
12081219
### `--expose-gc`
12091220

12101221
<!-- YAML

src/inspector/main_thread_interface.h

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ class MainThreadHandle : public std::enable_shared_from_this<MainThreadHandle> {
5757
std::unique_ptr<InspectorSessionDelegate> MakeDelegateThreadSafe(
5858
std::unique_ptr<InspectorSessionDelegate> delegate);
5959
bool Expired();
60+
void SetTargetSessionId(int target_session_id) {
61+
target_session_id_ = target_session_id;
62+
}
63+
std::optional<int> GetTargetSessionId() { return target_session_id_; }
6064

6165
private:
6266
void Reset();
@@ -65,6 +69,7 @@ class MainThreadHandle : public std::enable_shared_from_this<MainThreadHandle> {
6569
Mutex block_lock_;
6670
int next_session_id_ = 0;
6771
std::atomic_int next_object_id_ = {1};
72+
std::optional<int> target_session_id_ = std::nullopt;
6873

6974
friend class MainThreadInterface;
7075
};

src/inspector/node_inspector.gypi

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
'src/inspector/network_inspector.h',
3333
'src/inspector/network_agent.cc',
3434
'src/inspector/network_agent.h',
35+
'src/inspector/target_agent.cc',
36+
'src/inspector/target_agent.h',
3537
'src/inspector/worker_inspector.cc',
3638
'src/inspector/worker_inspector.h',
3739
],
@@ -47,6 +49,8 @@
4749
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/NodeRuntime.h',
4850
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.cpp',
4951
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Network.h',
52+
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Target.cpp',
53+
'<(SHARED_INTERMEDIATE_DIR)/src/node/inspector/protocol/Target.h',
5054
],
5155
'node_protocol_files': [
5256
'<(protocol_tool_path)/lib/Forward_h.template',

src/inspector/node_protocol.pdl

+25
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,28 @@ experimental domain NodeRuntime
249249
# This event is fired when the runtime is waiting for the debugger. For
250250
# example, when inspector.waitingForDebugger is called
251251
event waitingForDebugger
252+
253+
# https://chromedevtools.github.io/devtools-protocol/1-3/Target/
254+
experimental domain Target
255+
type SessionID extends string
256+
type TargetID extends string
257+
type TargetInfo extends object
258+
properties
259+
TargetID targetId
260+
string type
261+
string title
262+
string url
263+
boolean attached
264+
boolean canAccessOpener
265+
event targetCreated
266+
parameters
267+
TargetInfo targetInfo
268+
event attachedToTarget
269+
parameters
270+
SessionID sessionId
271+
TargetInfo targetInfo
272+
boolean waitingForDebugger
273+
command setAutoAttach
274+
parameters
275+
boolean autoAttach
276+
boolean waitForDebuggerOnStart

src/inspector/target_agent.cc

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "target_agent.h"
2+
#include <string_view>
3+
#include "crdtp/dispatch.h"
4+
#include "inspector/worker_inspector.h"
5+
#include "main_thread_interface.h"
6+
7+
namespace node {
8+
namespace inspector {
9+
namespace protocol {
10+
11+
std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
12+
TargetAgent::target_session_id_worker_map_ =
13+
std::unordered_map<int, std::shared_ptr<MainThreadHandle>>();
14+
int TargetAgent::next_session_id_ = 1;
15+
class WorkerTargetDelegate : public WorkerDelegate {
16+
public:
17+
explicit WorkerTargetDelegate(std::shared_ptr<TargetAgent> target_agent)
18+
: target_agent_(target_agent) {}
19+
20+
void WorkerCreated(const std::string& title,
21+
const std::string& url,
22+
bool waiting,
23+
std::shared_ptr<MainThreadHandle> worker) override {
24+
target_agent_->createAndAttachIfNecessary(worker, title, url);
25+
}
26+
27+
private:
28+
const std::shared_ptr<TargetAgent> target_agent_;
29+
};
30+
31+
std::unique_ptr<Target::TargetInfo> createTargetInfo(
32+
const std::string_view target_id,
33+
const std::string_view type,
34+
const std::string_view title,
35+
const std::string_view url) {
36+
return Target::TargetInfo::create()
37+
.setTargetId(std::string(target_id))
38+
.setType(std::string(type))
39+
.setTitle(std::string(title))
40+
.setUrl(std::string(url))
41+
.setAttached(false)
42+
.setCanAccessOpener(true)
43+
.build();
44+
}
45+
46+
void TargetAgent::Wire(UberDispatcher* dispatcher) {
47+
frontend_ = std::make_unique<Target::Frontend>(dispatcher->channel());
48+
Target::Dispatcher::wire(dispatcher, this);
49+
}
50+
51+
void TargetAgent::createAndAttachIfNecessary(
52+
std::shared_ptr<MainThreadHandle> worker,
53+
const std::string& title,
54+
const std::string& url) {
55+
std::string target_id = std::to_string(getNextTargetId());
56+
std::string type = "node_worker";
57+
58+
targetCreated(target_id, type, title, url);
59+
bool attached = false;
60+
if (auto_attach_) {
61+
attached = true;
62+
attachedToTarget(worker, target_id, type, title, url);
63+
}
64+
targets_.push_back({target_id, type, title, url, worker, attached});
65+
}
66+
67+
void TargetAgent::listenWorker(std::weak_ptr<WorkerManager> worker_manager) {
68+
auto manager = worker_manager.lock();
69+
if (!manager) {
70+
return;
71+
}
72+
std::unique_ptr<WorkerDelegate> delegate(
73+
new WorkerTargetDelegate(shared_from_this()));
74+
worker_event_handle_ = manager->SetAutoAttach(std::move(delegate));
75+
}
76+
77+
void TargetAgent::reset() {
78+
if (worker_event_handle_) {
79+
worker_event_handle_.reset();
80+
}
81+
}
82+
83+
void TargetAgent::targetCreated(const std::string_view target_id,
84+
const std::string_view type,
85+
const std::string_view title,
86+
const std::string_view url) {
87+
frontend_->targetCreated(createTargetInfo(target_id, type, title, url));
88+
}
89+
90+
int TargetAgent::getNextSessionId() {
91+
return next_session_id_++;
92+
}
93+
94+
int TargetAgent::getNextTargetId() {
95+
return next_target_id_++;
96+
}
97+
98+
void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker,
99+
const std::string& target_id,
100+
const std::string& type,
101+
const std::string& title,
102+
const std::string& url) {
103+
int session_id = getNextSessionId();
104+
target_session_id_worker_map_[session_id] = worker;
105+
worker->SetTargetSessionId(session_id);
106+
frontend_->attachedToTarget(std::to_string(session_id),
107+
createTargetInfo(target_id, type, title, url),
108+
true);
109+
}
110+
111+
// TODO(islandryu): Currently, setAutoAttach applies the main thread's value to
112+
// all threads. Modify it to be managed per worker thread.
113+
crdtp::DispatchResponse TargetAgent::setAutoAttach(
114+
bool auto_attach, bool wait_for_debugger_on_start) {
115+
auto_attach_ = auto_attach;
116+
wait_for_debugger_on_start_ = wait_for_debugger_on_start;
117+
118+
if (auto_attach) {
119+
for (auto& target : targets_) {
120+
if (!target.attached) {
121+
target.attached = true;
122+
attachedToTarget(target.worker,
123+
target.target_id,
124+
target.type,
125+
target.title,
126+
target.url);
127+
}
128+
}
129+
}
130+
131+
return DispatchResponse::Success();
132+
}
133+
134+
} // namespace protocol
135+
} // namespace inspector
136+
} // namespace node

src/inspector/target_agent.h

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#ifndef SRC_INSPECTOR_TARGET_AGENT_H_
2+
#define SRC_INSPECTOR_TARGET_AGENT_H_
3+
4+
#include <string_view>
5+
#include <unordered_map>
6+
#include <vector>
7+
#include "inspector/worker_inspector.h"
8+
#include "node/inspector/protocol/Target.h"
9+
10+
namespace node {
11+
12+
namespace inspector {
13+
class TargetInspector;
14+
15+
namespace protocol {
16+
17+
struct TargetInfo {
18+
std::string target_id;
19+
std::string type;
20+
std::string title;
21+
std::string url;
22+
std::shared_ptr<MainThreadHandle> worker;
23+
bool attached;
24+
};
25+
26+
class TargetAgent : public Target::Backend,
27+
public std::enable_shared_from_this<TargetAgent> {
28+
public:
29+
void Wire(UberDispatcher* dispatcher);
30+
31+
void createAndAttachIfNecessary(std::shared_ptr<MainThreadHandle> worker,
32+
const std::string& title,
33+
const std::string& url);
34+
35+
DispatchResponse setAutoAttach(bool auto_attach,
36+
bool wait_for_debugger_on_start) override;
37+
38+
void listenWorker(std::weak_ptr<WorkerManager> worker_manager);
39+
void reset();
40+
static std::unordered_map<int, std::shared_ptr<MainThreadHandle>>
41+
target_session_id_worker_map_;
42+
43+
bool isThisThread(MainThreadHandle* worker) { return worker == main_thread_; }
44+
45+
private:
46+
int getNextTargetId();
47+
int getNextSessionId();
48+
void targetCreated(const std::string_view target_id,
49+
const std::string_view type,
50+
const std::string_view title,
51+
const std::string_view url);
52+
void attachedToTarget(std::shared_ptr<MainThreadHandle> worker,
53+
const std::string& target_id,
54+
const std::string& type,
55+
const std::string& title,
56+
const std::string& url);
57+
58+
std::shared_ptr<Target::Frontend> frontend_;
59+
std::weak_ptr<WorkerManager> worker_manager_;
60+
static int next_session_id_;
61+
int next_target_id_ = 1;
62+
std::unique_ptr<WorkerManagerEventHandle> worker_event_handle_ = nullptr;
63+
bool auto_attach_ = false;
64+
// TODO(islandryu): If false, implement it so that each thread does not wait
65+
// for the worker to execute.
66+
bool wait_for_debugger_on_start_ = true;
67+
std::vector<TargetInfo> targets_;
68+
MainThreadHandle* main_thread_;
69+
};
70+
71+
} // namespace protocol
72+
} // namespace inspector
73+
} // namespace node
74+
75+
#endif // SRC_INSPECTOR_TARGET_AGENT_H_

0 commit comments

Comments
 (0)