enclose-io/compiler

View on GitHub
lts/tools/inspector_protocol/lib/DispatcherBase_cpp.template

Summary

Maintainability
Test Coverage
// 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));
    }

    String serializeToJSON() override
    {
        return serialize()->serializeToJSON();
    }

    std::vector<uint8_t> serializeToBinary() override
    {
        return serialize()->serializeToBinary();
    }

    ~ProtocolError() override {}

private:
    ProtocolError(DispatchResponse::ErrorCode code, const String& errorMessage)
        : m_code(code)
        , m_errorMessage(errorMessage)
    {
    }

    std::unique_ptr<DictionaryValue> serialize() {
        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<InternalResponse> InternalResponse::createResponse(int callId, std::unique_ptr<Serializable> params)
{
    return std::unique_ptr<InternalResponse>(new InternalResponse(callId, String(), std::move(params)));
}

// static
std::unique_ptr<InternalResponse> InternalResponse::createNotification(const String& notification, std::unique_ptr<Serializable> params)
{
    return std::unique_ptr<InternalResponse>(new InternalResponse(0, notification, std::move(params)));
}

String InternalResponse::serializeToJSON()
{
    std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
    std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
    if (m_notification.length()) {
        result->setString("method", m_notification);
        result->setValue("params", SerializedValue::fromJSON(params->serializeToJSON()));
    } else {
        result->setInteger("id", m_callId);
        result->setValue("result", SerializedValue::fromJSON(params->serializeToJSON()));
    }
    return result->serializeToJSON();
}

std::vector<uint8_t> InternalResponse::serializeToBinary()
{
    std::unique_ptr<DictionaryValue> result = DictionaryValue::create();
    std::unique_ptr<Serializable> params(m_params ? std::move(m_params) : DictionaryValue::create());
    if (m_notification.length()) {
        result->setString("method", m_notification);
        result->setValue("params", SerializedValue::fromBinary(params->serializeToBinary()));
    } else {
        result->setInteger("id", m_callId);
        result->setValue("result", SerializedValue::fromBinary(params->serializeToBinary()));
    }
    return result->serializeToBinary();
}

InternalResponse::InternalResponse(int callId, const String& notification, std::unique_ptr<Serializable> params)
    : m_callId(callId)
    , m_notification(notification)
    , m_params(params ? std::move(params) : nullptr)
{
}

{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}