diff options
-rw-r--r-- | .travis.yml | 45 | ||||
-rw-r--r-- | CMakeLists.txt | 25 | ||||
-rw-r--r-- | connection.cpp | 3 | ||||
-rw-r--r-- | jobs/basejob.cpp | 1 | ||||
-rw-r--r-- | jobs/generated/banning.cpp | 25 | ||||
-rw-r--r-- | jobs/generated/inviting.cpp | 11 | ||||
-rw-r--r-- | jobs/generated/kicking.cpp | 14 | ||||
-rw-r--r-- | jobs/generated/leaving.cpp | 6 | ||||
-rw-r--r-- | jobs/generated/logout.cpp | 3 | ||||
-rw-r--r-- | jobs/generated/profile.cpp | 33 | ||||
-rw-r--r-- | jobs/gtad.yaml | 62 | ||||
-rw-r--r-- | jobs/preamble.mustache | 3 | ||||
-rw-r--r-- | jobs/{{base}}.cpp.mustache | 76 | ||||
-rw-r--r-- | jobs/{{base}}.h.mustache | 47 |
14 files changed, 295 insertions, 59 deletions
diff --git a/.travis.yml b/.travis.yml index 313d1408..c4cd4326 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,43 @@ language: cpp + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - g++-5 + - clang-3.8 + - qt5-default + matrix: include: - - os: linux - dist: trusty - compiler: gcc - - os: linux - dist: trusty - compiler: clang - - os: osx + - os: linux + env: [ ENV_EVAL="CC=gcc-5 && CXX=g++-5" ] + - os: linux + env: [ ENV_EVAL="CC=clang-3.8 && CXX=clang++-3.8" ] + - os: osx + env: [ ENV_EVAL="brew update && brew install qt5 && CMAKE_PREFIX_PATH=/usr/local/opt/qt" ] + install: - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; else sudo apt-get update -qq; fi - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install qt5; export PATH="$PATH:/usr/local/opt/qt/bin"; else sudo apt-get install -y qt5-default; fi - - mkdir build && cd build - - cmake .. +- eval "${ENV_EVAL}" +- git clone https://github.com/QMatrixClient/matrix-doc.git +- git clone --recursive https://github.com/KitsuneRal/gtad.git +- pushd gtad +- cmake -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} . +- cmake --build . +- popd + +before_script: +- mkdir build && cd build +- cmake -DMATRIX_DOC_PATH="matrix-doc" -DGTAD_PATH="gtad/gtad" -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} .. +- cmake --build . --target update-api + script: - - cmake --build . --target all + - cmake --build . - cd .. - qmake qmc-example.pro && make all + notifications: webhooks: urls: diff --git a/CMakeLists.txt b/CMakeLists.txt index 29a5c811..2be54cb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,11 @@ if (CMAKE_BUILD_TYPE) endif(CMAKE_BUILD_TYPE) message( STATUS "Using compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}" ) message( STATUS "Using Qt ${Qt5_VERSION} at ${Qt5_Prefix}" ) +if (MATRIX_DOC_PATH AND GTAD_PATH) + message( STATUS "Generating API stubs enabled" ) + message( STATUS " Using GTAD at ${GTAD_PATH}" ) + message( STATUS " Using CS API files at ${MATRIX_DOC_PATH}/api/client-server" ) +endif () message( STATUS "=============================================================================" ) message( STATUS ) @@ -81,6 +86,26 @@ set(libqmatrixclient_SRCS jobs/mediathumbnailjob.cpp ) +set(API_DEF_PATH ${MATRIX_DOC_PATH}/api/client-server/) +file(GLOB_RECURSE API_DEFS RELATIVE ${PROJECT_SOURCE_DIR} + ${API_DEF_PATH}/*.yaml + ${API_DEF_PATH}/definitions/*.yaml + ${MATRIX_DOC_PATH}/event-schemas/schema/* +) +if (MATRIX_DOC_PATH AND GTAD_PATH) + add_custom_target(update-api + ${GTAD_PATH} --config jobs/gtad.yaml --out jobs/generated + ${MATRIX_DOC_PATH}/api/client-server + content-repo.yaml- cas_login_redirect.yaml- cas_login_ticket.yaml- + old_sync.yaml- room_initial_sync.yaml- + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + SOURCES jobs/gtad.yaml + jobs/{{base}}.h.mustache jobs/{{base}}.cpp.mustache + ${API_DEFS} + VERBATIM + ) +endif() + aux_source_directory(jobs/generated libqmatrixclient_job_SRCS) set(example_SRCS examples/qmc-example.cpp) diff --git a/connection.cpp b/connection.cpp index 78ef9754..d2641353 100644 --- a/connection.cpp +++ b/connection.cpp @@ -190,8 +190,7 @@ void Connection::Private::connectWithToken(const QString& user, data->setToken(accessToken.toLatin1()); data->setDeviceId(deviceId); qCDebug(MAIN) << "Using server" << data->baseUrl() << "by user" - << userId - << "from device" << deviceId; + << userId << "from device" << deviceId; emit q->connected(); } diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 9d5c5ed6..2f5c381a 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -25,7 +25,6 @@ #include <QtNetwork/QNetworkReply> #include <QtCore/QTimer> #include <QtCore/QRegularExpression> -//#include <QtCore/QStringBuilder> #include <array> diff --git a/jobs/generated/banning.cpp b/jobs/generated/banning.cpp index c47d3419..ebb4c96c 100644 --- a/jobs/generated/banning.cpp +++ b/jobs/generated/banning.cpp @@ -15,21 +15,24 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); BanJob::BanJob(QString roomId, QString user_id, QString reason) : BaseJob(HttpVerb::Post, "BanJob", basePath % "/rooms/" % roomId % "/ban", - Query { }, - Data { - { "user_id", toJson(user_id) }, - { "reason", toJson(reason) } - } + Query { } ) -{ } +{ + Data _data; + _data.insert("user_id", toJson(user_id)); + if (!reason.isEmpty()) + _data.insert("reason", toJson(reason)); + setRequestData(_data); +} UnbanJob::UnbanJob(QString roomId, QString user_id) : BaseJob(HttpVerb::Post, "UnbanJob", basePath % "/rooms/" % roomId % "/unban", - Query { }, - Data { - { "user_id", toJson(user_id) } - } + Query { } ) -{ } +{ + Data _data; + _data.insert("user_id", toJson(user_id)); + setRequestData(_data); +} diff --git a/jobs/generated/inviting.cpp b/jobs/generated/inviting.cpp index 11384c5e..73c73076 100644 --- a/jobs/generated/inviting.cpp +++ b/jobs/generated/inviting.cpp @@ -15,10 +15,11 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); InviteUserJob::InviteUserJob(QString roomId, QString user_id) : BaseJob(HttpVerb::Post, "InviteUserJob", basePath % "/rooms/" % roomId % "/invite", - Query { }, - Data { - { "user_id", toJson(user_id) } - } + Query { } ) -{ } +{ + Data _data; + _data.insert("user_id", toJson(user_id)); + setRequestData(_data); +} diff --git a/jobs/generated/kicking.cpp b/jobs/generated/kicking.cpp index e75b900a..28d51d05 100644 --- a/jobs/generated/kicking.cpp +++ b/jobs/generated/kicking.cpp @@ -15,11 +15,13 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); KickJob::KickJob(QString roomId, QString user_id, QString reason) : BaseJob(HttpVerb::Post, "KickJob", basePath % "/rooms/" % roomId % "/kick", - Query { }, - Data { - { "user_id", toJson(user_id) }, - { "reason", toJson(reason) } - } + Query { } ) -{ } +{ + Data _data; + _data.insert("user_id", toJson(user_id)); + if (!reason.isEmpty()) + _data.insert("reason", toJson(reason)); + setRequestData(_data); +} diff --git a/jobs/generated/leaving.cpp b/jobs/generated/leaving.cpp index e443612e..392f1ca8 100644 --- a/jobs/generated/leaving.cpp +++ b/jobs/generated/leaving.cpp @@ -15,16 +15,14 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); LeaveRoomJob::LeaveRoomJob(QString roomId) : BaseJob(HttpVerb::Post, "LeaveRoomJob", basePath % "/rooms/" % roomId % "/leave", - Query { }, - Data { } + Query { } ) { } ForgetRoomJob::ForgetRoomJob(QString roomId) : BaseJob(HttpVerb::Post, "ForgetRoomJob", basePath % "/rooms/" % roomId % "/forget", - Query { }, - Data { } + Query { } ) { } diff --git a/jobs/generated/logout.cpp b/jobs/generated/logout.cpp index a5848e7c..c2480ff9 100644 --- a/jobs/generated/logout.cpp +++ b/jobs/generated/logout.cpp @@ -15,8 +15,7 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); LogoutJob::LogoutJob() : BaseJob(HttpVerb::Post, "LogoutJob", basePath % "/logout", - Query { }, - Data { } + Query { } ) { } diff --git a/jobs/generated/profile.cpp b/jobs/generated/profile.cpp index 201bca79..f24db15a 100644 --- a/jobs/generated/profile.cpp +++ b/jobs/generated/profile.cpp @@ -15,12 +15,14 @@ static const auto basePath = QStringLiteral("/_matrix/client/r0"); SetDisplayNameJob::SetDisplayNameJob(QString userId, QString displayname) : BaseJob(HttpVerb::Put, "SetDisplayNameJob", basePath % "/profile/" % userId % "/displayname", - Query { }, - Data { - { "displayname", toJson(displayname) } - } + Query { } ) -{ } +{ + Data _data; + if (!displayname.isEmpty()) + _data.insert("displayname", toJson(displayname)); + setRequestData(_data); +} class GetDisplayNameJob::Private { @@ -32,8 +34,7 @@ class GetDisplayNameJob::Private GetDisplayNameJob::GetDisplayNameJob(QString userId) : BaseJob(HttpVerb::Get, "GetDisplayNameJob", basePath % "/profile/" % userId % "/displayname", - Query { }, - Data { } + Query { }, Data { }, false ), d(new Private) { } @@ -59,12 +60,14 @@ BaseJob::Status GetDisplayNameJob::parseJson(const QJsonDocument& data) SetAvatarUrlJob::SetAvatarUrlJob(QString userId, QString avatar_url) : BaseJob(HttpVerb::Put, "SetAvatarUrlJob", basePath % "/profile/" % userId % "/avatar_url", - Query { }, - Data { - { "avatar_url", toJson(avatar_url) } - } + Query { } ) -{ } +{ + Data _data; + if (!avatar_url.isEmpty()) + _data.insert("avatar_url", toJson(avatar_url)); + setRequestData(_data); +} class GetAvatarUrlJob::Private { @@ -76,8 +79,7 @@ class GetAvatarUrlJob::Private GetAvatarUrlJob::GetAvatarUrlJob(QString userId) : BaseJob(HttpVerb::Get, "GetAvatarUrlJob", basePath % "/profile/" % userId % "/avatar_url", - Query { }, - Data { } + Query { }, Data { }, false ), d(new Private) { } @@ -111,8 +113,7 @@ class GetUserProfileJob::Private GetUserProfileJob::GetUserProfileJob(QString userId) : BaseJob(HttpVerb::Get, "GetUserProfileJob", basePath % "/profile/" % userId, - Query { }, - Data { } + Query { }, Data { }, false ), d(new Private) { } diff --git a/jobs/gtad.yaml b/jobs/gtad.yaml new file mode 100644 index 00000000..4877aeb5 --- /dev/null +++ b/jobs/gtad.yaml @@ -0,0 +1,62 @@ +preprocess: + "%CLIENT_RELEASE_LABEL%": r0 + "%CLIENT_MAJOR_VERSION%": r0 + "unsigned:": "unsigned_:" + "default:": "default_:" + +# Structure: +# 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...> } +types: + integer: + - int64: qint64 + - int32: qint32 + - //: int + number: + - float: float + - //: double + boolean: bool + string: + - byte: &QByteArray + type: QByteArray + string?: true + imports: <QtCore/QByteArray> + - binary: *QByteArray + - date: + type: QDate + avoidCopy?: true + imports: <QtCore/QDate> + - dateTime: + type: QDateTime + avoidCopy?: true + imports: <QtCore/QDateTime> + - //: { type: QString, "string?": true, imports: <QtCore/QString> } + file: + type: QByteArray + imports: <QtCore/QByteArray> + "returnFile?": true + object: { type: QJsonObject, "avoidCopy?": true, imports: <QtCore/QJsonObject> } + array: { type: "QVector<{{1}}>", "avoidCopy?": true, imports: <QtCore/QVector> } + +#operations: + +env: +# preamble: preamble.mustache + copyrightName: Kitsune Ral + copyrightEmail: <kitsune-ral@users.sf.net> +# imports: { set: } +# returnFile?: { bool: false } + +templates: +- "{{base}}.h.mustache" +- "{{base}}.cpp.mustache" + +#outFilesList: apifiles.txt + diff --git a/jobs/preamble.mustache b/jobs/preamble.mustache new file mode 100644 index 00000000..3ba87d61 --- /dev/null +++ b/jobs/preamble.mustache @@ -0,0 +1,3 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ diff --git a/jobs/{{base}}.cpp.mustache b/jobs/{{base}}.cpp.mustache new file mode 100644 index 00000000..f3a6dc59 --- /dev/null +++ b/jobs/{{base}}.cpp.mustache @@ -0,0 +1,76 @@ +{{#@filePartial}}preamble{{/@filePartial}} + +#include "{{filenameBase}}.h" + +{{^models}}#include "jobs/converters.h"{{/models}} +{{#operations}}#include <QtCore/QStringBuilder>{{/operations}} + +using namespace QMatrixClient; +{{#models}}{{#model}} +{{classname}}::operator QJsonValue() const +{ + QJsonObject o; + {{#vars}}o.insert("{{name}}", toJson({{name}})); + {{/vars}} + return o; +} + +{{classname}} FromJson<{{classname}}>::operator()(QJsonValue jv) +{ + QJsonObject o = jv.toObject(); + {{classname}} result; + {{#vars}}result.{{name}} = fromJson<{{datatype}}>(o.value("{{name}}")); + {{/vars}} + return result; +} +{{/model}}{{/models}}{{#operations}} +static const auto basePath = QStringLiteral("{{basePathWithoutHost}}"); +{{# operation}}{{#responses}}{{#normalResponse?}}{{#properties?}} +class {{camelCaseOperationId}}Job::Private +{ + public: + {{#properties}}{{dataType}} {{paramName}}; + {{/properties}} +}; +{{/ properties?}}{{/normalResponse?}}{{/responses}} +{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job({{#allParams}}{{#avoidCopy?}}const {{dataType}}&{{/avoidCopy?}}{{^avoidCopy?}}{{dataType}}{{/avoidCopy?}} {{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + : BaseJob(HttpVerb::{{#@cap}}{{#@tolower}}{{httpMethod}}{{/@tolower}}{{/@cap}}, "{{camelCaseOperationId}}Job", + basePath{{#pathParts}} % {{part}}{{/pathParts}}, + Query {{^queryParams}}{ }{{/queryParams}}{{#queryParams?}}{ + {{#queryParams}}{ "{{baseName}}", toJson({{paramName}}).toString() }{{#hasMore}}, + {{/hasMore}}{{/queryParams}} + }{{/queryParams?}}{{#skipAuth}}, Data { }, false{{/skipAuth}} + ){{#responses}}{{#normalResponse?}}{{#properties?}}, d(new Private){{/properties?}}{{/normalResponse?}}{{/responses}} +{{#bodyParams?}}{ + Data _data;{{#bodyParams}} +{{^required?}}{{#string?}} if (!{{paramName}}.isEmpty()) + {{/string?}}{{/required?}} _data.insert("{{baseName}}", toJson({{paramName}}));{{/bodyParams}} + setRequestData(_data); +}{{/bodyParams?}}{{^bodyParams?}}{ }{{/bodyParams?}} +{{# responses}}{{#normalResponse?}}{{#properties?}} +{{camelCaseOperationId}}Job::~{{camelCaseOperationId}}Job() +{ + delete d; +} +{{# properties}} +const {{dataType}}& {{camelCaseOperationId}}Job::{{paramName}}() const +{ + return d->{{paramName}}; +} +{{/ properties}}{{#returnFile?}} +BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QByteArray data) +{ + {{#properties}}{{paramName}}{{/properties}} = data; + return Success; +}{{/ returnFile?}}{{^returnFile?}} +BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data) +{ + auto json = data.object(); + {{# properties}}{{#required?}}if (!json.contains("{{paramName}}")) + return { JsonParseError, + "The key '{{paramName}}' not found in the response" };{{/required?}} + d->{{paramName}} = fromJson<{{dataType}}>(json.value("{{paramName}}")); +{{/ properties}} + return Success; +}{{/ returnFile?}} +{{/properties?}}{{/normalResponse?}}{{/responses}}{{/operation}}{{/operations}} diff --git a/jobs/{{base}}.h.mustache b/jobs/{{base}}.h.mustache new file mode 100644 index 00000000..65c79e24 --- /dev/null +++ b/jobs/{{base}}.h.mustache @@ -0,0 +1,47 @@ +{{#@filePartial}}preamble{{/@filePartial}} + +#pragma once + +{{#operations}}#include "../basejob.h" +{{/operations}} +{{#imports}}#include {{.}} +{{/imports}} +{{#models}}#include "jobs/converters.h" +{{/models}} +namespace QMatrixClient +{ +{{#models}} // Data structures +{{# model}} + struct {{classname}}{{#parents?}} : {{#parents}}{{.}}{{#last?}}, {{/last?}}{{/parents}}{{/parents?}} + { + {{#vars}}{{datatype}} {{name}}; + {{/vars}} + operator QJsonValue() const; + }; + + template <> struct FromJson<{{classname}}> + { + {{classname}} operator()(QJsonValue jv); + }; +{{/ model}} +{{/models}} +{{#operations}} // Operations +{{# operation}} + class {{camelCaseOperationId}}Job : public BaseJob + { + public: + explicit {{camelCaseOperationId}}Job({{#allParams}}{{#avoidCopy?}}const {{dataType}}&{{/avoidCopy?}}{{^avoidCopy?}}{{dataType}}{{/avoidCopy?}} {{paramName}}{{^required?}} = {{defaultValue}}{{^defaultValue}}{}{{/defaultValue}}{{/required?}}{{#hasMore}}, {{/hasMore}}{{/allParams}}); +{{# responses}}{{#normalResponse?}}{{#properties?}} + ~{{camelCaseOperationId}}Job() override; + + {{#properties}}const {{dataType}}& {{paramName}}() const; + {{/properties}} + protected: + {{^returnFile}}Status parseJson(const QJsonDocument& data) override;{{/returnFile}} + {{#returnFile?}}Status parseReply(QByteArray data) override;{{/returnFile?}} + private: + class Private; + Private* d;{{/properties?}}{{/normalResponse?}}{{/responses}} + };{{/operation}} +{{/operations}} +} // namespace QMatrixClient |