diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/connection.cpp | 4 | ||||
-rw-r--r-- | lib/csapi/gtad.yaml | 165 | ||||
-rw-r--r-- | lib/csapi/preamble.mustache | 3 | ||||
-rw-r--r-- | lib/csapi/{{base}}.cpp.mustache | 182 | ||||
-rw-r--r-- | lib/csapi/{{base}}.h.mustache | 119 | ||||
-rw-r--r-- | lib/jobs/basejob.cpp | 96 | ||||
-rw-r--r-- | lib/jobs/basejob.h | 30 | ||||
-rw-r--r-- | lib/syncdata.h | 2 |
8 files changed, 75 insertions, 526 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 9f4f7082..efc7163e 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -20,7 +20,7 @@ #include "connectiondata.h" #ifdef Quotient_E2EE_ENABLED -#include "encryptionmanager.h" +# include "encryptionmanager.h" #endif // Quotient_E2EE_ENABLED #include "room.h" #include "settings.h" @@ -45,7 +45,7 @@ #include "jobs/syncjob.h" #ifdef Quotient_E2EE_ENABLED -#include "account.h" // QtOlm +# include "account.h" // QtOlm #endif // Quotient_E2EE_ENABLED #include <QtCore/QCoreApplication> diff --git a/lib/csapi/gtad.yaml b/lib/csapi/gtad.yaml deleted file mode 100644 index 086bd4f7..00000000 --- a/lib/csapi/gtad.yaml +++ /dev/null @@ -1,165 +0,0 @@ -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 - - # 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: - imports: [ '"converters.h"' ] - omittedValue: 'none' # See `none` in converters.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}}") - imports: <QtCore/QDate> - - dateTime: - type: QDateTime - initializer: QDateTime::fromString("{{defaultValue}}") - imports: <QtCore/QDateTime> - - //: &QString - type: QString - initializer: QStringLiteral("{{defaultValue}}") - isString: - - file: *ByteStream - - +set: { avoidCopy: } - +on: - - object: &QJsonObject { type: QJsonObject, imports: <QtCore/QJsonObject> } - - $ref: - - +set: { moveOnly: } - +on: - - /state_event.yaml$/: - { type: StateEventPtr, imports: '"events/eventloader.h"' } - - /room_event.yaml$/: - { type: RoomEventPtr, imports: '"events/eventloader.h"' } - - /event.yaml$/: - { type: EventPtr, imports: '"events/eventloader.h"' } - - /m\.room\.member$/: pass # This $ref is only used in an array, see below - - //: *UseOmittable # Also apply "avoidCopy" to all other ref'ed types - - schema: # Properties of inline structure definitions - - TurnServerCredentials: *QJsonObject # Because it's used as is - - //: *UseOmittable - - array: - - string: QStringList - - +set: { moveOnly: } - +on: - - /^Notification|Result$/: - type: "std::vector<{{1}}>" - imports: '"events/eventloader.h"' - - /m\.room\.member$/: - type: "EventsArray<RoomMemberEvent>" - imports: '"events/roommemberevent.h"' - - /state_event.yaml$/: StateEvents - - /room_event.yaml$/: RoomEvents - - /event.yaml$/: Events - - //: { type: "QVector<{{1}}>", imports: <QtCore/QVector> } - - map: # `additionalProperties` in OpenAPI - - RoomState: - type: "UnorderedMap<QString, {{1}}>" - moveOnly: - imports: '"util.h"' - - /.+/: - type: "QHash<QString, {{1}}>" - imports: <QtCore/QHash> - - //: - type: QVariantHash - imports: <QtCore/QVariant> - - variant: # A sequence `type` (multitype) in OpenAPI - - /^string,null|null,string$/: *QString - - //: { type: QVariant, imports: <QtCore/QVariant> } - - #operations: - -mustache: - constants: - # Syntax elements used by GTAD -# _quote: '"' # Common quote for left and right -# _leftQuote: '"' -# _rightQuote: '"' -# _joinChar: ',' # The character used by {{_join}} - not working yet - _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}}{{#moveOnly}}&&{{/moveOnly}}" - qualifiedMaybeCrefType: - "{{#avoidCopy}}const {{/avoidCopy}}{{>qualifiedMaybeOmittableType}}{{#avoidCopy}}&{{/avoidCopy}}{{#moveOnly}}&&{{/moveOnly}}" - - maybeCrefJsonObject: "{{^propertyMap}}const QJsonObject&{{/propertyMap}}{{#propertyMap}}QJsonObject{{/propertyMap}}" - takeOrValue: "{{#propertyMap}}take{{/propertyMap}}{{^propertyMap}}value{{/propertyMap}}" - - initializeDefaultValue: "{{#defaultValue}}{{>initializer}}{{/defaultValue}}{{^defaultValue}}{{>omittedValue}}{{/defaultValue}}" - joinedParamDecl: '{{>maybeCrefType}} {{paramName}}{{^required?}} = {{>initializeDefaultValue}}{{/required?}}{{>cjoin}}' - joinedParamDef: '{{>maybeCrefType}} {{paramName}}{{>cjoin}}' - passQueryParams: '{{#queryParams}}{{paramName}}{{>cjoin}}{{/queryParams}}' - - # 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...) - - # For structures that are not supposed to have a summary (e.g., JSON schema) - docCommentShort: |- - {{#description}} - /// {{_}}{{/description}} - docCommentSummary: |- - {{#summary}} \brief {{summary}} - *{{/summary}} - - templates: - - "{{base}}.h.mustache" - - "{{base}}.cpp.mustache" - - #outFilesList: apifiles.txt - diff --git a/lib/csapi/preamble.mustache b/lib/csapi/preamble.mustache deleted file mode 100644 index 3ba87d61..00000000 --- a/lib/csapi/preamble.mustache +++ /dev/null @@ -1,3 +0,0 @@ -/****************************************************************************** - * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN - */ diff --git a/lib/csapi/{{base}}.cpp.mustache b/lib/csapi/{{base}}.cpp.mustache deleted file mode 100644 index b3bd4de9..00000000 --- a/lib/csapi/{{base}}.cpp.mustache +++ /dev/null @@ -1,182 +0,0 @@ -{{>preamble}} -#include "{{filenameBase}}.h" -{{^models}} -#include "converters.h"{{/models}} -{{#operations}} - {{#producesNonJson?}} -#include <QtNetwork/QNetworkReply> - {{/producesNonJson?}} -#include <QtCore/QStringBuilder> -{{/operations}} - -using namespace Quotient; - -{{#models.model}} - {{#in?}} -void JsonObjectConverter<{{qualifiedName}}>::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?}} -void JsonObjectConverter<{{qualifiedName}}>::fillFrom( - {{>maybeCrefJsonObject}} jo, {{qualifiedName}}& result) -{ {{#parents}} - fillFromJson<{{qualifiedName}}>(jo, result); - {{/parents}}{{#vars}} - fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls), result.{{nameCamelCase}}); - {{/vars}}{{#propertyMap}} - fromJson(jo, result.{{nameCamelCase}}); - {{/propertyMap}} -} - {{/out?}} - -{{/models.model}} -{{#operations}} - -static const auto basePath = QStringLiteral("{{basePathWithoutHost}}"); - {{#operation}}{{#models}} - -// Converters -namespace Quotient { - {{#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<{{qualifiedName}}{{!of the parent!}}>(jo, result); - {{/parents}}{{#vars}} - fromJson(jo.{{>takeOrValue}}("{{baseName}}"_ls), - result.{{nameCamelCase}}); - {{/vars}}{{#propertyMap}} - fromJson(jo, result.{{nameCamelCase}}); - {{/propertyMap}} - } - {{/out?}} -}; - {{/model}} - -} // namespace Quotient - {{/models}} - {{#responses}}{{#normalResponse?}}{{#allProperties?}} - -class {{camelCaseOperationId}}Job::Private -{ - public:{{#allProperties}} - {{>maybeOmittableType}} {{paramName}};{{/allProperties}} -}; - {{/allProperties?}}{{/normalResponse?}}{{/responses}} - {{#queryParams?}} - -BaseJob::Query queryTo{{camelCaseOperationId}}( - {{#queryParams}}{{>joinedParamDef}}{{/queryParams}}) -{ - BaseJob::Query _q;{{#queryParams}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_q, - QStringLiteral("{{baseName}}"), {{paramName}});{{/queryParams}} - return _q; -} - {{/queryParams?}} - {{^bodyParams}} - -QUrl {{camelCaseOperationId}}Job::makeRequestUrl(QUrl baseUrl{{#allParams?}}, - {{#allParams}}{{>joinedParamDef}}{{/allParams}}{{/allParams?}}) -{ - return BaseJob::makeRequestUrl(std::move(baseUrl), - basePath{{#pathParts}} % {{_}}{{/pathParts}}{{#queryParams?}}, - queryTo{{camelCaseOperationId}}({{>passQueryParams}}){{/queryParams?}}); -} {{/bodyParams}} - -{{camelCaseOperationId}}Job::{{camelCaseOperationId}}Job( - {{#allParams}}{{>joinedParamDef}}{{/allParams}}) - : BaseJob(HttpVerb::{{#_cap}}{{#_tolower}}{{httpMethod}}{{/_tolower}}{{/_cap}}, - QStringLiteral("{{camelCaseOperationId}}Job"), {{!object name}} - basePath{{#pathParts}} % {{_}}{{/pathParts}} {{!API endpoint}} - {{#queryParams? - }} , queryTo{{camelCaseOperationId}}({{>passQueryParams}}) - {{/queryParams? - }}{{#skipAuth}}{{#queryParams?}}, {}{{/queryParams?}}, false{{/skipAuth}} ) - {{#responses}}{{#normalResponse?}}{{#allProperties? - }}, d(new Private){{/allProperties?}}{{/normalResponse?}}{{/responses}} -{ {{#headerParams}} - setRequestHeader("{{baseName}}", {{paramName}}.toLatin1()); - {{/headerParams}}{{#bodyParams?}} - {{#inlineBody}} - setRequestData(Data({{!avoid extra linebreaks}}{{ - #consumesNonJson?}}{{nameCamelCase}}{{/consumesNonJson?}}{{ - ^consumesNonJson?}}toJson({{nameCamelCase}}){{/consumesNonJson? - }})); - {{/inlineBody}}{{^inlineBody}} - QJsonObject _data; - {{#bodyParams}} - addParam<{{^required?}}IfNotEmpty{{/required?}}>(_data, - QStringLiteral("{{baseName}}"), {{paramName}}); - {{/bodyParams}} - setRequestData(_data); - {{/inlineBody}} - {{/bodyParams?}}{{#producesNonJson?}} - setExpectedContentTypes({ {{#produces}}"{{_}}"{{>cjoin}}{{/produces}} }); - {{/producesNonJson?}} -} - {{#responses}}{{#normalResponse?}}{{#allProperties?}} - -{{camelCaseOperationId}}Job::~{{camelCaseOperationId}}Job() = default; - {{#allProperties}} - -{{>qualifiedMaybeCrefType}} - {{camelCaseOperationId}}Job::{{paramName}}(){{^moveOnly}} const{{/moveOnly}} -{ - return {{#moveOnly}}std::move({{/moveOnly}}d->{{paramName}}{{#moveOnly}}){{/moveOnly}}; -} - {{/allProperties}} - - {{#producesNonJson?}} -BaseJob::Status {{camelCaseOperationId}}Job::parseReply(QNetworkReply* reply) -{ - {{! We don't check for required headers yet }} - {{#headers}}d->{{paramName}} = reply->rawHeader("{{baseName}}"); - {{/headers}}{{#properties}}d->{{paramName}} = reply;{{/properties}} - return Success; -} - {{/producesNonJson?}}{{^producesNonJson?}} -BaseJob::Status {{camelCaseOperationId}}Job::parseJson(const QJsonDocument& data) -{ - {{#inlineResponse}} - fromJson(data, d->{{paramName}}); - {{/inlineResponse}}{{^inlineResponse}} - auto json = data.object(); - {{#properties}}{{#required?}} - if (!json.contains("{{baseName}}"_ls)) - return { IncorrectResponse, - "The key '{{baseName}}' not found in the response" }; - {{/required?}} - fromJson(json.value("{{baseName}}"_ls), d->{{paramName}}); - {{/properties}} - {{/inlineResponse}} - - return Success; -} - {{/producesNonJson?}} - {{/allProperties?}}{{/normalResponse?}}{{/responses}} -{{/operation}}{{/operations}} diff --git a/lib/csapi/{{base}}.h.mustache b/lib/csapi/{{base}}.h.mustache deleted file mode 100644 index 404aafe8..00000000 --- a/lib/csapi/{{base}}.h.mustache +++ /dev/null @@ -1,119 +0,0 @@ -{{>preamble}} -#pragma once - -{{#operations}} -#include "jobs/basejob.h"{{/operations}} -{{#models}} -#include "converters.h"{{/models}} -{{#imports}} -#include {{_}}{{/imports}} - -namespace Quotient { -{{#models}} - -// Data structures - - {{#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); - {{/in?}} - {{#out?}} - static void fillFrom({{>maybeCrefJsonObject}} jo, {{name}}& pod); - {{/out?}} -}; - {{/model}} -{{/models}} -{{#operations}} - -// Operations - {{#operation}} - -/*!{{>docCommentSummary}}{{#description}} - * {{_}}{{/description}} - */ -class {{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?}} - {{#summary}} - /// {{summary}} - {{/summary}} - {{/allParams?}}{{#allParams?}} - /*!{{>docCommentSummary}} - {{#allParams}} - * \param {{nameCamelCase}}{{#description}} - * {{_}}{{/description}} - {{/allParams}} - */ - {{/allParams?}} - explicit {{camelCaseOperationId}}Job({{#allParams}}{{>joinedParamDecl}}{{/allParams}}); - {{^bodyParams}} - - /*! \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?}}); - {{/bodyParams}} - {{#responses}}{{#normalResponse?}}{{#allProperties?}} - ~{{camelCaseOperationId}}Job() override; - - // Result properties - {{#allProperties}} - - {{>docCommentShort}} - {{>maybeCrefType}} {{paramName}}(){{^moveOnly}} const{{/moveOnly}}; - {{/allProperties}} - -protected: {{#producesNonJson?}} - Status parseReply(QNetworkReply* reply) override; - {{/producesNonJson?}}{{^producesNonJson?}} - Status parseJson(const QJsonDocument& data) override; - {{/producesNonJson?}} - -private: - class Private; - QScopedPointer<Private> d; - {{/allProperties?}}{{/normalResponse?}}{{/responses}} -}; - {{/operation}} -{{/operations}} - -} // namespace Quotient diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index 470250bf..2519713e 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -35,6 +35,47 @@ using namespace Quotient; using std::chrono::seconds, std::chrono::milliseconds; using namespace std::chrono_literals; +BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode) +{ + if (httpCode / 10 == 41) // 41x errors + return httpCode == 410 ? IncorrectRequestError : NotFoundError; + switch (httpCode) { + case 401: + return Unauthorised; + // clang-format off + case 403: case 407: // clang-format on + return ContentAccessError; + case 404: + return NotFoundError; + // clang-format off + case 400: case 405: case 406: case 426: case 428: case 505: // clang-format on + case 494: // Unofficial nginx "Request header too large" + case 497: // Unofficial nginx "HTTP request sent to HTTPS port" + return IncorrectRequestError; + case 429: + return TooManyRequestsError; + case 501: + case 510: + return RequestNotImplementedError; + case 511: + return NetworkAuthRequiredError; + default: + return NetworkError; + } +} + +QDebug BaseJob::Status::dumpToLog(QDebug dbg) const +{ + QDebugStateSaver _s(dbg); + dbg.noquote().nospace(); + if (auto* const k = QMetaEnum::fromType<StatusCode>().valueToKey(code)) { + const QByteArray b = k; + dbg << b.mid(b.lastIndexOf(':')); + } else + dbg << code; + return dbg << ": " << message; +} + struct NetworkReplyDeleter : public QScopedPointerDeleteLater { static inline void cleanup(QNetworkReply* reply) { @@ -232,7 +273,13 @@ void BaseJob::Private::sendRequest() // Pipelining doesn't fly quite well with SSL, occasionally crashing at // what seems like an attempt to write to a closed channel. // req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); - req.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + req.setAttribute( +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + QNetworkRequest::Http2AllowedAttribute +#else + QNetworkRequest::HTTP2AllowedAttribute +#endif + , true); Q_ASSERT(req.url().isValid()); for (auto it = requestHeaders.cbegin(); it != requestHeaders.cend(); ++it) req.setRawHeader(it.key(), it.value()); @@ -316,8 +363,6 @@ void BaseJob::sendRequest() << "Request could not start:" << d->dumpRequest(); } -void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); } - void BaseJob::gotReply() { checkReply(); @@ -363,47 +408,6 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns) return false; } -BaseJob::StatusCode BaseJob::Status::fromHttpCode(int httpCode) -{ - if (httpCode / 10 == 41) // 41x errors - return httpCode == 410 ? IncorrectRequestError : NotFoundError; - switch (httpCode) { - case 401: - return Unauthorised; - // clang-format off - case 403: case 407: // clang-format on - return ContentAccessError; - case 404: - return NotFoundError; - // clang-format off - case 400: case 405: case 406: case 426: case 428: case 505: // clang-format on - case 494: // Unofficial nginx "Request header too large" - case 497: // Unofficial nginx "HTTP request sent to HTTPS port" - return IncorrectRequestError; - case 429: - return TooManyRequestsError; - case 501: case 510: - return RequestNotImplementedError; - case 511: - return NetworkAuthRequiredError; - default: - return NetworkError; - } -} - -QDebug BaseJob::Status::dumpToLog(QDebug dbg) const -{ - QDebugStateSaver _s(dbg); - dbg.noquote().nospace(); - if (auto* const k = QMetaEnum::fromType<StatusCode>().valueToKey(code)) { - const QByteArray b = k; - dbg << b.mid(b.lastIndexOf(':')); - } else - dbg << code; - return dbg << ": " << message; - -} - BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const { // QNetworkReply error codes seem to be flawed when it comes to HTTP; @@ -440,6 +444,8 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const return Status::fromHttpCode(httpCode, message); } +void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); } + BaseJob::Status BaseJob::parseReply(QNetworkReply* reply) { d->rawResponse = reply->readAll(); @@ -602,6 +608,8 @@ QByteArray BaseJob::rawData(int bytesAtMost) const : d->rawResponse; } +const QByteArray& BaseJob::rawData() const { return d->rawResponse; } + QString BaseJob::rawDataSample(int bytesAtMost) const { auto data = rawData(bytesAtMost); diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index 2049f59c..010aca78 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -157,11 +157,16 @@ public: /** Short human-friendly message on the job status */ QString statusCaption() const; - /** Get raw response body as received from the server - * \param bytesAtMost return this number of leftmost bytes, or -1 - * to return the entire response + /*! Get first bytes of the raw response body as received from the server + * + * \param bytesAtMost the number of leftmost bytes to return + * + * \sa rawDataSample */ - QByteArray rawData(int bytesAtMost = -1) const; + QByteArray rawData(int bytesAtMost) const; + + /*! Access the whole response body as received from the server */ + const QByteArray& rawData() const; /** Get UI-friendly sample of raw data * @@ -170,6 +175,8 @@ public: * recommended to present a sample of raw data as "details" next to * error messages. Note that the default \p bytesAtMost value is * also tailored to UI cases. + * + * \sa rawData */ QString rawDataSample(int bytesAtMost = 65535) const; @@ -322,6 +329,7 @@ protected: * on retries. */ virtual void doPrepare(); + /*! Postprocessing after the network request has been sent * * This method is called every time the job receives a running @@ -331,13 +339,15 @@ protected: virtual void onSentRequest(QNetworkReply*); virtual void beforeAbandon(QNetworkReply*); - /** - * Used by gotReply() to check the received reply for general - * issues such as network errors or access denial. - * Returning anything except NoError/Success prevents - * further parseReply()/parseJson() invocation. + /*! \brief Check the pending or received reply for upfront issues + * + * This is invoked when headers are first received and also once + * the complete reply is obtained; the base implementation checks the HTTP + * headers to detect general issues such as network errors or access denial. + * It cannot read the response body (use parseReply/parseError to check + * for problems in the body). Returning anything except NoError/Success + * prevents further processing of the reply. * - * @param reply the reply received from the server * @return the result of checking the reply * * @see gotReply diff --git a/lib/syncdata.h b/lib/syncdata.h index 6e7183ee..41b8186e 100644 --- a/lib/syncdata.h +++ b/lib/syncdata.h @@ -75,7 +75,7 @@ public: static const QString UnreadCountKey; }; -// QVector cannot work with non-copiable objects, std::vector can. +// QVector cannot work with non-copyable objects, std::vector can. using SyncDataList = std::vector<SyncRoomData>; class SyncData { |