GeezerVison is showing github.com — inspector: add Target.getTargets and extract TargetManager · nodejs/node@b67a8fb
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: src/inspector/domain_target.pdl +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -20,6 +20,9 @@ experimental domain Target | 20 | 20 | SessionID sessionId | 21 | 21 | TargetInfo targetInfo | 22 | 22 | boolean waitingForDebugger | | 23 | + command getTargets | | 24 | + returns | | 25 | + array of TargetInfo targetInfos | 23 | 26 | command setAutoAttach | 24 | 27 | parameters | 25 | 28 | boolean autoAttach | |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/node_inspector.gypi +2Lines changed: 2 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 32 | 32 | 'src/inspector/network_inspector.h', | 33 | 33 | 'src/inspector/network_agent.cc', | 34 | 34 | 'src/inspector/network_agent.h', | | 35 | + 'src/inspector/target_manager.cc', | | 36 | + 'src/inspector/target_manager.h', | 35 | 37 | 'src/inspector/target_agent.cc', | 36 | 38 | 'src/inspector/target_agent.h', | 37 | 39 | 'src/inspector/worker_inspector.cc', | |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/target_agent.cc +24-14Lines changed: 24 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -8,10 +8,6 @@ namespace node { | 8 | 8 | namespace inspector { | 9 | 9 | namespace protocol { | 10 | 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 | 11 | class WorkerTargetDelegate : public WorkerDelegate { | 16 | 12 | public: | 17 | 13 | explicit WorkerTargetDelegate(std::shared_ptr<TargetAgent> target_agent) | @@ -32,13 +28,14 @@ std::unique_ptr<Target::TargetInfo> createTargetInfo( | 32 | 28 | const std::string_view target_id, | 33 | 29 | const std::string_view type, | 34 | 30 | const std::string_view title, | 35 | | - const std::string_view url) { | | 31 | + const std::string_view url, | | 32 | + bool attached = false) { | 36 | 33 | return Target::TargetInfo::create() | 37 | 34 | .setTargetId(std::string(target_id)) | 38 | 35 | .setType(std::string(type)) | 39 | 36 | .setTitle(std::string(title)) | 40 | 37 | .setUrl(std::string(url)) | 41 | | - .setAttached(false) | | 38 | + .setAttached(attached) | 42 | 39 | .setCanAccessOpener(true) | 43 | 40 | .build(); | 44 | 41 | } | @@ -57,11 +54,11 @@ void TargetAgent::createAndAttachIfNecessary( | 57 | 54 |
| 58 | 55 | targetCreated(target_id, type, title, url); | 59 | 56 | bool attached = false; | 60 | | - if (auto_attach_) { | | 57 | + if (target_manager_->auto_attach()) { | 61 | 58 | attached = true; | 62 | 59 | attachedToTarget(worker, target_id, type, title, url); | 63 | 60 | } | 64 | | - targets_.push_back({target_id, type, title, url, worker, attached}); | | 61 | + target_manager_->AddTarget(worker, target_id, type, title, url, attached); | 65 | 62 | } | 66 | 63 |
| 67 | 64 | void TargetAgent::listenWorker(std::weak_ptr<WorkerManager> worker_manager) { | @@ -87,12 +84,26 @@ void TargetAgent::targetCreated(const std::string_view target_id, | 87 | 84 | frontend_->targetCreated(createTargetInfo(target_id, type, title, url)); | 88 | 85 | } | 89 | 86 |
| | 87 | +crdtp::DispatchResponse TargetAgent::getTargets( | | 88 | + std::unique_ptr<protocol::Array<Target::TargetInfo>>* out_targetInfos) { | | 89 | + auto target_infos = std::make_unique<protocol::Array<Target::TargetInfo>>(); | | 90 | + for (const auto& target : target_manager_->GetTargetsSnapshot()) { | | 91 | + target_infos->push_back(createTargetInfo(target.target_id, | | 92 | + target.type, | | 93 | + target.title, | | 94 | + target.url, | | 95 | + target.attached)); | | 96 | + } | | 97 | + *out_targetInfos = std::move(target_infos); | | 98 | + return DispatchResponse::Success(); | | 99 | +} | | 100 | + | 90 | 101 | int TargetAgent::getNextSessionId() { | 91 | | - return next_session_id_++; | | 102 | + return target_manager_->NextSessionId(); | 92 | 103 | } | 93 | 104 |
| 94 | 105 | int TargetAgent::getNextTargetId() { | 95 | | - return next_target_id_++; | | 106 | + return target_manager_->NextTargetId(); | 96 | 107 | } | 97 | 108 |
| 98 | 109 | void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker, | @@ -101,7 +112,7 @@ void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker, | 101 | 112 | const std::string& title, | 102 | 113 | const std::string& url) { | 103 | 114 | int session_id = getNextSessionId(); | 104 | | - target_session_id_worker_map_[session_id] = worker; | | 115 | + TargetManager::RegisterSessionWorker(session_id, worker); | 105 | 116 | worker->SetTargetSessionId(session_id); | 106 | 117 | frontend_->attachedToTarget(std::to_string(session_id), | 107 | 118 | createTargetInfo(target_id, type, title, url), | @@ -112,11 +123,10 @@ void TargetAgent::attachedToTarget(std::shared_ptr<MainThreadHandle> worker, | 112 | 123 | // all threads. Modify it to be managed per worker thread. | 113 | 124 | crdtp::DispatchResponse TargetAgent::setAutoAttach( | 114 | 125 | 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; | | 126 | + target_manager_->SetAutoAttach(auto_attach, wait_for_debugger_on_start); | 117 | 127 |
| 118 | 128 | if (auto_attach) { | 119 | | - for (auto& target : targets_) { | | 129 | + for (auto& target : target_manager_->targets()) { | 120 | 130 | if (!target.attached) { | 121 | 131 | target.attached = true; | 122 | 132 | attachedToTarget(target.worker, | |
Collapse file Copy file name to clipboardExpand all lines: src/inspector/target_agent.h +7-23Lines changed: 7 additions & 23 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | #ifndef SRC_INSPECTOR_TARGET_AGENT_H_ | 2 | 2 | #define SRC_INSPECTOR_TARGET_AGENT_H_ | 3 | 3 |
| | 4 | +#include <memory> | 4 | 5 | #include <string_view> | 5 | | -#include <unordered_map> | 6 | | -#include <vector> | | 6 | +#include "inspector/target_manager.h" | 7 | 7 | #include "inspector/worker_inspector.h" | 8 | 8 | #include "node/inspector/protocol/Target.h" | 9 | 9 |
| @@ -14,15 +14,6 @@ class TargetInspector; | 14 | 14 |
| 15 | 15 | namespace protocol { | 16 | 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 | 17 | class TargetAgent : public Target::Backend, | 27 | 18 | public std::enable_shared_from_this<TargetAgent> { | 28 | 19 | public: | @@ -32,15 +23,14 @@ class TargetAgent : public Target::Backend, | 32 | 23 | const std::string& title, | 33 | 24 | const std::string& url); | 34 | 25 |
| | 26 | + DispatchResponse getTargets( | | 27 | + std::unique_ptr<protocol::Array<Target::TargetInfo>>* out_targetInfos) | | 28 | + override; | 35 | 29 | DispatchResponse setAutoAttach(bool auto_attach, | 36 | 30 | bool wait_for_debugger_on_start) override; | 37 | 31 |
| 38 | 32 | void listenWorker(std::weak_ptr<WorkerManager> worker_manager); | 39 | 33 | 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 | 34 |
| 45 | 35 | private: | 46 | 36 | int getNextTargetId(); | @@ -57,15 +47,9 @@ class TargetAgent : public Target::Backend, | 57 | 47 |
| 58 | 48 | std::shared_ptr<Target::Frontend> frontend_; | 59 | 49 | std::weak_ptr<WorkerManager> worker_manager_; | 60 | | - static int next_session_id_; | 61 | | - int next_target_id_ = 1; | 62 | 50 | 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_; | | 51 | + std::unique_ptr<TargetManager> target_manager_ = | | 52 | + std::make_unique<TargetManager>(); | 69 | 53 | }; | 70 | 54 |
| 71 | 55 | } // namespace protocol | |
Collapse file Copy file name to clipboard +66Lines changed: 66 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +#include "inspector/target_manager.h" | | 2 | + | | 3 | +#include "inspector/main_thread_interface.h" | | 4 | + | | 5 | +namespace node { | | 6 | +namespace inspector { | | 7 | + | | 8 | +Mutex TargetManager::session_state_lock_; | | 9 | +std::unordered_map<int, std::shared_ptr<MainThreadHandle>> | | 10 | + TargetManager::session_worker_map_; | | 11 | +int TargetManager::next_session_id_ = 1; | | 12 | + | | 13 | +int TargetManager::NextTargetId() { | | 14 | + return next_target_id_++; | | 15 | +} | | 16 | + | | 17 | +int TargetManager::NextSessionId() { | | 18 | + Mutex::ScopedLock scoped_lock(session_state_lock_); | | 19 | + return next_session_id_++; | | 20 | +} | | 21 | + | | 22 | +void TargetManager::SetAutoAttach(bool auto_attach, | | 23 | + bool wait_for_debugger_on_start) { | | 24 | + auto_attach_ = auto_attach; | | 25 | + wait_for_debugger_on_start_ = wait_for_debugger_on_start; | | 26 | +} | | 27 | + | | 28 | +void TargetManager::AddTarget(std::shared_ptr<MainThreadHandle> worker, | | 29 | + const std::string& target_id, | | 30 | + const std::string& type, | | 31 | + const std::string& title, | | 32 | + const std::string& url, | | 33 | + bool attached) { | | 34 | + targets_.push_back({target_id, type, title, url, worker, attached}); | | 35 | +} | | 36 | + | | 37 | +std::vector<TargetManager::TargetInfo> TargetManager::GetTargetsSnapshot() | | 38 | + const { | | 39 | + std::vector<TargetInfo> result; | | 40 | + result.reserve(targets_.size()); | | 41 | + for (const auto& target : targets_) { | | 42 | + if (target.worker && !target.worker->Expired()) { | | 43 | + result.push_back(target); | | 44 | + } | | 45 | + } | | 46 | + return result; | | 47 | +} | | 48 | + | | 49 | +void TargetManager::RegisterSessionWorker( | | 50 | + int session_id, std::shared_ptr<MainThreadHandle> worker) { | | 51 | + Mutex::ScopedLock scoped_lock(session_state_lock_); | | 52 | + session_worker_map_[session_id] = std::move(worker); | | 53 | +} | | 54 | + | | 55 | +std::shared_ptr<MainThreadHandle> TargetManager::WorkerForSession( | | 56 | + int session_id) { | | 57 | + Mutex::ScopedLock scoped_lock(session_state_lock_); | | 58 | + auto it = session_worker_map_.find(session_id); | | 59 | + if (it == session_worker_map_.end()) { | | 60 | + return nullptr; | | 61 | + } | | 62 | + return it->second; | | 63 | +} | | 64 | + | | 65 | +} // namespace inspector | | 66 | +} // namespace node |
Collapse file Copy file name to clipboard +70Lines changed: 70 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +#ifndef SRC_INSPECTOR_TARGET_MANAGER_H_ | | 2 | +#define SRC_INSPECTOR_TARGET_MANAGER_H_ | | 3 | + | | 4 | +#include <memory> | | 5 | +#include <string> | | 6 | +#include <unordered_map> | | 7 | +#include <vector> | | 8 | + | | 9 | +#include "node_mutex.h" | | 10 | + | | 11 | +namespace node { | | 12 | +namespace inspector { | | 13 | + | | 14 | +class MainThreadHandle; | | 15 | + | | 16 | +class TargetManager { | | 17 | + public: | | 18 | + struct TargetInfo { | | 19 | + std::string target_id; | | 20 | + std::string type; | | 21 | + std::string title; | | 22 | + std::string url; | | 23 | + std::shared_ptr<MainThreadHandle> worker; | | 24 | + bool attached; | | 25 | + }; | | 26 | + | | 27 | + TargetManager() = default; | | 28 | + | | 29 | + int NextTargetId(); | | 30 | + int NextSessionId(); | | 31 | + | | 32 | + void SetAutoAttach(bool auto_attach, bool wait_for_debugger_on_start); | | 33 | + bool auto_attach() const { return auto_attach_; } | | 34 | + bool wait_for_debugger_on_start() const { | | 35 | + return wait_for_debugger_on_start_; | | 36 | + } | | 37 | + | | 38 | + void AddTarget(std::shared_ptr<MainThreadHandle> worker, | | 39 | + const std::string& target_id, | | 40 | + const std::string& type, | | 41 | + const std::string& title, | | 42 | + const std::string& url, | | 43 | + bool attached); | | 44 | + std::vector<TargetInfo> GetTargetsSnapshot() const; | | 45 | + std::vector<TargetInfo>& targets() { return targets_; } | | 46 | + const std::vector<TargetInfo>& targets() const { return targets_; } | | 47 | + | | 48 | + static void RegisterSessionWorker(int session_id, | | 49 | + std::shared_ptr<MainThreadHandle> worker); | | 50 | + static std::shared_ptr<MainThreadHandle> WorkerForSession(int session_id); | | 51 | + | | 52 | + private: | | 53 | + static Mutex session_state_lock_; | | 54 | + static std::unordered_map<int, std::shared_ptr<MainThreadHandle>> | | 55 | + session_worker_map_; | | 56 | + static int next_session_id_; | | 57 | + | | 58 | + int next_target_id_ = 1; | | 59 | + bool auto_attach_ = false; | | 60 | + // TODO(islandryu): Honor this flag for worker targets. It is stored here | | 61 | + // so Target.setAutoAttach() state can be tracked, but worker startup pause | | 62 | + // behavior does not change based on it yet. | | 63 | + bool wait_for_debugger_on_start_ = true; | | 64 | + std::vector<TargetInfo> targets_; | | 65 | +}; | | 66 | + | | 67 | +} // namespace inspector | | 68 | +} // namespace node | | 69 | + | | 70 | +#endif // SRC_INSPECTOR_TARGET_MANAGER_H_ |
Collapse file Copy file name to clipboardExpand all lines: src/inspector_io.cc +2-2Lines changed: 2 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 7 | 7 | #include "inspector/node_json.h" | 8 | 8 | #include "inspector/node_string.h" | 9 | 9 | #include "inspector/target_agent.h" | | 10 | +#include "inspector/target_manager.h" | 10 | 11 | #include "inspector_socket_server.h" | 11 | 12 | #include "ncrypto.h" | 12 | 13 | #include "node.h" | @@ -380,8 +381,7 @@ void InspectorIoDelegate::MessageReceived(int session_id, | 380 | 381 | ::isdigit); | 381 | 382 | if (is_number) { | 382 | 383 | int target_session_id = std::stoi(*target_session_id_str); | 383 | | - worker = protocol::TargetAgent::target_session_id_worker_map_ | 384 | | - [target_session_id]; | | 384 | + worker = TargetManager::WorkerForSession(target_session_id); | 385 | 385 | if (worker) { | 386 | 386 | merged_session_id += target_session_id << 16; | 387 | 387 | } | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-inspector-worker-target.js +16-1Lines changed: 16 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
| 3 | 3 | const common = require('../common'); | 4 | 4 | const fixtures = require('../common/fixtures'); | 5 | 5 |
| | 6 | +const assert = require('assert'); | | 7 | + | 6 | 8 | common.skipIfInspectorDisabled(); | 7 | 9 |
| 8 | 10 | const { NodeInstance } = require('../common/inspector-helper.js'); | @@ -21,6 +23,15 @@ async function setupInspector(session, sessionId = undefined) { | 21 | 23 | }); | 22 | 24 | } | 23 | 25 |
| | 26 | +async function assertTargetAttachedState(session, targetId, attached) { | | 27 | + const { targetInfos } = await session.send({ method: 'Target.getTargets' }); | | 28 | + const targetInfo = targetInfos.find((target) => { | | 29 | + return target.targetId === targetId; | | 30 | + }); | | 31 | + assert.notStrictEqual(targetInfo, undefined); | | 32 | + assert.strictEqual(targetInfo.attached, attached); | | 33 | +} | | 34 | + | 24 | 35 | async function test(isSetAutoAttachBeforeExecution) { | 25 | 36 | const child = new NodeInstance(['--inspect-brk=0', '--experimental-worker-inspection'], | 26 | 37 | '', | @@ -38,7 +49,10 @@ async function test(isSetAutoAttachBeforeExecution) { | 38 | 49 | await session.send({ method: 'Debugger.resume' }); | 39 | 50 |
| 40 | 51 | const sessionId = '1'; | 41 | | - await session.waitForNotification('Target.targetCreated'); | | 52 | + const targetCreated = await session.waitForNotification('Target.targetCreated'); | | 53 | + const targetId = targetCreated.params.targetInfo.targetId; | | 54 | + | | 55 | + await assertTargetAttachedState(session, targetId, isSetAutoAttachBeforeExecution); | 42 | 56 |
| 43 | 57 | if (!isSetAutoAttachBeforeExecution) { | 44 | 58 | await session.send({ method: 'Target.setAutoAttach', params: { autoAttach: true, waitForDebuggerOnStart: true } }); | @@ -47,6 +61,7 @@ async function test(isSetAutoAttachBeforeExecution) { | 47 | 61 | return notification.method === 'Target.attachedToTarget' && | 48 | 62 | notification.params.sessionId === sessionId; | 49 | 63 | }); | | 64 | + await assertTargetAttachedState(session, targetId, true); | 50 | 65 | await setupInspector(session, sessionId); | 51 | 66 | await session.waitForNotification('Debugger.paused'); | 52 | 67 | await session.send({ method: 'Debugger.resume', sessionId }); | |
|