| // 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 %} |