blob: 4f87072e208c4b02c97d94d42714fdf7a5a1c798 [file] [log] [blame]
// This file is generated
// Copyright (c) 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/inspector_protocol/{{class_name}}.h"
#include "platform/inspector_protocol/Collections.h"
#include "platform/inspector_protocol/FrontendChannel.h"
#include "platform/inspector_protocol/Parser.h"
namespace blink {
namespace protocol {
using protocol::Maybe;
class DispatcherImpl;
class DispatcherImplWeakPtr {
public:
DispatcherImplWeakPtr(DispatcherImpl* dispatcher) : m_dispatcher(dispatcher) { }
~DispatcherImplWeakPtr();
DispatcherImpl* get() { return m_dispatcher; }
void dispose() { m_dispatcher = nullptr; }
private:
DispatcherImpl* m_dispatcher;
};
class DispatcherImpl : public Dispatcher {
public:
DispatcherImpl(FrontendChannel* frontendChannel)
: m_frontendChannel(frontendChannel)
{% for domain in api.domains %}
, m_{{domain.domain | lower}}Agent(0)
{% endfor %}
{
{% for domain in api.domains %}
{% for command in domain.commands %}
{% if "redirect" in command %}{% continue %}{% endif %}
{% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
m_dispatchMap.set("{{domain.domain}}.{{command.name}}", &DispatcherImpl::{{domain.domain}}_{{command.name}});
{% endfor %}
{% endfor %}
// Initialize common errors.
m_commonErrors.resize(LastEntry);
m_commonErrors[ParseError] = -32700;
m_commonErrors[InvalidRequest] = -32600;
m_commonErrors[MethodNotFound] = -32601;
m_commonErrors[InvalidParams] = -32602;
m_commonErrors[InternalError] = -32603;
m_commonErrors[ServerError] = -32000;
}
~DispatcherImpl() { clearFrontend(); }
virtual void clearFrontend()
{
m_frontendChannel = nullptr;
for (auto& weak : m_weakPtrs)
weak.first->dispose();
m_weakPtrs.clear();
}
std::unique_ptr<DispatcherImplWeakPtr> weakPtr()
{
std::unique_ptr<DispatcherImplWeakPtr> weak(new DispatcherImplWeakPtr(this));
m_weakPtrs.add(weak.get());
return weak;
}
virtual void dispatch(const String16& message);
virtual void reportProtocolError(int callId, CommonErrorCode, const String16& errorMessage, ErrorSupport* errors) const;
using Dispatcher::reportProtocolError;
void sendResponse(int callId, const ErrorString& invocationError, ErrorSupport* errors, std::unique_ptr<protocol::DictionaryValue> result);
{% for domain in api.domains %}
virtual void registerAgent(blink::protocol::{{domain.domain}}::Backend* agent) { DCHECK(!m_{{domain.domain | lower}}Agent); m_{{domain.domain | lower}}Agent = agent; }
{% endfor %}
private:
friend class DispatcherCallbackBase;
friend class DispatcherImplWeakPtr;
using CallHandler = void (DispatcherImpl::*)(int callId, std::unique_ptr<DictionaryValue> messageObject, ErrorSupport* errors);
using DispatchMap = protocol::HashMap<String16, CallHandler>;
{% for domain in api.domains %}
{% for command in domain.commands %}
{% if "redirect" in command %}{% continue %}{% endif %}
{% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
void {{domain.domain}}_{{command.name}}(int callId, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport*);
{% endfor %}
{% endfor %}
FrontendChannel* m_frontendChannel;
{% for domain in api.domains %}
{{domain.domain}}::Backend* m_{{domain.domain | lower}}Agent;
{% endfor %}
void sendResponse(int callId, ErrorString invocationError, std::unique_ptr<protocol::DictionaryValue> result)
{
sendResponse(callId, invocationError, nullptr, std::move(result));
}
void sendResponse(int callId, ErrorString invocationError)
{
sendResponse(callId, invocationError, nullptr, DictionaryValue::create());
}
static const char kInvalidRequest[];
DispatchMap m_dispatchMap;
protocol::Vector<int> m_commonErrors;
protocol::HashSet<DispatcherImplWeakPtr*> m_weakPtrs;
};
class PLATFORM_EXPORT DispatcherCallbackBase : public protocol::BackendCallback {
public:
DispatcherCallbackBase(std::unique_ptr<DispatcherImplWeakPtr> backendImpl, int callId)
: m_backendImpl(std::move(backendImpl)), m_callId(callId) { }
virtual ~DispatcherCallbackBase() { }
void dispose() { m_backendImpl = nullptr; }
protected:
void sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const ErrorString& invocationError)
{
if (!m_backendImpl->get())
return;
m_backendImpl->get()->sendResponse(m_callId, invocationError, nullptr, std::move(partialMessage));
m_backendImpl = nullptr;
}
private:
std::unique_ptr<DispatcherImplWeakPtr> m_backendImpl;
int m_callId;
};
DispatcherImplWeakPtr::~DispatcherImplWeakPtr()
{
if (m_dispatcher)
m_dispatcher->m_weakPtrs.remove(this);
}
const char DispatcherImpl::kInvalidRequest[] = "Invalid request";
{% for domain in api.domains %}
{% for command in domain.commands %}
{% if "redirect" in command %}{% continue %}{% endif %}
{% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
{% if "async" in command %}
class PLATFORM_EXPORT {{domain.domain}}{{command.name | to_title_case}}Callback : public {{domain.domain}}::Backend::{{command.name | to_title_case}}Callback, public DispatcherCallbackBase {
public:
{{domain.domain}}{{command.name | to_title_case}}Callback(std::unique_ptr<DispatcherImplWeakPtr> backendImpl, int callId)
: DispatcherCallbackBase(std::move(backendImpl), callId) { }
void sendSuccess(
{%- for parameter in command.returns -%}
{%- if "optional" in parameter -%}
const Maybe<{{resolve_type(parameter).raw_type}}>& {{parameter.name}}
{%- else -%}
{{resolve_type(parameter).pass_type}} {{parameter.name}}
{%- endif -%}
{%- if not loop.last -%}, {% endif -%}
{%- endfor -%}) override
{
std::unique_ptr<protocol::DictionaryValue> resultObject = DictionaryValue::create();
{% for parameter in command.returns %}
{% if "optional" in parameter %}
if ({{parameter.name}}.isJust())
resultObject->setValue("{{parameter.name}}", toValue({{parameter.name}}.fromJust()));
{% else %}
resultObject->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).to_raw_type % parameter.name}}));
{% endif %}
{% endfor %}
sendIfActive(std::move(resultObject), ErrorString());
}
void sendFailure(const ErrorString& error) override
{
DCHECK(error.length());
sendIfActive(nullptr, error);
}
};
{% endif %}
void DispatcherImpl::{{domain.domain}}_{{command.name}}(int callId, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport* errors)
{
if (!m_{{domain.domain | lower}}Agent)
errors->addError("{{domain.domain}} handler is not available.");
if (errors->hasErrors()) {
reportProtocolError(callId, InvalidParams, kInvalidRequest, errors);
return;
}
{% if "parameters" in command %}
// Prepare input parameters.
protocol::DictionaryValue* object = DictionaryValue::cast(requestMessageObject->get("params"));
errors->push();
{% for property in command.parameters %}
protocol::Value* {{property.name}}Value = object ? object->get("{{property.name}}") : nullptr;
{% if property.optional %}
Maybe<{{resolve_type(property).raw_type}}> in_{{property.name}};
if ({{property.name}}Value) {
errors->setName("{{property.name}}");
in_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors);
}
{% else %}
errors->setName("{{property.name}}");
{{resolve_type(property).type}} in_{{property.name}} = FromValue<{{resolve_type(property).raw_type}}>::parse({{property.name}}Value, errors);
{% endif %}
{% endfor %}
errors->pop();
if (errors->hasErrors()) {
reportProtocolError(callId, InvalidParams, kInvalidRequest, errors);
return;
}
{% endif %}
{% if "async" in command %}
std::unique_ptr<{{domain.domain}}{{command.name | to_title_case}}Callback> callback(new {{domain.domain}}{{command.name | to_title_case}}Callback(weakPtr(), callId));
{% elif "returns" in command %}
// Declare output parameters.
std::unique_ptr<protocol::DictionaryValue> result = DictionaryValue::create();
{% for property in command.returns %}
{% if "optional" in property %}
Maybe<{{resolve_type(property).raw_type}}> out_{{property.name}};
{% else %}
{{resolve_type(property).type}} out_{{property.name}};
{% endif %}
{% endfor %}
{% endif %}
std::unique_ptr<DispatcherImplWeakPtr> weak = weakPtr();
ErrorString error;
m_{{domain.domain | lower}}Agent->{{command.name}}(&error
{%- for property in command.parameters -%}
{%- if "optional" in property -%}
, in_{{property.name}}
{%- else -%}
, {{resolve_type(property).to_pass_type % ("in_" + property.name)}}
{%- endif -%}
{%- endfor %}
{%- if "async" in command -%}
, std::move(callback)
{%- elif "returns" in command %}
{%- for property in command.returns -%}
, &out_{{property.name}}
{%- endfor %}
{% endif %});
{% if "returns" in command and not("async" in command) %}
if (!error.length()) {
{% for parameter in command.returns %}
{% if "optional" in parameter %}
if (out_{{parameter.name}}.isJust())
result->setValue("{{parameter.name}}", toValue(out_{{parameter.name}}.fromJust()));
{% else %}
result->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}}));
{% endif %}
{% endfor %}
}
if (weak->get())
weak->get()->sendResponse(callId, error, std::move(result));
{% elif not("async" in command) %}
if (weak->get())
weak->get()->sendResponse(callId, error);
{% endif %}
}
{% endfor %}
{% endfor %}
std::unique_ptr<Dispatcher> Dispatcher::create(FrontendChannel* frontendChannel)
{
return wrapUnique(new DispatcherImpl(frontendChannel));
}
void DispatcherImpl::dispatch(const String16& message)
{
int callId = 0;
std::unique_ptr<protocol::Value> parsedMessage = parseJSON(message);
DCHECK(parsedMessage);
std::unique_ptr<protocol::DictionaryValue> messageObject = DictionaryValue::cast(std::move(parsedMessage));
DCHECK(messageObject);
protocol::Value* callIdValue = messageObject->get("id");
bool success = callIdValue->asNumber(&callId);
DCHECK(success);
protocol::Value* methodValue = messageObject->get("method");
String16 method;
success = methodValue && methodValue->asString(&method);
DCHECK(success);
protocol::HashMap<String16, CallHandler>::iterator it = m_dispatchMap.find(method);
if (it == m_dispatchMap.end()) {
reportProtocolError(callId, MethodNotFound, "'" + method + "' wasn't found");
return;
}
protocol::ErrorSupport errors;
((*this).*(*it->second))(callId, std::move(messageObject), &errors);
}
void DispatcherImpl::sendResponse(int callId, const ErrorString& invocationError, ErrorSupport* errors, std::unique_ptr<protocol::DictionaryValue> result)
{
if (invocationError.length() || (errors && errors->hasErrors())) {
reportProtocolError(callId, ServerError, invocationError, errors);
return;
}
std::unique_ptr<protocol::DictionaryValue> responseMessage = DictionaryValue::create();
responseMessage->setNumber("id", callId);
responseMessage->setObject("result", std::move(result));
if (m_frontendChannel)
m_frontendChannel->sendProtocolResponse(callId, responseMessage->toJSONString());
}
void Dispatcher::reportProtocolError(int callId, CommonErrorCode code, const String16& errorMessage) const
{
ErrorSupport errors;
reportProtocolError(callId, code, errorMessage, &errors);
}
void DispatcherImpl::reportProtocolError(int callId, CommonErrorCode code, const String16& errorMessage, ErrorSupport* errors) const
{
DCHECK(code >=0);
DCHECK((unsigned)code < m_commonErrors.size());
DCHECK(m_commonErrors[code]);
std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
error->setNumber("code", m_commonErrors[code]);
error->setString("message", errorMessage);
DCHECK(error);
if (errors && errors->hasErrors())
error->setString("data", errors->errors());
std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
message->setObject("error", std::move(error));
message->setNumber("id", callId);
if (m_frontendChannel)
m_frontendChannel->sendProtocolResponse(callId, message->toJSONString());
}
bool Dispatcher::getCommandName(const String16& message, String16* result)
{
std::unique_ptr<protocol::Value> value = parseJSON(message);
if (!value)
return false;
protocol::DictionaryValue* object = DictionaryValue::cast(value.get());
if (!object)
return false;
if (!object->getString("method", result))
return false;
return true;
}
} // namespace protocol
} // namespace blink