blob: 22fabf9bfb9a5e606e1980c8555348c30dac2947 [file] [log] [blame]
// This file is generated by DispatcherBase_cpp.template.
// Copyright 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 "DispatcherBase.h"
//#include "Parser.h"
{% for namespace in config.protocol.namespace %}
namespace {{namespace}} {
{% endfor %}
// static
DispatchResponse DispatchResponse::OK()
{
DispatchResponse result;
result.m_status = kSuccess;
result.m_errorCode = kParseError;
return result;
}
// static
DispatchResponse DispatchResponse::Error(const String& error)
{
DispatchResponse result;
result.m_status = kError;
result.m_errorCode = kServerError;
result.m_errorMessage = error;
return result;
}
// static
DispatchResponse DispatchResponse::InternalError()
{
DispatchResponse result;
result.m_status = kError;
result.m_errorCode = kInternalError;
result.m_errorMessage = "Internal error";
return result;
}
// static
DispatchResponse DispatchResponse::InvalidParams(const String& error)
{
DispatchResponse result;
result.m_status = kError;
result.m_errorCode = kInvalidParams;
result.m_errorMessage = error;
return result;
}
// static
DispatchResponse DispatchResponse::FallThrough()
{
DispatchResponse result;
result.m_status = kFallThrough;
result.m_errorCode = kParseError;
return result;
}
// static
const char DispatcherBase::kInvalidParamsString[] = "Invalid parameters";
DispatcherBase::WeakPtr::WeakPtr(DispatcherBase* dispatcher) : m_dispatcher(dispatcher) { }
DispatcherBase::WeakPtr::~WeakPtr()
{
if (m_dispatcher)
m_dispatcher->m_weakPtrs.erase(this);
}
DispatcherBase::Callback::Callback(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, const ProtocolMessage& message)
: m_backendImpl(std::move(backendImpl))
, m_callId(callId)
, m_method(method)
, m_message(message) { }
DispatcherBase::Callback::~Callback() = default;
void DispatcherBase::Callback::dispose()
{
m_backendImpl = nullptr;
}
void DispatcherBase::Callback::sendIfActive(std::unique_ptr<protocol::DictionaryValue> partialMessage, const DispatchResponse& response)
{
if (!m_backendImpl || !m_backendImpl->get())
return;
m_backendImpl->get()->sendResponse(m_callId, response, std::move(partialMessage));
m_backendImpl = nullptr;
}
void DispatcherBase::Callback::fallThroughIfActive()
{
if (!m_backendImpl || !m_backendImpl->get())
return;
m_backendImpl->get()->channel()->fallThrough(m_callId, m_method, m_message);
m_backendImpl = nullptr;
}
DispatcherBase::DispatcherBase(FrontendChannel* frontendChannel)
: m_frontendChannel(frontendChannel) { }
DispatcherBase::~DispatcherBase()
{
clearFrontend();
}
void DispatcherBase::sendResponse(int callId, const DispatchResponse& response, std::unique_ptr<protocol::DictionaryValue> result)
{
if (!m_frontendChannel)
return;
if (response.status() == DispatchResponse::kError) {
reportProtocolError(callId, response.errorCode(), response.errorMessage(), nullptr);
return;
}
m_frontendChannel->sendProtocolResponse(callId, InternalResponse::createResponse(callId, std::move(result)));
}
void DispatcherBase::sendResponse(int callId, const DispatchResponse& response)
{
sendResponse(callId, response, DictionaryValue::create());
}
namespace {
class ProtocolError : public Serializable {
public:
static std::unique_ptr<ProtocolError> createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
{
std::unique_ptr<ProtocolError> protocolError(new ProtocolError(code, errorMessage));
protocolError->m_callId = callId;
protocolError->m_hasCallId = true;
if (errors && errors->hasErrors())
protocolError->m_data = errors->errors();
return protocolError;
}
static std::unique_ptr<ProtocolError> createErrorNotification(DispatchResponse::ErrorCode code, const String& errorMessage)
{
return std::unique_ptr<ProtocolError>(new ProtocolError(code, errorMessage));
}
void AppendSerialized(std::vector<uint8_t>* out) const override
{
toDictionary()->AppendSerialized(out);
}
~ProtocolError() override {}
private:
ProtocolError(DispatchResponse::ErrorCode code, const String& errorMessage)
: m_code(code)
, m_errorMessage(errorMessage)
{
}
std::unique_ptr<DictionaryValue> toDictionary() const {
std::unique_ptr<protocol::DictionaryValue> error = DictionaryValue::create();
error->setInteger("code", m_code);
error->setString("message", m_errorMessage);
if (m_data.length())
error->setString("data", m_data);
std::unique_ptr<protocol::DictionaryValue> message = DictionaryValue::create();
message->setObject("error", std::move(error));
if (m_hasCallId)
message->setInteger("id", m_callId);
return message;
}
DispatchResponse::ErrorCode m_code;
String m_errorMessage;
String m_data;
int m_callId = 0;
bool m_hasCallId = false;
};
} // namespace
static void reportProtocolErrorTo(FrontendChannel* frontendChannel, int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
{
if (frontendChannel)
frontendChannel->sendProtocolResponse(callId, ProtocolError::createErrorResponse(callId, code, errorMessage, errors));
}
static void reportProtocolErrorTo(FrontendChannel* frontendChannel, DispatchResponse::ErrorCode code, const String& errorMessage)
{
if (frontendChannel)
frontendChannel->sendProtocolNotification(ProtocolError::createErrorNotification(code, errorMessage));
}
void DispatcherBase::reportProtocolError(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors)
{
reportProtocolErrorTo(m_frontendChannel, callId, code, errorMessage, errors);
}
void DispatcherBase::clearFrontend()
{
m_frontendChannel = nullptr;
for (auto& weak : m_weakPtrs)
weak->dispose();
m_weakPtrs.clear();
}
std::unique_ptr<DispatcherBase::WeakPtr> DispatcherBase::weakPtr()
{
std::unique_ptr<DispatcherBase::WeakPtr> weak(new DispatcherBase::WeakPtr(this));
m_weakPtrs.insert(weak.get());
return weak;
}
UberDispatcher::UberDispatcher(FrontendChannel* frontendChannel)
: m_frontendChannel(frontendChannel) { }
void UberDispatcher::registerBackend(const String& name, std::unique_ptr<protocol::DispatcherBase> dispatcher)
{
m_dispatchers[name] = std::move(dispatcher);
}
void UberDispatcher::setupRedirects(const std::unordered_map<String, String>& redirects)
{
for (const auto& pair : redirects)
m_redirects[pair.first] = pair.second;
}
bool UberDispatcher::parseCommand(Value* parsedMessage, int* outCallId, String* outMethod) {
if (!parsedMessage) {
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kParseError, "Message must be a valid JSON");
return false;
}
protocol::DictionaryValue* messageObject = DictionaryValue::cast(parsedMessage);
if (!messageObject) {
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must be an object");
return false;
}
int callId = 0;
protocol::Value* callIdValue = messageObject->get("id");
bool success = callIdValue && callIdValue->asInteger(&callId);
if (!success) {
reportProtocolErrorTo(m_frontendChannel, DispatchResponse::kInvalidRequest, "Message must have integer 'id' property");
return false;
}
if (outCallId)
*outCallId = callId;
protocol::Value* methodValue = messageObject->get("method");
String method;
success = methodValue && methodValue->asString(&method);
if (!success) {
reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kInvalidRequest, "Message must have string 'method' property", nullptr);
return false;
}
if (outMethod)
*outMethod = method;
return true;
}
protocol::DispatcherBase* UberDispatcher::findDispatcher(const String& method) {
size_t dotIndex = StringUtil::find(method, ".");
if (dotIndex == StringUtil::kNotFound)
return nullptr;
String domain = StringUtil::substring(method, 0, dotIndex);
auto it = m_dispatchers.find(domain);
if (it == m_dispatchers.end())
return nullptr;
if (!it->second->canDispatch(method))
return nullptr;
return it->second.get();
}
bool UberDispatcher::canDispatch(const String& in_method)
{
String method = in_method;
auto redirectIt = m_redirects.find(method);
if (redirectIt != m_redirects.end())
method = redirectIt->second;
return !!findDispatcher(method);
}
void UberDispatcher::dispatch(int callId, const String& in_method, std::unique_ptr<Value> parsedMessage, const ProtocolMessage& rawMessage)
{
String method = in_method;
auto redirectIt = m_redirects.find(method);
if (redirectIt != m_redirects.end())
method = redirectIt->second;
protocol::DispatcherBase* dispatcher = findDispatcher(method);
if (!dispatcher) {
reportProtocolErrorTo(m_frontendChannel, callId, DispatchResponse::kMethodNotFound, "'" + method + "' wasn't found", nullptr);
return;
}
std::unique_ptr<protocol::DictionaryValue> messageObject = DictionaryValue::cast(std::move(parsedMessage));
dispatcher->dispatch(callId, method, rawMessage, std::move(messageObject));
}
UberDispatcher::~UberDispatcher() = default;
// static
std::unique_ptr<Serializable> InternalResponse::createResponse(int callId, std::unique_ptr<Serializable> params)
{
return std::unique_ptr<Serializable>(new InternalResponse(callId, nullptr, std::move(params)));
}
// static
std::unique_ptr<Serializable> InternalResponse::createNotification(const char* method, std::unique_ptr<Serializable> params)
{
return std::unique_ptr<Serializable>(new InternalResponse(0, method, std::move(params)));
}
// static
std::unique_ptr<Serializable> InternalResponse::createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& message)
{
return ProtocolError::createErrorResponse(callId, code, message, nullptr);
}
void InternalResponse::AppendSerialized(std::vector<uint8_t>* out) const
{
using {{config.crdtp.namespace}}::cbor::NewCBOREncoder;
using {{config.crdtp.namespace}}::ParserHandler;
using {{config.crdtp.namespace}}::Status;
using {{config.crdtp.namespace}}::SpanFrom;
Status status;
std::unique_ptr<ParserHandler> encoder = NewCBOREncoder(out, &status);
encoder->HandleMapBegin();
if (m_method) {
encoder->HandleString8(SpanFrom("method"));
encoder->HandleString8(SpanFrom(m_method));
encoder->HandleString8(SpanFrom("params"));
} else {
encoder->HandleString8(SpanFrom("id"));
encoder->HandleInt32(m_callId);
encoder->HandleString8(SpanFrom("result"));
}
if (m_params) {
m_params->AppendSerialized(out);
} else {
encoder->HandleMapBegin();
encoder->HandleMapEnd();
}
encoder->HandleMapEnd();
DCHECK(status.ok());
}
InternalResponse::InternalResponse(int callId, const char* method, std::unique_ptr<Serializable> params)
: m_callId(callId)
, m_method(method)
, m_params(params ? std::move(params) : nullptr)
{
}
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}