• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// This file is generated by TypeBuilder_cpp.template.
2
3// Copyright (c) 2016 The Chromium Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7#include {{format_domain_include(config.protocol.package, domain.domain)}}
8
9#include {{format_include(config.protocol.package, "Protocol")}}
10
11{% for namespace in config.protocol.namespace %}
12namespace {{namespace}} {
13{% endfor %}
14namespace {{domain.domain}} {
15
16// ------------- Enum values from types.
17
18const char Metainfo::domainName[] = "{{domain.domain}}";
19const char Metainfo::commandPrefix[] = "{{domain.domain}}.";
20const char Metainfo::version[] = "{{domain.version}}";
21  {% for type in domain.types %}
22    {% if not protocol.generate_type(domain.domain, type.id) %}{% continue %} {% endif %}
23    {% if "enum" in type %}
24
25namespace {{type.id}}Enum {
26      {% for literal in type.enum %}
27const char {{ literal | dash_to_camelcase}}[] = "{{literal}}";
28      {% endfor %}
29} // namespace {{type.id}}Enum
30      {% if protocol.is_exported(domain.domain, type.id) %}
31
32namespace API {
33namespace {{type.id}}Enum {
34        {% for literal in type.enum %}
35const char* {{ literal | dash_to_camelcase}} = "{{literal}}";
36        {% endfor %}
37} // namespace {{type.id}}Enum
38} // namespace API
39      {% endif %}
40    {% endif %}
41    {% for property in type.properties %}
42      {% if "enum" in property %}
43
44        {% for literal in property.enum %}
45const char* {{type.id}}::{{property.name | to_title_case}}Enum::{{literal | dash_to_camelcase}} = "{{literal}}";
46        {% endfor %}
47      {% endif %}
48    {% endfor %}
49    {% if not (type.type == "object") or not ("properties" in type) %}{% continue %}{% endif %}
50
51std::unique_ptr<{{type.id}}> {{type.id}}::fromValue(protocol::Value* value, ErrorSupport* errors)
52{
53    if (!value || value->type() != protocol::Value::TypeObject) {
54        errors->addError("object expected");
55        return nullptr;
56    }
57
58    std::unique_ptr<{{type.id}}> result(new {{type.id}}());
59    protocol::DictionaryValue* object = DictionaryValue::cast(value);
60    errors->push();
61    {% for property in type.properties %}
62    protocol::Value* {{property.name}}Value = object->get("{{property.name}}");
63      {% if property.optional %}
64    if ({{property.name}}Value) {
65        errors->setName("{{property.name}}");
66        result->m_{{property.name}} = ValueConversions<{{protocol.resolve_type(property).raw_type}}>::fromValue({{property.name}}Value, errors);
67    }
68      {% else %}
69    errors->setName("{{property.name}}");
70    result->m_{{property.name}} = ValueConversions<{{protocol.resolve_type(property).raw_type}}>::fromValue({{property.name}}Value, errors);
71      {% endif %}
72    {% endfor %}
73    errors->pop();
74    if (errors->hasErrors())
75        return nullptr;
76    return result;
77}
78
79std::unique_ptr<protocol::DictionaryValue> {{type.id}}::toValue() const
80{
81    std::unique_ptr<protocol::DictionaryValue> result = DictionaryValue::create();
82    {% for property in type.properties %}
83      {% set property_type = protocol.resolve_type(property) %}
84      {% set property_field = "m_" + property.name %}
85      {% if property.optional %}
86    if ({{property_field}}.isJust())
87        result->setValue("{{property.name}}", ValueConversions<{{property_type.raw_type}}>::toValue({{property_field}}.fromJust()));
88      {% else %}
89    result->setValue("{{property.name}}", ValueConversions<{{property_type.raw_type}}>::toValue({{property_type.to_raw_type % property_field}}));
90      {% endif %}
91    {% endfor %}
92    return result;
93}
94
95std::unique_ptr<{{type.id}}> {{type.id}}::clone() const
96{
97    ErrorSupport errors;
98    return fromValue(toValue().get(), &errors);
99}
100    {% if protocol.is_exported(domain.domain, type.id) %}
101
102{{config.exported.string_out}} {{type.id}}::toJSONString() const
103{
104    String json = toValue()->serializeToJSON();
105    return {{config.exported.to_string_out % "json"}};
106}
107
108void {{type.id}}::writeBinary(std::vector<uint8_t>* out) const
109{
110    toValue()->writeBinary(out);
111}
112
113// static
114std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromJSONString(const {{config.exported.string_in}}& json)
115{
116    ErrorSupport errors;
117    std::unique_ptr<Value> value = StringUtil::parseJSON(json);
118    if (!value)
119        return nullptr;
120    return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors);
121}
122
123// static
124std::unique_ptr<API::{{type.id}}> API::{{type.id}}::fromBinary(const uint8_t* data, size_t length)
125{
126    ErrorSupport errors;
127    std::unique_ptr<Value> value = Value::parseBinary(data, length);
128    if (!value)
129        return nullptr;
130    return protocol::{{domain.domain}}::{{type.id}}::fromValue(value.get(), &errors);
131}
132
133    {% endif %}
134  {% endfor %}
135
136// ------------- Enum values from params.
137
138  {% for command in join_arrays(domain, ["commands", "events"]) %}
139    {% for param in join_arrays(command, ["parameters", "returns"]) %}
140      {% if "enum" in param %}
141
142namespace {{command.name | to_title_case}} {
143namespace {{param.name | to_title_case}}Enum {
144        {% for literal in param.enum %}
145const char* {{ literal | to_title_case}} = "{{literal}}";
146        {% endfor %}
147} // namespace {{param.name | to_title_case}}Enum
148} // namespace {{command.name | to_title_case }}
149        {% if protocol.is_exported(domain.domain, command.name + "." + param.name) %}
150
151namespace API {
152namespace {{command.name | to_title_case}} {
153namespace {{param.name | to_title_case}}Enum {
154        {% for literal in param.enum %}
155const char* {{ literal | to_title_case}} = "{{literal}}";
156        {% endfor %}
157} // namespace {{param.name | to_title_case}}Enum
158} // namespace {{command.name | to_title_case }}
159} // namespace API
160        {% endif %}
161      {% endif %}
162    {% endfor %}
163  {% endfor %}
164
165// ------------- Frontend notifications.
166  {% for event in domain.events %}
167    {% if not protocol.generate_event(domain.domain, event.name) %}{% continue %}{% endif %}
168
169void Frontend::{{event.name | to_method_case}}(
170    {%- for parameter in event.parameters %}
171      {% if "optional" in parameter -%}
172        Maybe<{{protocol.resolve_type(parameter).raw_type}}>
173      {%- else -%}
174        {{protocol.resolve_type(parameter).pass_type}}
175      {%- endif %} {{parameter.name}}{%- if not loop.last -%}, {% endif -%}
176    {% endfor -%})
177{
178    if (!m_frontendChannel)
179        return;
180      {% if event.parameters %}
181    std::unique_ptr<{{event.name | to_title_case}}Notification> messageData = {{event.name | to_title_case}}Notification::{{"create" | to_method_case}}()
182        {% for parameter in event.parameters %}
183          {% if not "optional" in parameter %}
184        .{{"set" | to_method_case}}{{parameter.name | to_title_case}}({{protocol.resolve_type(parameter).to_pass_type % parameter.name}})
185          {% endif %}
186        {% endfor %}
187        .{{ "build" | to_method_case }}();
188        {% for parameter in event.parameters %}
189          {% if "optional" in parameter %}
190    if ({{parameter.name}}.isJust())
191        messageData->{{"set" | to_method_case}}{{parameter.name | to_title_case}}(std::move({{parameter.name}}).takeJust());
192          {% endif %}
193        {% endfor %}
194    m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}", std::move(messageData)));
195      {% else %}
196    m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("{{domain.domain}}.{{event.name}}"));
197      {% endif %}
198}
199  {% endfor %}
200
201void Frontend::flush()
202{
203    m_frontendChannel->flushProtocolNotifications();
204}
205
206void Frontend::sendRawJSONNotification(String notification)
207{
208    m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromJSON(std::move(notification)));
209}
210
211void Frontend::sendRawCBORNotification(std::vector<uint8_t> notification)
212{
213    m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromBinary(std::move(notification)));
214}
215
216// --------------------- Dispatcher.
217
218class DispatcherImpl : public protocol::DispatcherBase {
219public:
220    DispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
221        : DispatcherBase(frontendChannel)
222        , m_backend(backend) {
223  {% for command in domain.commands %}
224    {% if "redirect" in command %}
225      m_redirects["{{domain.domain}}.{{command.name}}"] = "{{command.redirect}}.{{command.name}}";
226      {% continue %}
227    {% endif %}
228    {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
229        m_dispatchMap["{{domain.domain}}.{{command.name}}"] = &DispatcherImpl::{{command.name}};
230  {% endfor %}
231    }
232    ~DispatcherImpl() override { }
233    bool canDispatch(const String& method) override;
234    void dispatch(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<protocol::DictionaryValue> messageObject) override;
235    std::unordered_map<String, String>& redirects() { return m_redirects; }
236
237protected:
238    using CallHandler = void (DispatcherImpl::*)(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<DictionaryValue> messageObject, ErrorSupport* errors);
239    using DispatchMap = std::unordered_map<String, CallHandler>;
240    DispatchMap m_dispatchMap;
241    std::unordered_map<String, String> m_redirects;
242
243  {% for command in domain.commands %}
244    {% if "redirect" in command %}{% continue %}{% endif %}
245    {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
246    void {{command.name}}(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport*);
247  {% endfor %}
248
249    Backend* m_backend;
250};
251
252bool DispatcherImpl::canDispatch(const String& method) {
253    return m_dispatchMap.find(method) != m_dispatchMap.end();
254}
255
256void DispatcherImpl::dispatch(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<protocol::DictionaryValue> messageObject)
257{
258    std::unordered_map<String, CallHandler>::iterator it = m_dispatchMap.find(method);
259    DCHECK(it != m_dispatchMap.end());
260    protocol::ErrorSupport errors;
261    (this->*(it->second))(callId, method, message, std::move(messageObject), &errors);
262}
263
264  {% for command in domain.commands %}
265    {% set command_name_title = command.name | to_title_case %}
266    {% if "redirect" in command %}{% continue %}{% endif %}
267    {% if not protocol.generate_command(domain.domain, command.name) %}{% continue %}{% endif %}
268    {% if protocol.is_async_command(domain.domain, command.name) %}
269
270class {{command_name_title}}CallbackImpl : public Backend::{{command_name_title}}Callback, public DispatcherBase::Callback {
271public:
272    {{command_name_title}}CallbackImpl(std::unique_ptr<DispatcherBase::WeakPtr> backendImpl, int callId, const String& method, const ProtocolMessage& message)
273        : DispatcherBase::Callback(std::move(backendImpl), callId, method, message) { }
274
275    void sendSuccess(
276      {%- for parameter in command.returns -%}
277        {%- if "optional" in parameter -%}
278        Maybe<{{protocol.resolve_type(parameter).raw_type}}> {{parameter.name}}
279        {%- else -%}
280        {{protocol.resolve_type(parameter).pass_type}} {{parameter.name}}
281        {%- endif -%}
282        {%- if not loop.last -%}, {% endif -%}
283      {%- endfor -%}) override
284    {
285        std::unique_ptr<protocol::DictionaryValue> resultObject = DictionaryValue::create();
286          {% for parameter in command.returns %}
287            {% if "optional" in parameter %}
288        if ({{parameter.name}}.isJust())
289            resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{parameter.name}}.fromJust()));
290           {% else %}
291        resultObject->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % parameter.name}}));
292            {% endif %}
293          {% endfor %}
294        sendIfActive(std::move(resultObject), DispatchResponse::OK());
295    }
296
297    void fallThrough() override
298    {
299        fallThroughIfActive();
300    }
301
302    void sendFailure(const DispatchResponse& response) override
303    {
304        DCHECK(response.status() == DispatchResponse::kError);
305        sendIfActive(nullptr, response);
306    }
307};
308    {% endif %}
309
310void DispatcherImpl::{{command.name}}(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport* errors)
311{
312    {% if "parameters" in command %}
313    // Prepare input parameters.
314    protocol::DictionaryValue* object = DictionaryValue::cast(requestMessageObject->get("params"));
315    errors->push();
316      {% for parameter in command.parameters %}
317        {% set parameter_type = protocol.resolve_type(parameter) %}
318    protocol::Value* {{parameter.name}}Value = object ? object->get("{{parameter.name}}") : nullptr;
319        {% if parameter.optional %}
320    Maybe<{{parameter_type.raw_type}}> in_{{parameter.name}};
321    if ({{parameter.name}}Value) {
322        errors->setName("{{parameter.name}}");
323        in_{{parameter.name}} = ValueConversions<{{parameter_type.raw_type}}>::fromValue({{parameter.name}}Value, errors);
324    }
325        {% else %}
326    errors->setName("{{parameter.name}}");
327    {{parameter_type.type}} in_{{parameter.name}} = ValueConversions<{{parameter_type.raw_type}}>::fromValue({{parameter.name}}Value, errors);
328        {% endif %}
329      {% endfor %}
330    errors->pop();
331    if (errors->hasErrors()) {
332        reportProtocolError(callId, DispatchResponse::kInvalidParams, kInvalidParamsString, errors);
333        return;
334    }
335    {% endif %}
336    {% if "returns" in command and not protocol.is_async_command(domain.domain, command.name) %}
337    // Declare output parameters.
338      {% for parameter in command.returns %}
339        {% if "optional" in parameter %}
340    Maybe<{{protocol.resolve_type(parameter).raw_type}}> out_{{parameter.name}};
341        {% else %}
342    {{protocol.resolve_type(parameter).type}} out_{{parameter.name}};
343        {% endif %}
344      {% endfor %}
345    {% endif %}
346
347    {% if not protocol.is_async_command(domain.domain, command.name) %}
348    std::unique_ptr<DispatcherBase::WeakPtr> weak = weakPtr();
349    DispatchResponse response = m_backend->{{command.name | to_method_case}}(
350      {%- for parameter in command.parameters -%}
351        {%- if not loop.first -%}, {% endif -%}
352        {%- if "optional" in parameter -%}
353        std::move(in_{{parameter.name}})
354        {%- else -%}
355        {{protocol.resolve_type(parameter).to_pass_type % ("in_" + parameter.name)}}
356        {%- endif -%}
357      {%- endfor %}
358      {%- if "returns" in command %}
359        {%- for parameter in command.returns -%}
360          {%- if not loop.first or command.parameters -%}, {% endif -%}
361          &out_{{parameter.name}}
362        {%- endfor %}
363      {% endif %});
364    if (response.status() == DispatchResponse::kFallThrough) {
365        channel()->fallThrough(callId, method, message);
366        return;
367    }
368      {% if "returns" in command %}
369    std::unique_ptr<protocol::DictionaryValue> result = DictionaryValue::create();
370    if (response.status() == DispatchResponse::kSuccess) {
371        {% for parameter in command.returns %}
372          {% if "optional" in parameter %}
373        if (out_{{parameter.name}}.isJust())
374            result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue(out_{{parameter.name}}.fromJust()));
375          {% else %}
376        result->setValue("{{parameter.name}}", ValueConversions<{{protocol.resolve_type(parameter).raw_type}}>::toValue({{protocol.resolve_type(parameter).to_raw_type % ("out_" + parameter.name)}}));
377          {% endif %}
378        {% endfor %}
379    }
380    if (weak->get())
381        weak->get()->sendResponse(callId, response, std::move(result));
382      {% else %}
383    if (weak->get())
384        weak->get()->sendResponse(callId, response);
385      {% endif %}
386    return;
387    {% else %}
388    std::unique_ptr<DispatcherBase::WeakPtr> weak = weakPtr();
389    std::unique_ptr<{{command_name_title}}CallbackImpl> callback(new {{command.name | to_title_case}}CallbackImpl(weakPtr(), callId, method, message));
390    m_backend->{{command.name | to_method_case}}(
391      {%- for property in command.parameters -%}
392        {%- if not loop.first -%}, {% endif -%}
393        {%- if "optional" in property -%}
394        std::move(in_{{property.name}})
395        {%- else -%}
396        {{protocol.resolve_type(property).to_pass_type % ("in_" + property.name)}}
397        {%- endif -%}
398      {%- endfor -%}
399        {%- if command.parameters -%}, {% endif -%}
400        std::move(callback));
401    return;
402    {% endif %}
403}
404  {% endfor %}
405
406// static
407void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
408{
409    std::unique_ptr<DispatcherImpl> dispatcher(new DispatcherImpl(uber->channel(), backend));
410    uber->setupRedirects(dispatcher->redirects());
411    uber->registerBackend("{{domain.domain}}", std::move(dispatcher));
412}
413
414} // {{domain.domain}}
415{% for namespace in config.protocol.namespace %}
416} // namespace {{namespace}}
417{% endfor %}
418