| // 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")}} |
| |
| #include "{{config.crdtp.dir}}/cbor.h" |
| #include "{{config.crdtp.dir}}/find_by_first.h" |
| #include "{{config.crdtp.dir}}/span.h" |
| |
| {% for namespace in config.protocol.namespace %} |
| namespace {{namespace}} { |
| {% endfor %} |
| namespace {{domain.domain}} { |
| |
| using {{config.crdtp.namespace}}::DeserializerState; |
| using {{config.crdtp.namespace}}::ProtocolTypeTraits; |
| |
| // ------------- 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 %} |
| V8_CRDTP_BEGIN_DESERIALIZER({{type.id}}) |
| {% for property in type.properties | sort(attribute = 'name', case_sensitive=True) %} |
| {% if property.optional %} |
| V8_CRDTP_DESERIALIZE_FIELD_OPT("{{property.name}}", m_{{property.name}}), |
| {% else %} |
| V8_CRDTP_DESERIALIZE_FIELD("{{property.name}}", m_{{property.name}}), |
| {% endif %} |
| {% endfor %} |
| V8_CRDTP_END_DESERIALIZER() |
| |
| V8_CRDTP_BEGIN_SERIALIZER({{type.id}}) |
| {% for property in type.properties %} |
| V8_CRDTP_SERIALIZE_FIELD("{{property.name}}", m_{{property.name}}); |
| {% endfor %} |
| V8_CRDTP_END_SERIALIZER(); |
| |
| {% if protocol.is_exported(domain.domain, type.id) %} |
| // static |
| std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromBinary(const uint8_t* data, size_t length) |
| { |
| return protocol::{{domain.domain}}::{{type.id}}::FromBinary(data, length); |
| } |
| {% 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 (!frontend_channel_) |
| return; |
| {% if event.parameters %} |
| {{config.crdtp.namespace}}::ObjectSerializer serializer; |
| {% for parameter in event.parameters %} |
| serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), {{parameter.name}}); |
| {% endfor %} |
| frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}", serializer.Finish())); |
| {% else %} |
| frontend_channel_->SendProtocolNotification({{config.crdtp.namespace}}::CreateNotification("{{domain.domain}}.{{event.name}}")); |
| {% endif %} |
| } |
| {% endfor %} |
| |
| void Frontend::flush() |
| { |
| frontend_channel_->FlushProtocolNotifications(); |
| } |
| |
| void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification) |
| { |
| frontend_channel_->SendProtocolNotification(std::move(notification)); |
| } |
| |
| // --------------------- Dispatcher. |
| |
| class DomainDispatcherImpl : public protocol::DomainDispatcher { |
| public: |
| DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend) |
| : DomainDispatcher(frontendChannel) |
| , m_backend(backend) {} |
| ~DomainDispatcherImpl() override { } |
| |
| using CallHandler = void (DomainDispatcherImpl::*)(const {{config.crdtp.namespace}}::Dispatchable& dispatchable); |
| |
| std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) override; |
| |
| {% 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}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable); |
| {% endfor %} |
| protected: |
| Backend* m_backend; |
| }; |
| |
| namespace { |
| // This helper method with a static map of command methods (instance methods |
| // of DomainDispatcherImpl declared just above) by their name is used immediately below, |
| // in the DomainDispatcherImpl::Dispatch method. |
| DomainDispatcherImpl::CallHandler CommandByName({{config.crdtp.namespace}}::span<uint8_t> command_name) { |
| static auto* commands = [](){ |
| auto* commands = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, |
| DomainDispatcherImpl::CallHandler>>{ |
| {% for command in domain.commands|sort(attribute="name",case_sensitive=True) %} |
| {% if "redirect" in command %}{% continue %}{% endif %} |
| {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %} |
| { |
| {{config.crdtp.namespace}}::SpanFrom("{{command.name}}"), |
| &DomainDispatcherImpl::{{command.name}} |
| }, |
| {% endfor %} |
| }; |
| return commands; |
| }(); |
| return {{config.crdtp.namespace}}::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr); |
| } |
| } // namespace |
| |
| std::function<void(const {{config.crdtp.namespace}}::Dispatchable&)> DomainDispatcherImpl::Dispatch({{config.crdtp.namespace}}::span<uint8_t> command_name) { |
| CallHandler handler = CommandByName(command_name); |
| if (!handler) return nullptr; |
| |
| return [this, handler](const {{config.crdtp.namespace}}::Dispatchable& dispatchable) { |
| (this->*handler)(dispatchable); |
| }; |
| } |
| |
| {% 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 DomainDispatcher::Callback { |
| public: |
| {{command_name_title}}CallbackImpl(std::unique_ptr<DomainDispatcher::WeakPtr> backendImpl, int callId, {{config.crdtp.namespace}}::span<uint8_t> message) |
| : DomainDispatcher::Callback(std::move(backendImpl), callId, |
| {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), 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 |
| { |
| {{config.crdtp.namespace}}::ObjectSerializer serializer; |
| {% for parameter in command.returns %} |
| serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), {{parameter.name}}); |
| {% endfor %} |
| sendIfActive(serializer.Finish(), DispatchResponse::Success()); |
| } |
| |
| void fallThrough() override |
| { |
| fallThroughIfActive(); |
| } |
| |
| void sendFailure(const DispatchResponse& response) override |
| { |
| DCHECK(response.IsError()); |
| sendIfActive(nullptr, response); |
| } |
| }; |
| {% endif %} |
| |
| namespace { |
| |
| {% if "parameters" in command %} |
| struct {{command.name}}Params : public {{config.crdtp.namespace}}::DeserializableProtocolObject<{{command.name}}Params> { |
| {% for parameter in command.parameters %} |
| {% set parameter_type = protocol.resolve_type(parameter) %} |
| {% if parameter.optional %} |
| Maybe<{{parameter_type.raw_type}}> {{parameter.name}}; |
| {% else %} |
| {{parameter_type.type}} {{parameter.name}}; |
| {% endif %} |
| {% endfor %} |
| DECLARE_DESERIALIZATION_SUPPORT(); |
| }; |
| |
| V8_CRDTP_BEGIN_DESERIALIZER({{command.name}}Params) |
| {% for parameter in command.parameters | sort(attribute = 'name', case_sensitive=True) %} |
| {% if parameter.optional %} |
| V8_CRDTP_DESERIALIZE_FIELD_OPT("{{parameter.name}}", {{parameter.name}}), |
| {% else %} |
| V8_CRDTP_DESERIALIZE_FIELD("{{parameter.name}}", {{parameter.name}}), |
| {% endif %} |
| {% endfor %} |
| V8_CRDTP_END_DESERIALIZER() |
| {% endif %} |
| |
| } // namespace |
| |
| void DomainDispatcherImpl::{{command.name}}(const {{config.crdtp.namespace}}::Dispatchable& dispatchable) |
| { |
| // Prepare input parameters. |
| {% if "parameters" in command %} |
| auto deserializer = {{config.crdtp.namespace}}::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer(); |
| {{command.name}}Params params; |
| {{command.name}}Params::Deserialize(&deserializer, ¶ms); |
| if (MaybeReportInvalidParams(dispatchable, deserializer)) |
| 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<DomainDispatcher::WeakPtr> 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(params.{{parameter.name}}) |
| {%- else -%} |
| {{protocol.resolve_type(parameter).to_pass_type % ("params." + 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.IsFallThrough()) { |
| channel()->FallThrough(dispatchable.CallId(), {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), dispatchable.Serialized()); |
| return; |
| } |
| {% if "returns" in command %} |
| if (weak->get()) { |
| std::unique_ptr<{{config.crdtp.namespace}}::Serializable> result; |
| if (response.IsSuccess()) { |
| {{config.crdtp.namespace}}::ObjectSerializer serializer; |
| {% for parameter in command.returns %} |
| serializer.AddField({{config.crdtp.namespace}}::MakeSpan("{{parameter.name}}"), out_{{parameter.name}}); |
| {% endfor %} |
| result = serializer.Finish(); |
| } else { |
| result = Serializable::From({}); |
| } |
| weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result)); |
| } |
| {% else %} |
| if (weak->get()) |
| weak->get()->sendResponse(dispatchable.CallId(), response); |
| {% endif %} |
| return; |
| {% else %} |
| m_backend->{{command.name | to_method_case}}( |
| {%- for property in command.parameters -%} |
| {%- if not loop.first -%}, {% endif -%} |
| {%- if "optional" in property -%} |
| std::move(params.{{property.name}}) |
| {%- else -%} |
| {{protocol.resolve_type(property).to_pass_type % ("params." + property.name)}} |
| {%- endif -%} |
| {%- endfor -%} |
| {%- if command.parameters -%}, {% endif -%} |
| std::make_unique<{{command_name_title}}CallbackImpl>(weakPtr(), dispatchable.CallId(), dispatchable.Serialized())); |
| {% endif %} |
| } |
| {% endfor %} |
| |
| namespace { |
| // This helper method (with a static map of redirects) is used from Dispatcher::wire |
| // immediately below. |
| const std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>& SortedRedirects() { |
| static auto* redirects = [](){ |
| auto* redirects = new std::vector<std::pair<{{config.crdtp.namespace}}::span<uint8_t>, {{config.crdtp.namespace}}::span<uint8_t>>>{ |
| {% for command in domain.commands|sort(attribute="name",case_sensitive=True) %} |
| {% if "redirect" in command %} |
| { {{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}.{{command.name}}"), {{config.crdtp.namespace}}::SpanFrom("{{command.redirect}}.{{command.name}}") }, |
| {% endif %} |
| {% endfor %} |
| }; |
| return redirects; |
| }(); |
| return *redirects; |
| } |
| } // namespace |
| |
| // static |
| void Dispatcher::wire(UberDispatcher* uber, Backend* backend) |
| { |
| auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend); |
| uber->WireBackend({{config.crdtp.namespace}}::SpanFrom("{{domain.domain}}"), SortedRedirects(), std::move(dispatcher)); |
| } |
| |
| } // {{domain.domain}} |
| {% for namespace in config.protocol.namespace %} |
| } // namespace {{namespace}} |
| {% endfor %} |