| // This file is generated |
| |
| // 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<protocol::DictionaryValue> {{type.id}}::toValue() const |
| { |
| std::unique_ptr<protocol::DictionaryValue> 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()->serialize(); |
| return {{config.exported.to_string_out % "json"}}; |
| } |
| |
| // static |
| std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromJSONString(const {{config.exported.string_in}}& json) |
| { |
| ErrorSupport errors; |
| std::unique_ptr<Value> value = StringUtil::parseJSON(json); |
| 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::sendRawNotification(const String& notification) |
| { |
| m_frontendChannel->sendProtocolNotification(InternalRawNotification::create(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 String& message, std::unique_ptr<protocol::DictionaryValue> messageObject) override; |
| std::unordered_map<String, String>& redirects() { return m_redirects; } |
| |
| protected: |
| using CallHandler = void (DispatcherImpl::*)(int callId, const String& method, const String& message, std::unique_ptr<DictionaryValue> messageObject, ErrorSupport* errors); |
| using DispatchMap = std::unordered_map<String, CallHandler>; |
| DispatchMap m_dispatchMap; |
| std::unordered_map<String, String> 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 String& message, std::unique_ptr<DictionaryValue> 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 String& message, std::unique_ptr<protocol::DictionaryValue> messageObject) |
| { |
| std::unordered_map<String, CallHandler>::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<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, const String& 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<protocol::DictionaryValue> 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 String& message, std::unique_ptr<DictionaryValue> 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<DispatcherBase::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(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<protocol::DictionaryValue> 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<DispatcherBase::WeakPtr> 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<DispatcherImpl> 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 %} |