aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml17
-rw-r--r--CMakeLists.txt58
-rw-r--r--connection.cpp3
-rw-r--r--converters.h4
-rw-r--r--jobs/basejob.cpp1
-rw-r--r--jobs/gtad.yaml79
-rw-r--r--jobs/preamble.mustache3
-rw-r--r--jobs/{{base}}.cpp.mustache101
-rw-r--r--jobs/{{base}}.h.mustache61
9 files changed, 294 insertions, 33 deletions
diff --git a/.travis.yml b/.travis.yml
index f033f3dd..6c08b428 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,13 +16,24 @@ addons:
matrix:
exclude: [ { os: osx, compiler: gcc } ]
-install:
+before_install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install qt5; export PATH="$PATH:/usr/local/opt/qt/bin"; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then . /opt/qt56/bin/qt56-env.sh; fi
-script:
+install:
+- 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 ..
+- 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
- cd ..
- qmake qmc-example.pro && make all
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e33c4e0e..0ead9ec8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,29 +20,16 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif()
# Setup command line parameters for the compiler and linker
-CHECK_CXX_COMPILER_FLAG("-Wall" WALL_FLAG_SUPPORTED)
-if ( WALL_FLAG_SUPPORTED AND NOT CMAKE_CXX_FLAGS MATCHES "(^| )-Wall($| )")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
-endif ( )
-CHECK_CXX_COMPILER_FLAG("-Wpedantic" PEDANTIC_FLAG_SUPPORTED)
-if ( PEDANTIC_FLAG_SUPPORTED AND NOT CMAKE_CXX_FLAGS MATCHES "(^| )pedantic($| )")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
-endif ( )
-CHECK_CXX_COMPILER_FLAG("-Werror=return-type" WERROR_FLAG_SUPPORTED)
-if ( WERROR_FLAG_SUPPORTED )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type")
-endif ( )
-
-if ( CMAKE_VERSION VERSION_LESS "3.1" )
- CHECK_CXX_COMPILER_FLAG("-std=c++11" STD_FLAG_SUPPORTED)
- if ( STD_FLAG_SUPPORTED )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
- endif ( STD_FLAG_SUPPORTED )
-else ( CMAKE_VERSION VERSION_LESS "3.1" )
- set(CMAKE_CXX_STANDARD 11)
-endif ( CMAKE_VERSION VERSION_LESS "3.1" )
-
-find_package(Qt5 5.2.1 REQUIRED Network Gui)
+foreach (FLAG all pedantic error=return-type)
+ CHECK_CXX_COMPILER_FLAG("-W${FLAG}" WARN_${FLAG}_SUPPORTED)
+ if ( WARN_${FLAG}_SUPPORTED AND NOT CMAKE_CXX_FLAGS MATCHES "(^| )-W?${FLAG}($| )")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W${FLAG}")
+ endif ( )
+endforeach ()
+
+set(CMAKE_CXX_STANDARD 14)
+
+find_package(Qt5 5.6 REQUIRED Network Gui)
get_filename_component(Qt5_Prefix "${Qt5_DIR}/../../../.." ABSOLUTE)
message( STATUS )
@@ -54,6 +41,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 )
@@ -83,6 +75,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
+ 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 b6239762..1f554974 100644
--- a/connection.cpp
+++ b/connection.cpp
@@ -189,8 +189,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/converters.h b/converters.h
index 00d1d339..0d7f734e 100644
--- a/converters.h
+++ b/converters.h
@@ -46,11 +46,7 @@ namespace QMatrixClient
inline QJsonValue toJson(const QByteArray& bytes)
{
-#if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
- return QJsonValue(QLatin1String(bytes.constData()));
-#else
return QJsonValue(bytes.constData());
-#endif
}
template <typename T>
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/gtad.yaml b/jobs/gtad.yaml
new file mode 100644
index 00000000..a19415a6
--- /dev/null
+++ b/jobs/gtad.yaml
@@ -0,0 +1,79 @@
+preprocess:
+ "%CLIENT_RELEASE_LABEL%": r0
+ "%CLIENT_MAJOR_VERSION%": r0
+ # FIXME: the below only fixes C++ compilation but not actual work - the code
+ # will try to reach out for wrong values in JSON payloads
+ "signed:": "signedData:"
+ "unsigned:": "unsignedData:"
+ "default:": "isDefault:"
+
+# 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
+ avoidCopy?: 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>
+ - //: { type: QJsonArray, "avoidCopy?": true, imports: <QtCore/QJsonArray> }
+ schema:
+ avoidCopy?: true
+
+#operations:
+
+env:
+ _typeRenderer: "{{#scope}}{{scopeCamelCase}}Job::{{/scope}}{{name}}"
+ maybeCrefType: "{{#avoidCopy?}}const {{/avoidCopy?}}{{dataType.name}}{{#avoidCopy?}}&{{/avoidCopy?}}"
+ qualifiedMaybeCrefType: "{{#avoidCopy?}}const {{/avoidCopy?}}{{dataType.qualifiedName}}{{#avoidCopy?}}&{{/avoidCopy?}}"
+# 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..b303c053
--- /dev/null
+++ b/jobs/{{base}}.cpp.mustache
@@ -0,0 +1,101 @@
+{{#@filePartial}}preamble{{/@filePartial}}
+
+#include "{{filenameBase}}.h"
+
+#include "converters.h"
+{{#operations}}
+#include <QtCore/QStringBuilder>
+{{/operations}}
+using namespace QMatrixClient;
+{{#models.model}}{{^trivial?}}
+{{qualifiedName}}::operator QJsonValue() const
+{
+ QJsonObject o;
+ {{#vars}}o.insert("{{baseName}}", toJson({{nameCamelCase}}));
+ {{/vars}}
+ return o;
+}
+
+{{qualifiedName}} FromJson<{{qualifiedName}}>::operator()(QJsonValue jv)
+{
+ QJsonObject o = jv.toObject();
+ {{qualifiedName}} result;
+ {{#vars}}result.{{nameCamelCase}} =
+ fromJson<{{dataType.name}}>(o.value("{{baseName}}"));
+ {{/vars}}
+ return result;
+}
+{{/trivial?}}{{/models.model}}{{#operations}}
+static const auto basePath = QStringLiteral("{{basePathWithoutHost}}");
+{{# operation}}{{#models.model}}{{^trivial?}}
+{{qualifiedName}}::operator QJsonObject() const
+{
+ QJsonObject o;
+ {{#vars}}o.insert("{{baseName}}", toJson({{nameCamelCase}}));
+ {{/vars}}
+ return o;
+}
+namespace QMatrixClient
+{
+ template <> struct FromJson<{{qualifiedName}}>
+ {
+ {{qualifiedName}} operator()(QJsonValue jv)
+ {
+ QJsonObject o = jv.toObject();
+ {{qualifiedName}} result;
+ {{#vars}}result.{{nameCamelCase}} =
+ fromJson<{{dataType.qualifiedName}}>(o.value("{{baseName}}"));
+ {{/vars}}
+ return result;
+ }
+ };
+} // namespace QMatrixClient
+{{/ trivial?}}{{/models.model}}{{#responses}}{{#normalResponse?}}{{#properties?}}
+class {{camelCaseOperationId}}Job::Private
+{
+ public:
+ {{#properties}}{{dataType.name}} {{paramName}};{{#@join}}{{!EOL except the last line}}
+ {{/@join}}{{/properties}}
+};
+{{/ properties?}}{{/normalResponse?}}{{/responses}}
+{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job({{#allParams}}{{>maybeCrefType}} {{paramName}}{{#@join}}, {{/@join}}{{/allParams}})
+ : BaseJob(HttpVerb::{{#@cap}}{{#@tolower}}{{httpMethod}}{{/@tolower}}{{/@cap}}, "{{camelCaseOperationId}}Job",
+ basePath{{#pathParts}} % {{_}}{{/pathParts}},
+ Query {{^queryParams}}{ }{{/queryParams}}{{#queryParams?}}{
+ {{#queryParams}}{ "{{baseName}}", toJson({{paramName}}).toString() }{{#@join}},
+ {{/@join}}{{/queryParams}}
+ }{{/queryParams?}}{{#skipAuth}}, Data { }, false{{/skipAuth}}
+ ){{#responses}}{{#normalResponse?}}{{#properties?}}, d(new Private){{/properties?}}{{/normalResponse?}}{{/responses}}
+{{#bodyParams?}}{
+{{#inlineBody}} setRequestData(Data({{paramName}}));{{/inlineBody}}{{!
+}}{{^inlineBody}} QJsonObject _data;{{#bodyParams}}
+{{^required?}}{{#string?}} if (!{{paramName}}.isEmpty())
+ {{/string?}}{{/required?}} _data.insert("{{baseName}}", toJson({{paramName}}));{{/bodyParams}}
+ setRequestData(_data);{{/inlineBody}}
+}{{/bodyParams?}}{{^bodyParams?}}{ }{{/bodyParams?}}
+{{# responses}}{{#normalResponse?}}{{#properties?}}
+{{camelCaseOperationId}}Job::~{{camelCaseOperationId}}Job()
+{
+ delete d;
+}
+{{# properties}}
+{{>qualifiedMaybeCrefType}} {{camelCaseOperationId}}Job::{{paramName}}() const
+{
+ return d->{{paramName}};
+}
+{{/ properties}}{{#returnFile?}}
+BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QByteArray data)
+{
+ {{properties.nameCamelCase}} = data;
+ return Success;
+}{{/ returnFile?}}{{^returnFile?}}
+BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data)
+{
+ auto json = data.object();
+ {{# properties}}{{#required?}}if (!json.contains("{{baseName}}"))
+ return { JsonParseError,
+ "The key '{{baseName}}' not found in the response" };
+ {{/required?}}d->{{paramName}} = fromJson<{{dataType.name}}>(json.value("{{baseName}}"));
+ {{/ 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..76ae4f51
--- /dev/null
+++ b/jobs/{{base}}.h.mustache
@@ -0,0 +1,61 @@
+{{#@filePartial}}preamble{{/@filePartial}}
+
+#pragma once
+
+{{#operations}}#include "../basejob.h"
+{{/operations}}
+{{#imports}}#include {{_}}
+{{/imports}}
+{{#allModels}}#include "converters.h"
+{{/allModels}}
+namespace QMatrixClient
+{
+{{#models}} // Data structures
+{{# model}}{{#trivial?}}
+ using {{name}} = {{parent.name}};
+{{/ trivial?}}{{^trivial?}}
+ struct {{name}}{{#parents?}} : {{#parents}}{{name}}{{#@join}}, {{/@join}}{{/parents}}{{/parents?}}
+ {
+ {{#vars}}{{dataType.name}} {{nameCamelCase}};
+ {{/vars}}
+ operator QJsonObject() const;
+ };
+
+ template <> struct FromJson<{{name}}>
+ {
+ {{name}} operator()(QJsonValue jv);
+ };
+{{/ trivial?}}{{/model}}
+{{/models}}{{#operations}} // Operations
+{{# operation}}
+ class {{camelCaseOperationId}}Job : public BaseJob
+ {
+ public:{{# models}}
+ // Inner data structures
+{{# model}}{{#trivial?}}
+ using {{name}} = {{parent.name}};
+{{/ trivial?}}{{^trivial?}}
+ struct {{name}}{{#parents?}} : {{#parents}}{{name}}{{#@join}}, {{/@join}}{{/parents}}{{/parents?}}
+ {
+ {{#vars}}{{dataType.name}} {{nameCamelCase}};
+ {{/vars}}
+ operator QJsonObject() const;
+ };
+{{/ trivial?}}{{/model}}
+ // End of inner data structures
+{{/models}}
+ explicit {{camelCaseOperationId}}Job({{#allParams}}{{>maybeCrefType}} {{paramName}}{{^required?}} = {{defaultValue}}{{^defaultValue}}{}{{/defaultValue}}{{/required?}}{{#@join}}, {{/@join}}{{/allParams}});{{!skip EOL
+}}{{# responses}}{{#normalResponse?}}{{#properties?}}
+ ~{{camelCaseOperationId}}Job() override;
+
+ {{#properties}}{{>maybeCrefType}} {{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}}{{!skip EOL
+}}} // namespace QMatrixClient