blob: 87404c1decca6383587d861d156f455be6e8ee4d [file] [log] [blame]
// 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, bool fallThroughForNotFound)
: DispatcherBase(frontendChannel)
, m_backend(backend)
, m_fallThroughForNotFound(fallThroughForNotFound) {
{% 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 { }
DispatchResponse::Status dispatch(int callId, const String& method, std::unique_ptr<protocol::DictionaryValue> messageObject) override;
HashMap<String, String>& redirects() { return m_redirects; }
protected:
using CallHandler = DispatchResponse::Status (DispatcherImpl::*)(int callId, std::unique_ptr<DictionaryValue> messageObject, ErrorSupport* errors);
using DispatchMap = protocol::HashMap<String, CallHandler>;
DispatchMap m_dispatchMap;
HashMap<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 %}
DispatchResponse::Status {{command.name}}(int callId, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport*);
{% endfor %}
Backend* m_backend;
bool m_fallThroughForNotFound;
};
DispatchResponse::Status DispatcherImpl::dispatch(int callId, const String& method, std::unique_ptr<protocol::DictionaryValue> messageObject)
{
protocol::HashMap<String, CallHandler>::iterator it = m_dispatchMap.find(method);
if (it == m_dispatchMap.end()) {
if (m_fallThroughForNotFound)
return DispatchResponse::kFallThrough;
reportProtocolError(callId, DispatchResponse::kMethodNotFound, "'" + method + "' wasn't found", nullptr);
return DispatchResponse::kError;
}
protocol::ErrorSupport errors;
return (this->*(it->second))(callId, 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, int callbackId)
: DispatcherBase::Callback(std::move(backendImpl), callId, callbackId) { }
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 %}
DispatchResponse::Status DispatcherImpl::{{command.name}}(int callId, 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 DispatchResponse::kError;
}
{% 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)
return response.status();
{% 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 response.status();
{% 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, nextCallbackId()));
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 (weak->get() && weak->get()->lastCallbackFallThrough()) ? DispatchResponse::kFallThrough : DispatchResponse::kAsync;
{% endif %}
}
{% endfor %}
// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
std::unique_ptr<DispatcherImpl> dispatcher(new DispatcherImpl(uber->channel(), backend, uber->fallThroughForNotFound()));
uber->setupRedirects(dispatcher->redirects());
uber->registerBackend("{{domain.domain}}", std::move(dispatcher));
}
} // {{domain.domain}}
{% for namespace in config.protocol.namespace %}
} // namespace {{namespace}}
{% endfor %}