blob: 30aea03d716bb025583e58c35e793c598750eb5a [file] [log] [blame]
// Copyright 2018 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/debug/backend/script_debugger_agent.h"
#include <string>
#include "base/stringprintf.h"
#include "cobalt/debug/json_object.h"
namespace {
constexpr const char* kInspectorDomains[] = {
"Runtime", "Debugger", "Profiler",
// TODO: "HeapProfiler",
};
constexpr int kInspectorDomainsCount =
sizeof(kInspectorDomains) / sizeof(kInspectorDomains[0]);
// JSON attribute names
constexpr char kId[] = "id";
constexpr char kMethod[] = "method";
constexpr char kParams[] = "params";
} // namespace
namespace cobalt {
namespace debug {
namespace backend {
ScriptDebuggerAgent::ScriptDebuggerAgent(
DebugDispatcher* dispatcher, script::ScriptDebugger* script_debugger)
: dispatcher_(dispatcher), script_debugger_(script_debugger) {
for (int i = 0; i < kInspectorDomainsCount; i++) {
std::string domain(kInspectorDomains[i]);
if (script_debugger_->CanDispatchProtocolMethod(domain + ".enable")) {
dispatcher_->AddDomain(
domain,
base::Bind(&ScriptDebuggerAgent::RunCommand, base::Unretained(this)));
registered_domains_.insert(domain);
}
}
}
ScriptDebuggerAgent::~ScriptDebuggerAgent() {
for (auto it = registered_domains_.begin(); it != registered_domains_.end();
++it) {
dispatcher_->RemoveDomain(*it);
}
}
bool ScriptDebuggerAgent::RunCommand(const Command& command) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!script_debugger_->CanDispatchProtocolMethod(command.GetMethod())) {
return false;
}
// Use an internal ID to store the pending command until we get a response.
int command_id = ++last_command_id_;
pending_commands_.emplace(command_id, command);
JSONObject message(new base::DictionaryValue());
message->SetInteger(kId, command_id);
message->SetString(kMethod, command.GetMethod());
JSONObject params = JSONParse(command.GetParams());
if (params) {
message->Set(kParams, params.release());
}
script_debugger_->DispatchProtocolMessage(JSONStringify(message));
return true;
}
void ScriptDebuggerAgent::SendCommandResponse(
const std::string& json_response) {
JSONObject response = JSONParse(json_response);
// Strip the internal ID from the response, and get its value.
int command_id = 0;
response->GetInteger(kId, &command_id);
response->Remove(kId, nullptr);
// Use the stripped ID to lookup the command it's a response for.
auto iter = pending_commands_.find(command_id);
if (iter != pending_commands_.end()) {
iter->second.SendResponse(response);
pending_commands_.erase(iter);
} else {
DLOG(ERROR) << "Spurious debugger response: " << json_response;
}
}
void ScriptDebuggerAgent::SendEvent(const std::string& json_event) {
JSONObject event = JSONParse(json_event);
std::string method;
event->GetString(kMethod, &method);
JSONObject params;
base::Value* value = nullptr;
base::DictionaryValue* dict_value = nullptr;
if (event->Get(kParams, &value) && value->GetAsDictionary(&dict_value)) {
params.reset(dict_value->DeepCopy());
}
dispatcher_->SendEvent(method, params);
}
} // namespace backend
} // namespace debug
} // namespace cobalt