browser: add webContents.debugger api
[platform/framework/web/crosswalk-tizen.git] / atom / browser / api / atom_api_debugger.cc
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.
4
5 #include "atom/browser/api/atom_api_debugger.h"
6
7 #include <string>
8
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"
16
17 using content::DevToolsAgentHost;
18
19 namespace atom {
20
21 namespace api {
22
23 Debugger::Debugger(content::WebContents* web_contents)
24     : web_contents_(web_contents),
25       previous_request_id_(0) {
26 }
27
28 Debugger::~Debugger() {
29 }
30
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);
38 }
39
40 void Debugger::DispatchProtocolMessage(DevToolsAgentHost* agent_host,
41                                        const std::string& message) {
42   DCHECK(agent_host == agent_host_.get());
43
44   scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
45   if (!parsed_message->IsType(base::Value::TYPE_DICTIONARY))
46     return;
47
48   base::DictionaryValue* dict =
49       static_cast<base::DictionaryValue*>(parsed_message.get());
50   int id;
51   if (!dict->GetInteger("id", &id)) {
52     std::string method;
53     if (!dict->GetString("method", &method))
54       return;
55     base::DictionaryValue* params = nullptr;
56     dict->GetDictionary("params", &params);
57     if (!response_callback_.is_null())
58       response_callback_.Run(method, *params);
59   } else {
60     auto send_command_callback = pending_requests_[id];
61     pending_requests_.erase(id);
62     if (send_command_callback.is_null())
63       return;
64     base::DictionaryValue* result = nullptr;
65     dict->GetDictionary("result", &result);
66     send_command_callback.Run(*result);
67   }
68 }
69
70 void Debugger::Attach(mate::Arguments* args) {
71   std::string protocol_version;
72   args->GetNext(&protocol_version);
73
74   if (!protocol_version.empty() &&
75       !DevToolsAgentHost::IsSupportedProtocolVersion(protocol_version)) {
76     args->ThrowError("Requested protocol version is not supported");
77     return;
78   }
79   agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents_);
80   if (!agent_host_.get()) {
81     args->ThrowError("No target available");
82     return;
83   }
84   if (agent_host_->IsAttached()) {
85     args->ThrowError("Another debugger is already attached to this target");
86     return;
87   }
88
89   agent_host_->AttachClient(this);
90 }
91
92 void Debugger::Detach() {
93   agent_host_->DetachClient();
94   agent_host_ = nullptr;
95 }
96
97 void Debugger::SendCommand(mate::Arguments* args) {
98   if (!agent_host_.get())
99     args->ThrowError("Debugger is not attached to a target");
100
101   std::string method;
102   if (!args->GetNext(&method)) {
103     args->ThrowError();
104     return;
105   }
106   base::DictionaryValue command_params;
107   args->GetNext(&command_params);
108   SendCommandCallback callback;
109   args->GetNext(&callback);
110
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());
118
119   std::string json_args;
120   base::JSONWriter::Write(request, &json_args);
121   agent_host_->DispatchProtocolMessage(json_args);
122 }
123
124 void Debugger::OnDetach(const DetachCallback& callback) {
125   detach_callback_ = callback;
126 }
127
128 void Debugger::OnEvent(const ResponseCallback& callback) {
129   response_callback_ = callback;
130 }
131
132 // static
133 mate::Handle<Debugger> Debugger::Create(
134     v8::Isolate* isolate,
135     content::WebContents* web_contents) {
136   return mate::CreateHandle(isolate, new Debugger(web_contents));
137 }
138
139 // static
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);
148 }
149
150 }  // namespace api
151
152 }  // namespace atom