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