aboutsummaryrefslogtreecommitdiff
path: root/gtad
diff options
context:
space:
mode:
Diffstat (limited to 'gtad')
-rw-r--r--gtad/data.h.mustache56
-rw-r--r--gtad/gtad.yaml243
-rw-r--r--gtad/operation.cpp.mustache59
-rw-r--r--gtad/operation.h.mustache128
-rw-r--r--gtad/preamble.mustache3
5 files changed, 489 insertions, 0 deletions
diff --git a/gtad/data.h.mustache b/gtad/data.h.mustache
new file mode 100644
index 00000000..1b511262
--- /dev/null
+++ b/gtad/data.h.mustache
@@ -0,0 +1,56 @@
+{{!
+SPDX-FileCopyrightText: 2020 Kitsune Ral <Kitsune-Ral@users.sf.net>
+SPDX-License-Identifier: LGPL-2.1-or-later
+}}{{>preamble}}
+#pragma once
+
+#include "converters.h"
+{{#imports}}
+#include {{_}}{{/imports}}
+
+namespace Quotient {
+{{#models}}
+ {{#model}}
+{{>docCommentShort}}
+struct {{name}}{{#parents?}} : {{#parents}}{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
+{ {{#vars}}
+
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/vars}}{{#propertyMap}}
+
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/propertyMap}}
+};
+
+template <> struct JsonObjectConverter<{{name}}>
+{
+ {{#in?}}
+ static void dumpTo(QJsonObject& jo, const {{name}}& pod)
+ { {{#propertyMap}}
+ fillJson(jo, pod.{{nameCamelCase}});
+ {{/propertyMap}}{{#parents}}
+ fillJson<{{name}}>(jo, pod);
+ {{/parents}}{{#vars}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo,
+ QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});
+ {{/vars}}
+ }
+ {{/in?}}
+ {{#out?}}
+ static void fillFrom({{>maybeCrefJsonObject}} jo, {{name}}& pod)
+ { {{#parents}}
+ fillFromJson<{{qualifiedName}}>(jo, pod);
+ {{/parents}}{{#vars}}
+ fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls), pod.{{nameCamelCase}});
+ {{/vars}}{{#propertyMap}}
+ fromJson(jo, pod.{{nameCamelCase}});
+ {{/propertyMap}}
+ }
+ {{/out?}}
+};
+
+ {{/model}}
+{{/models}}
+} // namespace Quotient
diff --git a/gtad/gtad.yaml b/gtad/gtad.yaml
new file mode 100644
index 00000000..4b05d2d4
--- /dev/null
+++ b/gtad/gtad.yaml
@@ -0,0 +1,243 @@
+analyzer:
+ subst:
+ "%CLIENT_RELEASE_LABEL%": r0
+ "%CLIENT_MAJOR_VERSION%": r0
+ identifiers:
+ signed: signedData
+ unsigned: unsignedData
+ PushRule/default: isDefault
+ default: defaultVersion # getCapabilities/RoomVersionsCapability
+ origin_server_ts: originServerTimestamp # Instead of originServerTs
+ start: begin # Because start() is a method in BaseJob
+ m.upload.size: uploadSize
+ m.homeserver: homeserver
+ m.identity_server: identityServer
+ m.change_password: changePassword
+ m.room_versions: roomVersions
+ AuthenticationData/additionalProperties: authInfo
+ /^/(Location|Protocol|User)$/: 'ThirdParty$1'
+ # Change some response names
+ /requestTokenTo.*</data/: response
+ requestOpenIdToken</data: tokenData
+ getDevice</data: device
+ getFilter</data: filter
+ getProtocols</data: protocols
+ getOneRoomEvent</data: event
+ getRoomState</data: events
+ getPushRule</data: pushRule
+ # These parameters are deprecated and unused in Quotient; so drop them
+ login>/user: ""
+ login>/medium: ""
+ login>/address: ""
+ login</home_server: ""
+ register</home_server: ""
+
+ # Structure inside `types`:
+ # - swaggerType: <targetTypeSpec>
+ # OR
+ # - swaggerType:
+ # - swaggerFormat: <targetTypeSpec>
+ # - /swaggerFormatRegEx/: <targetTypeSpec>
+ # - //: <targetTypeSpec> # default, if the format doesn't mach anything above
+ # WHERE
+ # targetTypeSpec = targetType OR
+ # { type: targetType, imports: <filename OR [ filenames... ]>, <other attributes...> }
+ # swaggerType can be +set/+on pair; attributes from the map under +set
+ # are added to each type from the sequence under +on.
+ types:
+ - +set: &UseOmittable
+ useOmittable:
+ omittedValue: 'none' # Quotient::none in lib/omittable.h
+ +on:
+ - integer:
+ - int64: qint64
+ - int32: qint32
+ - //: int
+ - number:
+ - float: float
+ - //: double
+ - boolean: bool
+ - string:
+ - byte: &ByteStream
+ type: QIODevice*
+ imports: <QtCore/QIODevice>
+ - binary: *ByteStream
+ - +set: { avoidCopy: }
+ +on:
+ - date:
+ type: QDate
+ initializer: QDate::fromString("{{defaultValue}}")
+ - dateTime:
+ type: QDateTime
+ initializer: QDateTime::fromString("{{defaultValue}}")
+ - uri:
+ type: QUrl
+ initializer: QUrl::fromEncoded("{{defaultValue}}")
+ - //: &QString
+ type: QString
+ initializer: QStringLiteral("{{defaultValue}}")
+ isString:
+ - file: *ByteStream
+ - +set: { avoidCopy: }
+ +on:
+ - object: &QJsonObject { type: QJsonObject }
+ - $ref:
+ - +set:
+ moveOnly:
+ +on:
+ - /state_event.yaml$/:
+ type: StateEventPtr
+ imports: '"events/stateevent.h"'
+ - /(room|client)_event.yaml$/:
+ type: RoomEventPtr
+ imports: '"events/roomevent.h"'
+ - /event(_without_room_id)?.yaml$/:
+ type: EventPtr
+ imports: '"events/event.h"'
+ - +set:
+ # This renderer applies to everything actually $ref'ed
+ # (not substituted)
+ _importRenderer: '"{{#segments}}{{_}}{{#_join}}/{{/_join}}{{/segments}}.h"'
+ +on:
+ - '/^(\./)?definitions/request_email_validation.yaml$/':
+ title: EmailValidationData
+ - '/^(\./)?definitions/request_msisdn_validation.yaml$/':
+ title: MsisdnValidationData
+ - /_filter.yaml$/: # Event/RoomEventFilters do NOT need Omittable<>
+
+ # Despite being used in two calls, it's more practical to have those
+ # fields available as getters right from the respective job classes
+ - /public_rooms_response.yaml$/: { _inline: true }
+
+ # list_public_rooms.yaml (via public_rooms_response.yaml) and
+ # space_hierarchy.yaml use public_rooms_chunk.yaml as a common base
+ # structure, adding (space_hiearchy) or overriding
+ # (public_rooms_response) fields for their purposes. The spec text
+ # confusingly ends up with having two different structures named
+ # "PublicRoomsChunk". To make sure the types are distinct in
+ # libQuotient, this common base is inlined into the actually used
+ # data structures (that have distinct names) defined
+ # in space_hierarchy.h and public_rooms_response.h, respectively
+ - /public_rooms_chunk.yaml$/: { _inline: true }
+ - //: *UseOmittable # Also apply "avoidCopy" to all other ref'ed types
+ - schema:
+ - getTurnServer<: *QJsonObject # It's used as an opaque JSON object
+# - defineFilter>: &Filter # Force folding into a structure
+# type: Filter
+# imports: '"csapi/definitions/sync_filter.h"'
+# - getFilter<: *Filter
+ - StrippedChildStateEvent: void # only used in an array, see below
+ - RoomFilter: # A structure inside Filter, same story as with *_filter.yaml
+ - OneTimeKeys:
+ type: OneTimeKeys
+ imports: '"e2ee/e2ee.h"'
+ - //: *UseOmittable
+ - array:
+ - string: QStringList
+ - +set: { moveOnly: }
+ +on:
+ - /^Notification|Result|ChildRoomsChunk$/: "std::vector<{{1}}>"
+ - /^StrippedChildStateEvent$|state_event.yaml$/:
+ type: StateEvents
+ imports: '"events/stateevent.h"' # For StrippedChildStateEvent
+ - /(room|client)_event.yaml$/: RoomEvents
+ - /event(_without_room_id)?.yaml$/: Events
+ - //: "QVector<{{1}}>"
+ - map: # `additionalProperties` in OpenAPI
+ - RoomState:
+ type: "UnorderedMap<QString, {{1}}>"
+ moveOnly:
+ - /.+/: "QHash<QString, {{1}}>"
+ - //: QVariantHash # QJsonObject?..
+ - variant: # A sequence `type` or a 'oneOf' group in OpenAPI
+ - /^string,null|null,string$/: *QString
+ - //: QVariant
+
+ #operations:
+
+mustache:
+# delimiter: '%| |%' # or something else instead of '{{ }}'
+ constants:
+ # Syntax elements used by GTAD
+# _quote: '"' # Common quote for left and right
+# _leftQuote: '"'
+# _rightQuote: '"_ls'
+ _comment: '//'
+ copyrightName: Kitsune Ral
+ copyrightEmail: <kitsune-ral@users.sf.net>
+
+ partials:
+ _typeRenderer: "{{#scope}}{{scopeCamelCase}}Job::{{/scope}}{{>name}}"
+ omittedValue: '{}' # default value to initialize omitted parameters with
+ initializer: '{{defaultValue}}'
+ cjoin: '{{#hasMore}}, {{/hasMore}}'
+
+ openOmittable:
+ "{{^required?}}{{#useOmittable}}\
+ {{^defaultValue}}Omittable<{{/defaultValue}}\
+ {{/useOmittable}}{{/required?}}"
+ closeOmittable:
+ "{{^required?}}{{#useOmittable}}\
+ {{^defaultValue}}>{{/defaultValue}}\
+ {{/useOmittable}}{{/required?}}"
+
+ maybeOmittableType: "{{>openOmittable}}{{dataType.name}}{{>closeOmittable}}"
+ qualifiedMaybeOmittableType:
+ "{{>openOmittable}}{{dataType.qualifiedName}}{{>closeOmittable}}"
+
+ maybeCrefType:
+ "{{#avoidCopy}}const {{/avoidCopy}}{{>maybeOmittableType}}{{#avoidCopy}}&{{/avoidCopy}}"
+
+ maybeCrefJsonObject:
+ "{{^propertyMap}}const QJsonObject&{{/propertyMap}}\
+ {{#propertyMap}}QJsonObject{{/propertyMap}}"
+
+ takeOrValue:
+ "{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}"
+ takeOrLoad: "{{#moveOnly}}take{{/moveOnly}}{{^moveOnly}}load{{/moveOnly}}"
+
+ initializeDefaultValue:
+ "{{#defaultValue}}{{>initializer}}{{/defaultValue}}\
+ {{^defaultValue}}{{>omittedValue}}{{/defaultValue}}"
+
+ # No inner indents in folded values!
+
+ joinedParamDecl: >-
+ {{>maybeCrefType}} {{paramName}}
+ {{^required?}} = {{>initializeDefaultValue}}{{/required?}}{{>cjoin}}
+ joinedParamDef: "{{>maybeCrefType}} {{paramName}}{{>cjoin}}"
+
+ passPathAndMaybeQuery: >-
+ makePath("{{basePathWithoutHost}}"{{#pathParts}},
+ {{_}}{{/pathParts}}){{#queryParams?}},
+ queryTo{{camelCaseOperationId}}(
+ {{#queryParams}}{{paramName}}{{>cjoin}}{{/queryParams}}){{/queryParams?}}
+
+ nonInlineResponseSignature: |-
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{paramName}}(){{^moveOnly}} const{{/moveOnly}}
+
+ # Doc-comment blocks. Comment indent is managed by clang-format
+ # (without clang-format there'd have to be a separate partial definition
+ # for each indent...) but we take care of line breaks to maintain
+ # some sanity even before clang-format
+
+ # This is for structures that don't expect a summary (e.g., JSON schema)
+ docCommentShort: |-
+ {{#description}}
+ /// {{_}}{{/description}}
+ # For structures with the summary, a common partial for summary is here;
+ # the main part is different in different places
+ docCommentSummary: |-
+ {{#summary}} \brief {{summary}}
+ *{{/summary}}
+
+ templates:
+ data:
+ .h: "{{>data.h.mustache}}"
+ api:
+ .h: "{{>operation.h.mustache}}"
+ .cpp: "{{>operation.cpp.mustache}}"
+
+ #outFilesList: apifiles.txt
+
diff --git a/gtad/operation.cpp.mustache b/gtad/operation.cpp.mustache
new file mode 100644
index 00000000..4b75434c
--- /dev/null
+++ b/gtad/operation.cpp.mustache
@@ -0,0 +1,59 @@
+{{!
+SPDX-FileCopyrightText: 2020 Kitsune Ral <Kitsune-Ral@users.sf.net>
+SPDX-License-Identifier: LGPL-2.1-or-later
+}}{{>preamble}}
+#include "{{filenameBase}}.h"
+
+using namespace Quotient;
+{{#operations}}{{#operation}}
+ {{#queryParams?}}
+
+auto queryTo{{camelCaseOperationId}}(
+ {{#queryParams}}{{>joinedParamDef}}{{/queryParams}})
+{
+ QUrlQuery _q;{{#queryParams}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q,
+ QStringLiteral("{{baseName}}"), {{paramName}});{{/queryParams}}
+ return _q;
+}
+ {{/queryParams?}}
+ {{^hasBody?}}
+
+QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}},
+ {{#allParams}}{{>joinedParamDef}}{{/allParams}}{{/allParams?}})
+{
+ return BaseJob::makeRequestUrl(std::move(baseUrl), {{>passPathAndMaybeQuery}});
+} {{/hasBody?}}
+
+{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job(
+ {{#allParams}}{{>joinedParamDef}}{{/allParams}})
+ : BaseJob(HttpVerb::{{#_cap}}{{#_tolower}}{{httpMethod}}{{/_tolower}}{{/_cap}},
+ {{!object name}}QStringLiteral("{{camelCaseOperationId}}Job"),
+ {{>passPathAndMaybeQuery}}
+ {{#skipAuth}}{{#queryParams?}}, {}{{/queryParams?}}, false{{/skipAuth}} )
+{ {{#headerParams}}
+ setRequestHeader("{{baseName}}", {{paramName}}.toLatin1());
+ {{/headerParams}}{{#inlineBody}}{{^propertyMap}}{{^bodyParams?}}
+ setRequestData({ {{#consumesNonJson?}}{{nameCamelCase}}{{/consumesNonJson?
+ }}{{^consumesNonJson?}}toJson({{nameCamelCase}}){{/consumesNonJson?}} });
+ {{/bodyParams?}}{{/propertyMap}}{{/inlineBody
+ }}{{^consumesNonJson?}}{{#bodyParams?}}
+ QJsonObject _dataJson;
+ {{#propertyMap}}
+ fillJson(_dataJson, {{nameCamelCase}});
+ {{/propertyMap}}{{#inlineBody}}
+ fillJson<{{>maybeOmittableType}}>(_dataJson, {{paramName}});
+ {{/inlineBody}}{{#bodyParams}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(_dataJson,
+ QStringLiteral("{{baseName}}"), {{paramName}});
+ {{/bodyParams}}
+ setRequestData({ _dataJson });
+ {{/bodyParams?}}{{/consumesNonJson?}}{{#producesNonJson?}}
+ setExpectedContentTypes({ {{#produces}}"{{_}}"{{>cjoin}}{{/produces}} });
+ {{/producesNonJson?}}{{^producesNonJson?
+ }}{{#responses}}{{#normalResponse?}}{{#properties}}{{#required?}}
+ addExpectedKey("{{baseName}}");
+ {{/required?}}{{/properties}}{{/normalResponse?}}{{/responses
+ }}{{/producesNonJson?}}
+}
+{{/operation}}{{/operations}}
diff --git a/gtad/operation.h.mustache b/gtad/operation.h.mustache
new file mode 100644
index 00000000..063f0bbd
--- /dev/null
+++ b/gtad/operation.h.mustache
@@ -0,0 +1,128 @@
+{{!
+SPDX-FileCopyrightText: 2020 Kitsune Ral <Kitsune-Ral@users.sf.net>
+SPDX-License-Identifier: LGPL-2.1-or-later
+}}{{>preamble}}
+#pragma once
+
+#include "jobs/basejob.h"
+{{#imports}}
+#include {{_}}{{/imports}}
+{{#operations.producesNonJson?}}
+#include <QtNetwork/QNetworkReply>{{/operations.producesNonJson?}}
+
+namespace Quotient {
+{{#operations.operation}}
+
+/*!{{>docCommentSummary}}{{#description}}
+ * {{_}}{{/description}}
+ */
+class QUOTIENT_API {{camelCaseOperationId}}Job : public BaseJob {
+public:
+ {{#models}}
+ // Inner data structures
+ {{#model}}
+
+ {{>docCommentShort}}
+ struct {{name}}{{#parents?}} :
+ {{#parents}}{{name}}{{>cjoin}}{{/parents}}{{/parents?}}
+ {
+ {{#vars}}
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/vars}}
+ {{#propertyMap}}
+ {{>docCommentShort}}
+ {{>maybeOmittableType}} {{nameCamelCase}};
+ {{/propertyMap}}
+ };
+ {{/model}}
+
+ // Construction/destruction
+
+ {{/models}}
+ {{#allParams?}}
+ /*!{{>docCommentSummary}}
+ {{#allParams}}
+ * \param {{nameCamelCase}}{{#description}}
+ * {{_}}{{/description}}{{#_join}}
+ * {{/_join}}
+ {{/allParams}}
+ */
+ {{/allParams?}}{{^allParams?}}
+ {{#summary}}
+ /// {{summary}}
+ {{/summary}}
+ {{/allParams?}}
+ explicit {{camelCaseOperationId}}Job({{#allParams}}{{>joinedParamDecl}}{{/allParams}});
+ {{^hasBody?}}
+
+ /*! \brief Construct a URL without creating a full-fledged job object
+ *
+ * This function can be used when a URL for {{camelCaseOperationId}}Job
+ * is necessary but the job itself isn't.
+ */
+ static QUrl makeRequestUrl(QUrl baseUrl{{#allParams?}},
+ {{#allParams}}{{>joinedParamDecl}}{{/allParams}}{{/allParams?}});
+ {{/hasBody?}}
+ {{#responses}}{{#normalResponse?}}{{#allProperties?}}
+
+ // Result properties
+ {{#headers}}
+
+ {{>nonInlineResponseSignature}}
+ {
+ return reply()->rawHeader("{{baseName}}");
+ }
+ {{/headers}}{{#inlineResponse}}
+
+ {{>docCommentShort}}
+ {{dataType.name}} {{paramName}}()
+ {{^moveOnly}}{{^producesNonJson?}} const{{/producesNonJson?}}{{/moveOnly}}
+ {
+ return {{#producesNonJson?}}reply(){{/producesNonJson?}}
+ {{^producesNonJson?
+ }}fromJson<{{dataType.name}}>(jsonData()){{/producesNonJson?
+ }};
+ }
+ {{/inlineResponse}}{{#properties}}
+
+ {{!there's nothing in #properties if the response is inline}}
+ {{>nonInlineResponseSignature}}
+ {
+ return {{>takeOrLoad}}FromJson<{{>maybeOmittableType}}>("{{baseName}}"_ls);
+ }
+ {{/properties}}
+ {{/allProperties?}}{{/normalResponse?}}{{/responses}}
+};
+ {{#models.model}}
+
+template <> struct JsonObjectConverter<{{qualifiedName}}> {
+ {{#in?}}
+ static void dumpTo(QJsonObject& jo, const {{qualifiedName}}& pod)
+ { {{#propertyMap}}
+ fillJson(jo, pod.{{nameCamelCase}});
+ {{/propertyMap}}{{#parents}}
+ fillJson<{{name}}>(jo, pod);
+ {{/parents}}{{#vars}}
+ addParam<{{^required?}}IfNotEmpty{{/required?}}>(jo,
+ QStringLiteral("{{baseName}}"), pod.{{nameCamelCase}});
+ {{/vars}}
+ }
+ {{/in?}}
+ {{#out?}}
+ static void fillFrom({{>maybeCrefJsonObject}} jo, {{qualifiedName}}& result)
+ { {{#parents}}
+ fillFromJson<{{name}}{{!of the parent!}}>(jo, result);
+ {{/parents}}{{#vars}}
+ fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls),
+ result.{{nameCamelCase}});
+ {{/vars}}{{#propertyMap}}
+ fromJson(jo, result.{{nameCamelCase}});
+ {{/propertyMap}}
+ }
+ {{/out?}}
+};
+ {{/models.model}}
+{{/operations.operation}}
+
+} // namespace Quotient
diff --git a/gtad/preamble.mustache b/gtad/preamble.mustache
new file mode 100644
index 00000000..3ba87d61
--- /dev/null
+++ b/gtad/preamble.mustache
@@ -0,0 +1,3 @@
+/******************************************************************************
+ * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN
+ */