// 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 backendImpl, int callId, const String& method, {{config.crdtp.namespace}}::span message) : m_backendImpl(std::move(backendImpl)) , m_callId(callId) , m_method(method) , m_message(message.begin(), message.end()) { } DispatcherBase::Callback::~Callback() = default; void DispatcherBase::Callback::dispose() { m_backendImpl = nullptr; } void DispatcherBase::Callback::sendIfActive(std::unique_ptr 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, {{config.crdtp.namespace}}::SpanFrom(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 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 createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& errorMessage, ErrorSupport* errors) { std::unique_ptr protocolError(new ProtocolError(code, errorMessage)); protocolError->m_callId = callId; protocolError->m_hasCallId = true; if (errors && !errors->Errors().empty()) { protocolError->m_data = StringUtil::fromUTF8(errors->Errors().data(), errors->Errors().size()); } return protocolError; } static std::unique_ptr createErrorNotification(DispatchResponse::ErrorCode code, const String& errorMessage) { return std::unique_ptr(new ProtocolError(code, errorMessage)); } void AppendSerialized(std::vector* 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 toDictionary() const { std::unique_ptr 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 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() { std::unique_ptr 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 dispatcher) { m_dispatchers[name] = std::move(dispatcher); } void UberDispatcher::setupRedirects(const std::unordered_map& 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 parsedMessage, {{config.crdtp.namespace}}::span 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 messageObject = DictionaryValue::cast(std::move(parsedMessage)); dispatcher->dispatch(callId, method, rawMessage, std::move(messageObject)); } UberDispatcher::~UberDispatcher() = default; // static std::unique_ptr InternalResponse::createResponse(int callId, std::unique_ptr params) { return std::unique_ptr(new InternalResponse(callId, nullptr, std::move(params))); } // static std::unique_ptr InternalResponse::createNotification(const char* method, std::unique_ptr params) { return std::unique_ptr(new InternalResponse(0, method, std::move(params))); } // static std::unique_ptr InternalResponse::createErrorResponse(int callId, DispatchResponse::ErrorCode code, const String& message) { return ProtocolError::createErrorResponse(callId, code, message, nullptr); } void InternalResponse::AppendSerialized(std::vector* 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 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 params) : m_callId(callId) , m_method(method) , m_params(params ? std::move(params) : nullptr) { } {% for namespace in config.protocol.namespace %} } // namespace {{namespace}} {% endfor %}