1 // Copyright (c) 2015 GitHub, Inc.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
5 #include "atom/browser/api/atom_api_debugger.h"
9 #include "atom/common/native_mate_converters/callback.h"
10 #include "atom/common/native_mate_converters/value_converter.h"
11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "content/public/browser/devtools_agent_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "native_mate/object_template_builder.h"
17 using content::DevToolsAgentHost;
23 Debugger::Debugger(content::WebContents* web_contents)
24 : web_contents_(web_contents),
25 previous_request_id_(0) {
28 Debugger::~Debugger() {
31 void Debugger::AgentHostClosed(DevToolsAgentHost* agent_host,
32 bool replaced_with_another_client) {
33 std::string detach_reason = "target closed";
34 if (replaced_with_another_client)
35 detach_reason = "replaced with devtools";
36 if (!detach_callback_.is_null())
37 detach_callback_.Run(detach_reason);
40 void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
41 const std::string& message) {
42 DCHECK(agent_host == agent_host_.get());
44 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
45 if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY))
48 base::DictionaryValue* dict =
49 static_cast<base::DictionaryValue*>(parsed_message.get());
51 if (!dict->GetInteger("id", &id)) {
53 if (!dict->GetString("method", &method))
55 base::DictionaryValue* params = nullptr;
56 dict->GetDictionary("params", ¶ms);
57 if (!response_callback_.is_null())
58 response_callback_.Run(method, *params);
60 auto send_command_callback = pending_requests_[id];
61 pending_requests_.erase(id);
62 if (send_command_callback.is_null())
64 base::DictionaryValue* result = nullptr;
65 dict->GetDictionary("result", &result);
66 send_command_callback.Run(*result);
70 void Debugger::Attach(mate::Arguments* args) {
71 std::string protocol_version;
72 args->GetNext(&protocol_version);
74 if (!protocol_version.empty() &&
75 !DevToolsAgentHost::IsSupportedProtocolVersion(protocol_version)) {
76 args->ThrowError("Requested protocol version is not supported");
79 agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents_);
80 if (!agent_host_.get()) {
81 args->ThrowError("No target available");
84 if (agent_host_->IsAttached()) {
85 args->ThrowError("Another debugger is already attached to this target");
89 agent_host_->AttachClient(this);
92 void Debugger::Detach() {
93 agent_host_->DetachClient();
94 agent_host_ = nullptr;
97 void Debugger::SendCommand(mate::Arguments* args) {
98 if (!agent_host_.get())
99 args->ThrowError("Debugger is not attached to a target");
102 if (!args->GetNext(&method)) {
106 base::DictionaryValue command_params;
107 args->GetNext(&command_params);
108 SendCommandCallback callback;
109 args->GetNext(&callback);
111 base::DictionaryValue request;
112 int request_id = ++previous_request_id_;
113 pending_requests_[request_id] = callback;
114 request.SetInteger("id", request_id);
115 request.SetString("method", method);
116 if (!command_params.empty())
117 request.Set("params", command_params.DeepCopy());
119 std::string json_args;
120 base::JSONWriter::Write(request, &json_args);
121 agent_host_->DispatchProtocolMessage(json_args);
124 void Debugger::OnDetach(const DetachCallback& callback) {
125 detach_callback_ = callback;
128 void Debugger::OnEvent(const ResponseCallback& callback) {
129 response_callback_ = callback;
133 mate::Handle<Debugger> Debugger::Create(
134 v8::Isolate* isolate,
135 content::WebContents* web_contents) {
136 return mate::CreateHandle(isolate, new Debugger(web_contents));
140 void Debugger::BuildPrototype(v8::Isolate* isolate,
141 v8::Local<v8::ObjectTemplate> prototype) {
142 mate::ObjectTemplateBuilder(isolate, prototype)
143 .SetMethod("attach", &Debugger::Attach)
144 .SetMethod("detach", &Debugger::Detach)
145 .SetMethod("sendCommand", &Debugger::SendCommand)
146 .SetMethod("onDetach", &Debugger::OnDetach)
147 .SetMethod("onEvent", &Debugger::OnEvent);