// This file is generated by TypeBuilder_cpp.template. // 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 {{format_domain_include(config.protocol.package, domain.domain)}} #include {{format_include(config.protocol.package, "Protocol")}} {% for namespace in config.protocol.namespace %} namespace {{namespace}} { {% endfor %} namespace {{domain.domain}} { // ------------- Enum values from types. const char Metainfo::domainName[] = "{{domain.domain}}"; const char Metainfo::commandPrefix[] = "{{domain.domain}}."; const char Metainfo::version[] = "{{domain.version}}"; {% for type in domain.types %} {% if not protocol.generate_type(domain.domain, type.id) %}{% continue %} {% endif %} {% if "enum" in type %} namespace {{type.id}}Enum { {% for literal in type.enum %} const char {{ literal | dash_to_camelcase}}[] = "{{literal}}"; {% endfor %} } // namespace {{type.id}}Enum {% if protocol.is_exported(domain.domain, type.id) %} namespace API { namespace {{type.id}}Enum { {% for literal in type.enum %} const char* {{ literal | dash_to_camelcase}} = "{{literal}}"; {% endfor %} } // namespace {{type.id}}Enum } // namespace API {% endif %} {% endif %} {% for property in type.properties %} {% if "enum" in property %} {% for literal in property.enum %} const char* {{type.id}}::{{property.name | to_title_case}}Enum::{{literal | dash_to_camelcase}} = "{{literal}}"; {% endfor %} {% endif %} {% endfor %} {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %} std::unique_ptr<{{type.id}}> {{type.id}}::fromValue(protocol::Value* value, ErrorSupport* errors) { if (!value || value->type() != protocol::Value::TypeObject) { errors->addError("object expected"); return nullptr; } std::unique_ptr<{{type.id}}> result(new {{type.id}}()); protocol::DictionaryValue* object = DictionaryValue::cast(value); errors->push(); {% for property in type.properties %} protocol::Value* {{property.name}}Value = object->get("{{property.name}}"); {% if property.optional %} if ({{property.name}}Value) { errors->setName("{{property.name}}"); result->m_{{property.name}} = ValueConversions<{{protocol.resolve_type(property).raw_type}}>::fromValue({{property.name}}Value, errors); } {% else %} errors->setName("{{property.name}}"); result->m_{{property.name}} = ValueConversions<{{protocol.resolve_type(property).raw_type}}>::fromValue({{property.name}}Value, errors); {% endif %} {% endfor %} errors->pop(); if (errors->hasErrors()) return nullptr; return result; } std::unique_ptr {{type.id}}::toValue() const { std::unique_ptr result = DictionaryValue::create(); {% for property in type.properties %} {% set property_type = protocol.resolve_type(property) %} {% set property_field = "m_" + property.name %} {% if property.optional %} if ({{property_field}}.isJust()) result->setValue("{{property.name}}", ValueConversions<{{property_type.raw_type}}>::toValue({{property_field}}.fromJust())); {% else %} result->setValue("{{property.name}}", ValueConversions<{{property_type.raw_type}}>::toValue({{property_type.to_raw_type % property_field}})); {% endif %} {% endfor %} return result; } std::unique_ptr<{{type.id}}> {{type.id}}::clone() const { ErrorSupport errors; return fromValue(toValue().get(), &errors); } {% if protocol.is_exported(domain.domain, type.id) %} {{config.exported.string_out}} {{type.id}}::toJSONString() const { String json = toValue()->serializeToJSON(); return {{config.exported.to_string_out % "json"}}; } void {{type.id}}::writeBinary(std::vector* out) const { toValue()->writeBinary(out); } // static std::unique_ptr API::{{type.id}}::fromJSONString(const {{config.exported.string_in}}& json) { ErrorSupport errors; std::unique_ptr value = StringUtil::parseJSON(json); if (!value) return nullptr; return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors); } // static std::unique_ptr API::{{type.id}}::fromBinary(const uint8_t* data, size_t length) { ErrorSupport errors; std::unique_ptr value = Value::parseBinary(data, length); if (!value) return nullptr; return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors); } {% endif %} {% endfor %} // ------------- Enum values from params. {% for command in join_arrays(domain, ["commands", "events"]) %} {% for param in join_arrays(command, ["parameters", "returns"]) %} {% if "enum" in param %} namespace {{command.name | to_title_case}} { namespace {{param.name | to_title_case}}Enum { {% for literal in param.enum %} const char* {{ literal | to_title_case}} = "{{literal}}"; {% endfor %} } // namespace {{param.name | to_title_case}}Enum } // namespace {{command.name | to_title_case }} {% if protocol.is_exported(domain.domain, command.name + "." + param.name) %} namespace API { namespace {{command.name | to_title_case}} { namespace {{param.name | to_title_case}}Enum { {% for literal in param.enum %} const char* {{ literal | to_title_case}} = "{{literal}}"; {% endfor %} } // namespace {{param.name | to_title_case}}Enum } // namespace {{command.name | to_title_case }} } // namespace API {% endif %} {% endif %} {% endfor %} {% endfor %} // ------------- Frontend notifications. {% for event in domain.events %} {% if not protocol.generate_event(domain.domain, event.name) %}{% continue %}{% endif %} void Frontend::{{event.name | to_method_case}}( {%- for parameter in event.parameters %} {% if "optional" in parameter -%} Maybe<{{protocol.resolve_type(parameter).raw_type}}> {%- else -%} {{protocol.resolve_type(parameter).pass_type}} {%- endif %} {{parameter.name}}{%- if not loop.last -%}, {% endif -%} {% endfor -%}) { if (!m_frontendChannel) return; {% if event.parameters %} std::unique_ptr<{{event.name | to_title_case}}Notification> messageData = {{event.name | to_title_case}}Notification::{{"create" | to_method_case}}() {% for parameter in event.parameters %} {% if not "optional" in parameter %} .{{"set" | to_method_case}}{{parameter.name | to_title_case}}({{protocol.resolve_type(parameter).to_pass_type % parameter.name}}) {% endif %} {% endfor %} .{{ "build" | to_method_case }}(); {% for parameter in event.parameters %} {% if "optional" in parameter %} if ({{parameter.name}}.isJust()) messageData->{{"set" | to_method_case}}{{parameter.name | to_title_case}}(std::move({{parameter.name}}).takeJust()); {% endif %} {% endfor %} m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}", std::move(messageData))); {% else %} m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}")); {% endif %} } {% endfor %} void Frontend::flush() { m_frontendChannel->flushProtocolNotifications(); } void Frontend::sendRawJSONNotification(String notification) { m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromJSON(std::move(notification))); } void Frontend::sendRawCBORNotification(std::vector notification) { m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromBinary(std::move(notification))); } // --------------------- Dispatcher. class DispatcherImpl : public protocol::DispatcherBase { public: DispatcherImpl(FrontendChannel* frontendChannel, Backend* backend) : DispatcherBase(frontendChannel) , m_backend(backend) { {% for command in domain.commands %} {% if "redirect" in command %} m_redirects["{{domain.domain}}.{{command.name}}"] = "{{command.redirect}}.{{command.name}}"; {% continue %} {% endif %} {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %} m_dispatchMap["{{domain.domain}}.{{command.name}}"] = &DispatcherImpl::{{command.name}}; {% endfor %} } ~DispatcherImpl() override { } bool canDispatch(const String& method) override; void dispatch(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr messageObject) override; std::unordered_map& redirects() { return m_redirects; } protected: using CallHandler = void (DispatcherImpl::*)(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr messageObject, ErrorSupport* errors); using DispatchMap = std::unordered_map; DispatchMap m_dispatchMap; std::unordered_map m_redirects; {% for command in domain.commands %} {% if "redirect" in command %}{% continue %}{% endif %} {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %} void {{command.name}}(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr requestMessageObject, ErrorSupport*); {% endfor %} Backend* m_backend; }; bool DispatcherImpl::canDispatch(const String& method) { return m_dispatchMap.find(method) != m_dispatchMap.end(); } void DispatcherImpl::dispatch(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr messageObject) { std::unordered_map::iterator it = m_dispatchMap.find(method); DCHECK(it != m_dispatchMap.end()); protocol::ErrorSupport errors; (this->*(it->second))(callId, method, message, std::move(messageObject), &errors); } {% for command in domain.commands %} {% set command_name_title = command.name | to_title_case %} {% if "redirect" in command %}{% continue %}{% endif %} {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %} {% if protocol.is_async_command(domain.domain, command.name) %} class {{command_name_title}}CallbackImpl : public Backend::{{command_name_title}}Callback, public DispatcherBase::Callback { public: {{command_name_title}}CallbackImpl(std::unique_ptr backendImpl, int callId, const String& method, const ProtocolMessage& message) : DispatcherBase::Callback(std::move(backendImpl), callId, method, message) { } void sendSuccess( {%- for parameter in command.returns -%} {%- if "optional" in parameter -%} Maybe<{{protocol.resolve_type(parameter).raw_type}}> {{parameter.name}} {%- else -%} {{protocol.resolve_type(parameter).pass_type}} {{parameter.name}} {%- endif -%} {%- if not loop.last -%}, {% endif -%} {%- endfor -%}) override { std::unique_ptr resultObject = DictionaryValue::create(); {% for parameter in command.returns %} {% if "optional" in parameter %} if ({{parameter.name}}.isJust()) resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{parameter.name}}.fromJust())); {% else %} resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % parameter.name}})); {% endif %} {% endfor %} sendIfActive(std::move(resultObject), DispatchResponse::OK()); } void fallThrough() override { fallThroughIfActive(); } void sendFailure(const DispatchResponse& response) override { DCHECK(response.status() == DispatchResponse::kError); sendIfActive(nullptr, response); } }; {% endif %} void DispatcherImpl::{{command.name}}(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr requestMessageObject, ErrorSupport* errors) { {% if "parameters" in command %} // Prepare input parameters. protocol::DictionaryValue* object = DictionaryValue::cast(requestMessageObject->get("params")); errors->push(); {% for parameter in command.parameters %} {% set parameter_type = protocol.resolve_type(parameter) %} protocol::Value* {{parameter.name}}Value = object ? object->get("{{parameter.name}}") : nullptr; {% if parameter.optional %} Maybe<{{parameter_type.raw_type}}> in_{{parameter.name}}; if ({{parameter.name}}Value) { errors->setName("{{parameter.name}}"); in_{{parameter.name}} = ValueConversions<{{parameter_type.raw_type}}>::fromValue({{parameter.name}}Value, errors); } {% else %} errors->setName("{{parameter.name}}"); {{parameter_type.type}} in_{{parameter.name}} = ValueConversions<{{parameter_type.raw_type}}>::fromValue({{parameter.name}}Value, errors); {% endif %} {% endfor %} errors->pop(); if (errors->hasErrors()) { reportProtocolError(callId, DispatchResponse::kInvalidParams, kInvalidParamsString, errors); return; } {% endif %} {% if "returns" in command and not protocol.is_async_command(domain.domain, command.name) %} // Declare output parameters. {% for parameter in command.returns %} {% if "optional" in parameter %} Maybe<{{protocol.resolve_type(parameter).raw_type}}> out_{{parameter.name}}; {% else %} {{protocol.resolve_type(parameter).type}} out_{{parameter.name}}; {% endif %} {% endfor %} {% endif %} {% if not protocol.is_async_command(domain.domain, command.name) %} std::unique_ptr weak = weakPtr(); DispatchResponse response = m_backend->{{command.name | to_method_case}}( {%- for parameter in command.parameters -%} {%- if not loop.first -%}, {% endif -%} {%- if "optional" in parameter -%} std::move(in_{{parameter.name}}) {%- else -%} {{protocol.resolve_type(parameter).to_pass_type % ("in_" + parameter.name)}} {%- endif -%} {%- endfor %} {%- if "returns" in command %} {%- for parameter in command.returns -%} {%- if not loop.first or command.parameters -%}, {% endif -%} &out_{{parameter.name}} {%- endfor %} {% endif %}); if (response.status() == DispatchResponse::kFallThrough) { channel()->fallThrough(callId, method, message); return; } {% if "returns" in command %} std::unique_ptr result = DictionaryValue::create(); if (response.status() == DispatchResponse::kSuccess) { {% for parameter in command.returns %} {% if "optional" in parameter %} if (out_{{parameter.name}}.isJust()) result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue(out_{{parameter.name}}.fromJust())); {% else %} result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}})); {% endif %} {% endfor %} } if (weak->get()) weak->get()->sendResponse(callId, response, std::move(result)); {% else %} if (weak->get()) weak->get()->sendResponse(callId, response); {% endif %} return; {% else %} std::unique_ptr weak = weakPtr(); std::unique_ptr<{{command_name_title}}CallbackImpl> callback(new {{command.name | to_title_case}}CallbackImpl(weakPtr(), callId, method, message)); m_backend->{{command.name | to_method_case}}( {%- for property in command.parameters -%} {%- if not loop.first -%}, {% endif -%} {%- if "optional" in property -%} std::move(in_{{property.name}}) {%- else -%} {{protocol.resolve_type(property).to_pass_type % ("in_" + property.name)}} {%- endif -%} {%- endfor -%} {%- if command.parameters -%}, {% endif -%} std::move(callback)); return; {% endif %} } {% endfor %} // static void Dispatcher::wire(UberDispatcher* uber, Backend* backend) { std::unique_ptr dispatcher(new DispatcherImpl(uber->channel(), backend)); uber->setupRedirects(dispatcher->redirects()); uber->registerBackend("{{domain.domain}}", std::move(dispatcher)); } } // {{domain.domain}} {% for namespace in config.protocol.namespace %} } // namespace {{namespace}} {% endfor %}