From aacc4bcb4a487871daae6717f77605aaba444341 Mon Sep 17 00:00:00 2001 From: Marc Deop Date: Sat, 2 Mar 2019 12:26:57 +0100 Subject: style: apply .clang-format to all .cpp and .h files --- lib/jobs/basejob.cpp | 436 ++++++++++++++---------------- lib/jobs/basejob.h | 584 +++++++++++++++++++++-------------------- lib/jobs/downloadfilejob.cpp | 61 ++--- lib/jobs/downloadfilejob.h | 28 +- lib/jobs/mediathumbnailjob.cpp | 37 +-- lib/jobs/mediathumbnailjob.h | 29 +- lib/jobs/postreadmarkersjob.h | 20 +- lib/jobs/requestdata.cpp | 19 +- lib/jobs/requestdata.h | 37 ++- lib/jobs/syncjob.cpp | 18 +- lib/jobs/syncjob.h | 26 +- 11 files changed, 624 insertions(+), 671 deletions(-) (limited to 'lib/jobs') diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index 8c3381ae..a023d4f7 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "basejob.h" @@ -21,19 +21,18 @@ #include "connectiondata.h" #include "util.h" +#include +#include +#include #include -#include #include -#include -#include -#include +#include #include using namespace QMatrixClient; -struct NetworkReplyDeleter : public QScopedPointerDeleteLater -{ +struct NetworkReplyDeleter : public QScopedPointerDeleteLater { static inline void cleanup(QNetworkReply* reply) { if (reply && reply->isRunning()) @@ -45,51 +44,58 @@ struct NetworkReplyDeleter : public QScopedPointerDeleteLater class BaseJob::Private { public: - // Using an idiom from clang-tidy: - // http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html - Private(HttpVerb v, QString endpoint, const QUrlQuery& q, - Data&& data, bool nt) - : verb(v), apiEndpoint(std::move(endpoint)), requestQuery(q) - , requestData(std::move(data)), needsToken(nt) - { } - - void sendRequest(bool inBackground); - const JobTimeoutConfig& getCurrentTimeoutConfig() const; - - const ConnectionData* connection = nullptr; - - // Contents for the network request - HttpVerb verb; - QString apiEndpoint; - QHash requestHeaders; - QUrlQuery requestQuery; - Data requestData; - bool needsToken; - - // There's no use of QMimeType here because we don't want to match - // content types against the known MIME type hierarchy; and at the same - // type QMimeType is of little help with MIME type globs (`text/*` etc.) - QByteArrayList expectedContentTypes; - - QScopedPointer reply; - Status status = Pending; - QByteArray rawResponse; - QUrl errorUrl; //< May contain a URL to help with some errors - - QTimer timer; - QTimer retryTimer; - - QVector errorStrategy = - { { 90, 5 }, { 90, 10 }, { 120, 30 } }; - int maxRetries = errorStrategy.size(); - int retriesTaken = 0; - - LoggingCategory logCat = JOBS; + // Using an idiom from clang-tidy: + // http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html + Private(HttpVerb v, QString endpoint, const QUrlQuery& q, Data&& data, + bool nt) + : verb(v), + apiEndpoint(std::move(endpoint)), + requestQuery(q), + requestData(std::move(data)), + needsToken(nt) + { + } + + void sendRequest(bool inBackground); + const JobTimeoutConfig& getCurrentTimeoutConfig() const; + + const ConnectionData* connection = nullptr; + + // Contents for the network request + HttpVerb verb; + QString apiEndpoint; + QHash requestHeaders; + QUrlQuery requestQuery; + Data requestData; + bool needsToken; + + // There's no use of QMimeType here because we don't want to match + // content types against the known MIME type hierarchy; and at the same + // type QMimeType is of little help with MIME type globs (`text/*` etc.) + QByteArrayList expectedContentTypes; + + QScopedPointer reply; + Status status = Pending; + QByteArray rawResponse; + QUrl errorUrl; //< May contain a URL to help with some errors + + QTimer timer; + QTimer retryTimer; + + QVector errorStrategy = { { 90, 5 }, + { 90, 10 }, + { 120, 30 } }; + int maxRetries = errorStrategy.size(); + int retriesTaken = 0; + + LoggingCategory logCat = JOBS; }; -BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, bool needsToken) - : BaseJob(verb, name, endpoint, Query { }, Data { }, needsToken) -{ } +BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, + bool needsToken) + : BaseJob(verb, name, endpoint, Query {}, Data {}, needsToken) +{ +} BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, const Query& query, Data&& data, bool needsToken) @@ -98,7 +104,7 @@ BaseJob::BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, setObjectName(name); setExpectedContentTypes({ "application/json" }); d->timer.setSingleShot(true); - connect (&d->timer, &QTimer::timeout, this, &BaseJob::timeout); + connect(&d->timer, &QTimer::timeout, this, &BaseJob::timeout); } BaseJob::~BaseJob() @@ -114,21 +120,20 @@ QUrl BaseJob::requestUrl() const bool BaseJob::isBackground() const { - return d->reply && d->reply->request().attribute( - QNetworkRequest::BackgroundRequestAttribute).toBool(); + return d->reply + && d->reply->request() + .attribute(QNetworkRequest::BackgroundRequestAttribute) + .toBool(); } -const QString& BaseJob::apiEndpoint() const -{ - return d->apiEndpoint; -} +const QString& BaseJob::apiEndpoint() const { return d->apiEndpoint; } void BaseJob::setApiEndpoint(const QString& apiEndpoint) { d->apiEndpoint = apiEndpoint; } -const BaseJob::headers_t&BaseJob::requestHeaders() const +const BaseJob::headers_t& BaseJob::requestHeaders() const { return d->requestHeaders; } @@ -144,25 +149,16 @@ void BaseJob::setRequestHeaders(const BaseJob::headers_t& headers) d->requestHeaders = headers; } -const QUrlQuery& BaseJob::query() const -{ - return d->requestQuery; -} +const QUrlQuery& BaseJob::query() const { return d->requestQuery; } void BaseJob::setRequestQuery(const QUrlQuery& query) { d->requestQuery = query; } -const BaseJob::Data& BaseJob::requestData() const -{ - return d->requestData; -} +const BaseJob::Data& BaseJob::requestData() const { return d->requestData; } -void BaseJob::setRequestData(Data&& data) -{ - std::swap(d->requestData, data); -} +void BaseJob::setRequestData(Data&& data) { std::swap(d->requestData, data); } const QByteArrayList& BaseJob::expectedContentTypes() const { @@ -179,22 +175,22 @@ void BaseJob::setExpectedContentTypes(const QByteArrayList& contentTypes) d->expectedContentTypes = contentTypes; } -QUrl BaseJob::makeRequestUrl(QUrl baseUrl, - const QString& path, const QUrlQuery& query) +QUrl BaseJob::makeRequestUrl(QUrl baseUrl, const QString& path, + const QUrlQuery& query) { auto pathBase = baseUrl.path(); if (!pathBase.endsWith('/') && !path.startsWith('/')) pathBase.push_back('/'); - baseUrl.setPath( pathBase + path ); + baseUrl.setPath(pathBase + path); baseUrl.setQuery(query); return baseUrl; } void BaseJob::Private::sendRequest(bool inBackground) { - QNetworkRequest req - { makeRequestUrl(connection->baseUrl(), apiEndpoint, requestQuery) }; + QNetworkRequest req { makeRequestUrl(connection->baseUrl(), apiEndpoint, + requestQuery) }; if (!requestHeaders.contains("Content-Type")) req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); req.setRawHeader("Authorization", @@ -211,38 +207,34 @@ void BaseJob::Private::sendRequest(bool inBackground) #endif for (auto it = requestHeaders.cbegin(); it != requestHeaders.cend(); ++it) req.setRawHeader(it.key(), it.value()); - switch( verb ) - { - case HttpVerb::Get: - reply.reset( connection->nam()->get(req) ); - break; - case HttpVerb::Post: - reply.reset( connection->nam()->post(req, requestData.source()) ); - break; - case HttpVerb::Put: - reply.reset( connection->nam()->put(req, requestData.source()) ); - break; - case HttpVerb::Delete: - reply.reset( connection->nam()->deleteResource(req) ); - break; + switch (verb) { + case HttpVerb::Get: + reply.reset(connection->nam()->get(req)); + break; + case HttpVerb::Post: + reply.reset(connection->nam()->post(req, requestData.source())); + break; + case HttpVerb::Put: + reply.reset(connection->nam()->put(req, requestData.source())); + break; + case HttpVerb::Delete: + reply.reset(connection->nam()->deleteResource(req)); + break; } } -void BaseJob::beforeStart(const ConnectionData*) -{ } +void BaseJob::beforeStart(const ConnectionData*) {} -void BaseJob::afterStart(const ConnectionData*, QNetworkReply*) -{ } +void BaseJob::afterStart(const ConnectionData*, QNetworkReply*) {} -void BaseJob::beforeAbandon(QNetworkReply*) -{ } +void BaseJob::beforeAbandon(QNetworkReply*) {} void BaseJob::start(const ConnectionData* connData, bool inBackground) { d->connection = connData; d->retryTimer.setSingleShot(true); - connect (&d->retryTimer, &QTimer::timeout, - this, [this,inBackground] { sendRequest(inBackground); }); + connect(&d->retryTimer, &QTimer::timeout, this, + [this, inBackground] { sendRequest(inBackground); }); beforeStart(connData); if (status().good()) @@ -261,27 +253,23 @@ void BaseJob::sendRequest(bool inBackground) if (!d->requestQuery.isEmpty()) qCDebug(d->logCat) << " query:" << d->requestQuery.toString(); d->sendRequest(inBackground); - connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply ); - if (d->reply->isRunning()) - { - connect( d->reply.data(), &QNetworkReply::metaDataChanged, - this, &BaseJob::checkReply); - connect( d->reply.data(), &QNetworkReply::uploadProgress, - this, &BaseJob::uploadProgress); - connect( d->reply.data(), &QNetworkReply::downloadProgress, - this, &BaseJob::downloadProgress); + connect(d->reply.data(), &QNetworkReply::finished, this, + &BaseJob::gotReply); + if (d->reply->isRunning()) { + connect(d->reply.data(), &QNetworkReply::metaDataChanged, this, + &BaseJob::checkReply); + connect(d->reply.data(), &QNetworkReply::uploadProgress, this, + &BaseJob::uploadProgress); + connect(d->reply.data(), &QNetworkReply::downloadProgress, this, + &BaseJob::downloadProgress); d->timer.start(getCurrentTimeout()); qCDebug(d->logCat) << this << "request has been sent"; emit started(); - } - else + } else qCWarning(d->logCat) << this << "request could not start"; } -void BaseJob::checkReply() -{ - setStatus(doCheckReply(d->reply.data())); -} +void BaseJob::checkReply() { setStatus(doCheckReply(d->reply.data())); } void BaseJob::gotReply() { @@ -293,20 +281,18 @@ void BaseJob::gotReply() d->rawResponse = d->reply->readAll(); const auto jsonBody = d->reply->rawHeader("Content-Type") == "application/json"; - qCDebug(d->logCat).noquote() - << "Error body (truncated if long):" << d->rawResponse.left(500); - if (jsonBody) - { + qCDebug(d->logCat).noquote() << "Error body (truncated if long):" + << d->rawResponse.left(500); + if (jsonBody) { auto json = QJsonDocument::fromJson(d->rawResponse).object(); const auto errCode = json.value("errcode"_ls).toString(); - if (error() == TooManyRequestsError || - errCode == "M_LIMIT_EXCEEDED") - { + if (error() == TooManyRequestsError + || errCode == "M_LIMIT_EXCEEDED") { QString msg = tr("Too many requests"); auto retryInterval = json.value("retry_after_ms"_ls).toInt(-1); if (retryInterval != -1) msg += tr(", next retry advised after %1 ms") - .arg(retryInterval); + .arg(retryInterval); else // We still have to figure some reasonable interval retryInterval = getNextRetryInterval(); @@ -320,19 +306,16 @@ void BaseJob::gotReply() emit retryScheduled(d->retriesTaken, retryInterval); return; } - if (errCode == "M_CONSENT_NOT_GIVEN") - { + if (errCode == "M_CONSENT_NOT_GIVEN") { d->status.code = UserConsentRequiredError; d->errorUrl = json.value("consent_uri"_ls).toString(); - } - else if (errCode == "M_UNSUPPORTED_ROOM_VERSION" || - errCode == "M_INCOMPATIBLE_ROOM_VERSION") - { + } else if (errCode == "M_UNSUPPORTED_ROOM_VERSION" + || errCode == "M_INCOMPATIBLE_ROOM_VERSION") { d->status.code = UnsupportedRoomVersionError; if (json.contains("room_version")) d->status.message = - tr("Requested room version: %1") - .arg(json.value("room_version").toString()); + tr("Requested room version: %1") + .arg(json.value("room_version").toString()); } else if (!json.isEmpty()) // Not localisable on the client side setStatus(IncorrectRequestError, json.value("error"_ls).toString()); @@ -350,18 +333,18 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns) // ignore possible appendixes of the content type const auto ctype = type.split(';').front(); - for (const auto& pattern: patterns) - { + for (const auto& pattern : patterns) { if (pattern.startsWith('*') || ctype == pattern) // Fast lane return true; auto patternParts = pattern.split('/'); Q_ASSERT_X(patternParts.size() <= 2, __FUNCTION__, - "BaseJob: Expected content type should have up to two" - " /-separated parts; violating pattern: " + pattern); + "BaseJob: Expected content type should have up to two" + " /-separated parts; violating pattern: " + + pattern); - if (ctype.split('/').front() == patternParts.front() && - patternParts.back() == "*") + if (ctype.split('/').front() == patternParts.front() + && patternParts.back() == "*") return true; // Exact match already went on fast lane } @@ -376,24 +359,26 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes const auto httpCodeHeader = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); - if (!httpCodeHeader.isValid()) - { + if (!httpCodeHeader.isValid()) { qCWarning(d->logCat) << this << "didn't get valid HTTP headers"; return { NetworkError, reply->errorString() }; } - const QString replyState = reply->isRunning() ? - QStringLiteral("(tentative)") : QStringLiteral("(final)"); + const QString replyState = reply->isRunning() + ? QStringLiteral("(tentative)") + : QStringLiteral("(final)"); const auto urlString = '|' + d->reply->url().toDisplayString(); const auto httpCode = httpCodeHeader.toInt(); const auto reason = - reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(); + reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute) + .toString(); if (httpCode / 100 == 2) // 2xx { qCDebug(d->logCat).noquote().nospace() << this << urlString; - qCDebug(d->logCat).noquote() << " " << httpCode << reason << replyState; + qCDebug(d->logCat).noquote() + << " " << httpCode << reason << replyState; if (!checkContentType(reply->rawHeader("Content-Type"), - d->expectedContentTypes)) + d->expectedContentTypes)) return { UnexpectedResponseTypeWarning, "Unexpected content type of the response" }; return NoError; @@ -402,29 +387,37 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const qCWarning(d->logCat).noquote().nospace() << this << urlString; qCWarning(d->logCat).noquote() << " " << httpCode << reason << replyState; return { [httpCode]() -> StatusCode { - if (httpCode / 10 == 41) - return httpCode == 410 ? IncorrectRequestError : NotFoundError; - switch (httpCode) - { - case 401: case 403: case 407: + if (httpCode / 10 == 41) + return httpCode == 410 ? IncorrectRequestError + : NotFoundError; + switch (httpCode) { + case 401: + case 403: + case 407: return ContentAccessError; case 404: return NotFoundError; - case 400: case 405: case 406: case 426: case 428: + case 400: + case 405: + case 406: + case 426: + case 428: case 505: 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: + case 501: + case 510: return RequestNotImplementedError; case 511: return NetworkAuthRequiredError; default: return NetworkError; - } - }(), reply->errorString() }; + } + }(), + reply->errorString() }; } BaseJob::Status BaseJob::parseReply(QNetworkReply* reply) @@ -432,30 +425,25 @@ BaseJob::Status BaseJob::parseReply(QNetworkReply* reply) d->rawResponse = reply->readAll(); QJsonParseError error; const auto& json = QJsonDocument::fromJson(d->rawResponse, &error); - if( error.error == QJsonParseError::NoError ) + if (error.error == QJsonParseError::NoError) return parseJson(json); return { IncorrectResponseError, error.errorString() }; } -BaseJob::Status BaseJob::parseJson(const QJsonDocument&) -{ - return Success; -} +BaseJob::Status BaseJob::parseJson(const QJsonDocument&) { return Success; } void BaseJob::stop() { d->timer.stop(); - if (d->reply) - { + if (d->reply) { d->reply->disconnect(this); // Ignore whatever comes from the reply - if (d->reply->isRunning()) - { - qCWarning(d->logCat) << this << "stopped without ready network reply"; + if (d->reply->isRunning()) { + qCWarning(d->logCat) + << this << "stopped without ready network reply"; d->reply->abort(); } - } - else + } else qCWarning(d->logCat) << this << "stopped with empty network reply"; } @@ -463,16 +451,16 @@ void BaseJob::finishJob() { stop(); if ((error() == NetworkError || error() == TimeoutError) - && d->retriesTaken < d->maxRetries) - { + && d->retriesTaken < d->maxRetries) { // TODO: The whole retrying thing should be put to ConnectionManager // otherwise independently retrying jobs make a bit of notification // storm towards the UI. const auto retryInterval = error() == TimeoutError ? 0 : getNextRetryInterval(); ++d->retriesTaken; - qCWarning(d->logCat).nospace() << this << ": retry #" << d->retriesTaken - << " in " << retryInterval/1000 << " s"; + qCWarning(d->logCat).nospace() + << this << ": retry #" << d->retriesTaken << " in " + << retryInterval / 1000 << " s"; d->retryTimer.start(retryInterval); emit retryScheduled(d->retriesTaken, retryInterval); return; @@ -510,93 +498,78 @@ BaseJob::duration_t BaseJob::millisToRetry() const return d->retryTimer.isActive() ? d->retryTimer.remainingTime() : 0; } -int BaseJob::maxRetries() const -{ - return d->maxRetries; -} +int BaseJob::maxRetries() const { return d->maxRetries; } void BaseJob::setMaxRetries(int newMaxRetries) { d->maxRetries = newMaxRetries; } -BaseJob::Status BaseJob::status() const -{ - return d->status; -} +BaseJob::Status BaseJob::status() const { return d->status; } QByteArray BaseJob::rawData(int bytesAtMost) const { return bytesAtMost > 0 && d->rawResponse.size() > bytesAtMost - ? d->rawResponse.left(bytesAtMost) : d->rawResponse; + ? d->rawResponse.left(bytesAtMost) + : d->rawResponse; } QString BaseJob::rawDataSample(int bytesAtMost) const { auto data = rawData(bytesAtMost); Q_ASSERT(data.size() <= d->rawResponse.size()); - return data.size() == d->rawResponse.size() - ? data : data + tr("...(truncated, %Ln bytes in total)", - "Comes after trimmed raw network response", - d->rawResponse.size()); - + return data.size() == d->rawResponse.size() ? data + : data + + tr("...(truncated, %Ln bytes in total)", + "Comes after trimmed raw network response", + d->rawResponse.size()); } QString BaseJob::statusCaption() const { - switch (d->status.code) - { - case Success: - return tr("Success"); - case Pending: - return tr("Request still pending response"); - case UnexpectedResponseTypeWarning: - return tr("Warning: Unexpected response type"); - case Abandoned: - return tr("Request was abandoned"); - case NetworkError: - return tr("Network problems"); - case JsonParseError: - return tr("Response could not be parsed"); - case TimeoutError: - return tr("Request timed out"); - case ContentAccessError: - return tr("Access error"); - case NotFoundError: - return tr("Not found"); - case IncorrectRequestError: - return tr("Invalid request"); - case IncorrectResponseError: - return tr("Response could not be parsed"); - case TooManyRequestsError: - return tr("Too many requests"); - case RequestNotImplementedError: - return tr("Function not implemented by the server"); - case NetworkAuthRequiredError: - return tr("Network authentication required"); - case UserConsentRequiredError: - return tr("User consent required"); - case UnsupportedRoomVersionError: - return tr("The server does not support the needed room version"); - default: - return tr("Request failed"); + switch (d->status.code) { + case Success: + return tr("Success"); + case Pending: + return tr("Request still pending response"); + case UnexpectedResponseTypeWarning: + return tr("Warning: Unexpected response type"); + case Abandoned: + return tr("Request was abandoned"); + case NetworkError: + return tr("Network problems"); + case JsonParseError: + return tr("Response could not be parsed"); + case TimeoutError: + return tr("Request timed out"); + case ContentAccessError: + return tr("Access error"); + case NotFoundError: + return tr("Not found"); + case IncorrectRequestError: + return tr("Invalid request"); + case IncorrectResponseError: + return tr("Response could not be parsed"); + case TooManyRequestsError: + return tr("Too many requests"); + case RequestNotImplementedError: + return tr("Function not implemented by the server"); + case NetworkAuthRequiredError: + return tr("Network authentication required"); + case UserConsentRequiredError: + return tr("User consent required"); + case UnsupportedRoomVersionError: + return tr("The server does not support the needed room version"); + default: + return tr("Request failed"); } } -int BaseJob::error() const -{ - return d->status.code; -} +int BaseJob::error() const { return d->status.code; } -QString BaseJob::errorString() const -{ - return d->status.message; -} +QString BaseJob::errorString() const { return d->status.message; } -QUrl BaseJob::errorUrl() const -{ - return d->errorUrl; -} +QUrl BaseJob::errorUrl() const { return d->errorUrl; } void BaseJob::setStatus(Status s) { @@ -629,11 +602,8 @@ void BaseJob::abandon() void BaseJob::timeout() { - setStatus( TimeoutError, "The job has timed out" ); + setStatus(TimeoutError, "The job has timed out"); finishJob(); } -void BaseJob::setLoggingCategory(LoggingCategory lcf) -{ - d->logCat = lcf; -} +void BaseJob::setLoggingCategory(LoggingCategory lcf) { d->logCat = lcf; } diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index 4c1c7706..8ff25d42 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once @@ -21,332 +21,336 @@ #include "../logging.h" #include "requestdata.h" +#include #include #include -#include class QNetworkReply; class QSslError; -namespace QMatrixClient -{ +namespace QMatrixClient { class ConnectionData; enum class HttpVerb { Get, Put, Post, Delete }; - struct JobTimeoutConfig - { + struct JobTimeoutConfig { int jobTimeout; int nextRetryInterval; }; - class BaseJob: public QObject + class BaseJob : public QObject { - Q_OBJECT - Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT) - Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries) + Q_OBJECT + Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT) + Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries) public: - /* Just in case, the values are compatible with KJob - * (which BaseJob used to inherit from). */ - enum StatusCode { NoError = 0 // To be compatible with Qt conventions - , Success = 0 - , Pending = 1 - , WarningLevel = 20 - , UnexpectedResponseTypeWarning = 21 - , Abandoned = 50 //< A very brief period between abandoning and object deletion - , ErrorLevel = 100 //< Errors have codes starting from this - , NetworkError = 100 - , JsonParseError // TODO: Merge into IncorrectResponseError - , TimeoutError - , ContentAccessError - , NotFoundError - , IncorrectRequestError - , IncorrectResponseError - , TooManyRequestsError - , RequestNotImplementedError - , UnsupportedRoomVersionError - , NetworkAuthRequiredError - , UserConsentRequiredError - , UserDefinedError = 200 - }; - - /** - * A simple wrapper around QUrlQuery that allows its creation from - * a list of string pairs - */ - class Query : public QUrlQuery + /* Just in case, the values are compatible with KJob + * (which BaseJob used to inherit from). */ + enum StatusCode { + NoError = 0 // To be compatible with Qt conventions + , + Success = 0, + Pending = 1, + WarningLevel = 20, + UnexpectedResponseTypeWarning = 21, + Abandoned = 50 //< A very brief period between abandoning and object + //deletion + , + ErrorLevel = 100 //< Errors have codes starting from this + , + NetworkError = 100, + JsonParseError // TODO: Merge into IncorrectResponseError + , + TimeoutError, + ContentAccessError, + NotFoundError, + IncorrectRequestError, + IncorrectResponseError, + TooManyRequestsError, + RequestNotImplementedError, + UnsupportedRoomVersionError, + NetworkAuthRequiredError, + UserConsentRequiredError, + UserDefinedError = 200 + }; + + /** + * A simple wrapper around QUrlQuery that allows its creation from + * a list of string pairs + */ + class Query : public QUrlQuery + { + public: + using QUrlQuery::QUrlQuery; + Query() = default; + Query(const std::initializer_list>& l) { - public: - using QUrlQuery::QUrlQuery; - Query() = default; - Query(const std::initializer_list< QPair >& l) - { - setQueryItems(l); - } - }; - - using Data = RequestData; - - /** - * This structure stores the status of a server call job. The status consists - * of a code, that is described (but not delimited) by the respective enum, - * and a freeform message. - * - * To extend the list of error codes, define an (anonymous) enum - * along the lines of StatusCode, with additional values - * starting at UserDefinedError - */ - class Status + setQueryItems(l); + } + }; + + using Data = RequestData; + + /** + * This structure stores the status of a server call job. The status + * consists of a code, that is described (but not delimited) by the + * respective enum, and a freeform message. + * + * To extend the list of error codes, define an (anonymous) enum + * along the lines of StatusCode, with additional values + * starting at UserDefinedError + */ + class Status + { + public: + Status(StatusCode c) : code(c) {} + Status(int c, QString m) : code(c), message(std::move(m)) {} + + bool good() const { return code < ErrorLevel; } + friend QDebug operator<<(QDebug dbg, const Status& s) { - public: - Status(StatusCode c) : code(c) { } - Status(int c, QString m) : code(c), message(std::move(m)) { } - - bool good() const { return code < ErrorLevel; } - friend QDebug operator<<(QDebug dbg, const Status& s) - { - QDebugStateSaver _s(dbg); - return dbg.noquote().nospace() - << s.code << ": " << s.message; - } - - bool operator==(const Status& other) const - { - return code == other.code && message == other.message; - } - bool operator!=(const Status& other) const - { - return !operator==(other); - } - - int code; - QString message; - }; - - using duration_t = int; // milliseconds + QDebugStateSaver _s(dbg); + return dbg.noquote().nospace() << s.code << ": " << s.message; + } - public: - BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, - bool needsToken = true); - BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, - const Query& query, Data&& data = {}, - bool needsToken = true); - - QUrl requestUrl() const; - bool isBackground() const; - - /** Current status of the job */ - Status status() const; - /** 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 - */ - QByteArray rawData(int bytesAtMost = -1) const; - /** Get UI-friendly sample of raw data - * - * This is almost the same as rawData but appends the "truncated" - * suffix if not all data fit in bytesAtMost. This call is - * 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. - */ - QString rawDataSample(int bytesAtMost = 65535) const; - - /** Error (more generally, status) code - * Equivalent to status().code - * \sa status - */ - int error() const; - /** Error-specific message, as returned by the server */ - virtual QString errorString() const; - /** A URL to help/clarify the error, if provided by the server */ - QUrl errorUrl() const; - - int maxRetries() const; - void setMaxRetries(int newMaxRetries); - - Q_INVOKABLE duration_t getCurrentTimeout() const; - Q_INVOKABLE duration_t getNextRetryInterval() const; - Q_INVOKABLE duration_t millisToRetry() const; - - friend QDebug operator<<(QDebug dbg, const BaseJob* j) + bool operator==(const Status& other) const { - return dbg << j->objectName(); + return code == other.code && message == other.message; } + bool operator!=(const Status& other) const + { + return !operator==(other); + } + + int code; + QString message; + }; + + using duration_t = int; // milliseconds + + public: + BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, + bool needsToken = true); + BaseJob(HttpVerb verb, const QString& name, const QString& endpoint, + const Query& query, Data&& data = {}, bool needsToken = true); + + QUrl requestUrl() const; + bool isBackground() const; + + /** Current status of the job */ + Status status() const; + /** 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 + */ + QByteArray rawData(int bytesAtMost = -1) const; + /** Get UI-friendly sample of raw data + * + * This is almost the same as rawData but appends the "truncated" + * suffix if not all data fit in bytesAtMost. This call is + * 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. + */ + QString rawDataSample(int bytesAtMost = 65535) const; + + /** Error (more generally, status) code + * Equivalent to status().code + * \sa status + */ + int error() const; + /** Error-specific message, as returned by the server */ + virtual QString errorString() const; + /** A URL to help/clarify the error, if provided by the server */ + QUrl errorUrl() const; + + int maxRetries() const; + void setMaxRetries(int newMaxRetries); + + Q_INVOKABLE duration_t getCurrentTimeout() const; + Q_INVOKABLE duration_t getNextRetryInterval() const; + Q_INVOKABLE duration_t millisToRetry() const; + + friend QDebug operator<<(QDebug dbg, const BaseJob* j) + { + return dbg << j->objectName(); + } public slots: - void start(const ConnectionData* connData, - bool inBackground = false); - - /** - * Abandons the result of this job, arrived or unarrived. - * - * This aborts waiting for a reply from the server (if there was - * any pending) and deletes the job object. No result signals - * (result, success, failure) are emitted. - */ - void abandon(); + void start(const ConnectionData* connData, bool inBackground = false); + + /** + * Abandons the result of this job, arrived or unarrived. + * + * This aborts waiting for a reply from the server (if there was + * any pending) and deletes the job object. No result signals + * (result, success, failure) are emitted. + */ + void abandon(); signals: - /** The job is about to send a network request */ - void aboutToStart(); - - /** The job has sent a network request */ - void started(); - - /** The job has changed its status */ - void statusChanged(Status newStatus); - - /** - * The previous network request has failed; the next attempt will - * be done in the specified time - * @param nextAttempt the 1-based number of attempt (will always be more than 1) - * @param inMilliseconds the interval after which the next attempt will be taken - */ - void retryScheduled(int nextAttempt, int inMilliseconds); - - /** - * Emitted when the job is finished, in any case. It is used to notify - * observers that the job is terminated and that progress can be hidden. - * - * This should not be emitted directly by subclasses; - * use finishJob() instead. - * - * In general, to be notified of a job's completion, client code - * should connect to result(), success(), or failure() - * rather than finished(). However if you need to track the job's - * lifecycle you should connect to this instead of result(); - * in particular, only this signal will be emitted on abandoning. - * - * @param job the job that emitted this signal - * - * @see result, success, failure - */ - void finished(BaseJob* job); - - /** - * Emitted when the job is finished (except when abandoned). - * - * Use error() to know if the job was finished with error. - * - * @param job the job that emitted this signal - * - * @see success, failure - */ - void result(BaseJob* job); - - /** - * Emitted together with result() in case there's no error. - * - * @see result, failure - */ - void success(BaseJob*); - - /** - * Emitted together with result() if there's an error. - * Similar to result(), this won't be emitted in case of abandon(). - * - * @see result, success - */ - void failure(BaseJob*); - - void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); - void uploadProgress(qint64 bytesSent, qint64 bytesTotal); + /** The job is about to send a network request */ + void aboutToStart(); + + /** The job has sent a network request */ + void started(); + + /** The job has changed its status */ + void statusChanged(Status newStatus); + + /** + * The previous network request has failed; the next attempt will + * be done in the specified time + * @param nextAttempt the 1-based number of attempt (will always be more + * than 1) + * @param inMilliseconds the interval after which the next attempt will + * be taken + */ + void retryScheduled(int nextAttempt, int inMilliseconds); + + /** + * Emitted when the job is finished, in any case. It is used to notify + * observers that the job is terminated and that progress can be hidden. + * + * This should not be emitted directly by subclasses; + * use finishJob() instead. + * + * In general, to be notified of a job's completion, client code + * should connect to result(), success(), or failure() + * rather than finished(). However if you need to track the job's + * lifecycle you should connect to this instead of result(); + * in particular, only this signal will be emitted on abandoning. + * + * @param job the job that emitted this signal + * + * @see result, success, failure + */ + void finished(BaseJob* job); + + /** + * Emitted when the job is finished (except when abandoned). + * + * Use error() to know if the job was finished with error. + * + * @param job the job that emitted this signal + * + * @see success, failure + */ + void result(BaseJob* job); + + /** + * Emitted together with result() in case there's no error. + * + * @see result, failure + */ + void success(BaseJob*); + + /** + * Emitted together with result() if there's an error. + * Similar to result(), this won't be emitted in case of abandon(). + * + * @see result, success + */ + void failure(BaseJob*); + + void downloadProgress(qint64 bytesReceived, qint64 bytesTotal); + void uploadProgress(qint64 bytesSent, qint64 bytesTotal); protected: - using headers_t = QHash; - - const QString& apiEndpoint() const; - void setApiEndpoint(const QString& apiEndpoint); - const headers_t& requestHeaders() const; - void setRequestHeader(const headers_t::key_type& headerName, - const headers_t::mapped_type& headerValue); - void setRequestHeaders(const headers_t& headers); - const QUrlQuery& query() const; - void setRequestQuery(const QUrlQuery& query); - const Data& requestData() const; - void setRequestData(Data&& data); - const QByteArrayList& expectedContentTypes() const; - void addExpectedContentType(const QByteArray& contentType); - void setExpectedContentTypes(const QByteArrayList& contentTypes); - - /** Construct a URL out of baseUrl, path and query - * The function automatically adds '/' between baseUrl's path and - * \p path if necessary. The query component of \p baseUrl - * is ignored. - */ - static QUrl makeRequestUrl(QUrl baseUrl, const QString& path, - const QUrlQuery& query = {}); - - virtual void beforeStart(const ConnectionData* connData); - virtual void afterStart(const ConnectionData* connData, - QNetworkReply* reply); - 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. - * - * @param reply the reply received from the server - * @return the result of checking the reply - * - * @see gotReply - */ - virtual Status doCheckReply(QNetworkReply* reply) const; - - /** - * Processes the reply. By default, parses the reply into - * a QJsonDocument and calls parseJson() if it's a valid JSON. - * - * @param reply raw contents of a HTTP reply from the server (without headers) - * - * @see gotReply, parseJson - */ - virtual Status parseReply(QNetworkReply* reply); - - /** - * Processes the JSON document received from the Matrix server. - * By default returns succesful status without analysing the JSON. - * - * @param json valid JSON document received from the server - * - * @see parseReply - */ - virtual Status parseJson(const QJsonDocument&); - - void setStatus(Status s); - void setStatus(int code, QString message); - - // Q_DECLARE_LOGGING_CATEGORY return different function types - // in different versions - using LoggingCategory = decltype(JOBS)*; - void setLoggingCategory(LoggingCategory lcf); - - // Job objects should only be deleted via QObject::deleteLater - ~BaseJob() override; + using headers_t = QHash; + + const QString& apiEndpoint() const; + void setApiEndpoint(const QString& apiEndpoint); + const headers_t& requestHeaders() const; + void setRequestHeader(const headers_t::key_type& headerName, + const headers_t::mapped_type& headerValue); + void setRequestHeaders(const headers_t& headers); + const QUrlQuery& query() const; + void setRequestQuery(const QUrlQuery& query); + const Data& requestData() const; + void setRequestData(Data&& data); + const QByteArrayList& expectedContentTypes() const; + void addExpectedContentType(const QByteArray& contentType); + void setExpectedContentTypes(const QByteArrayList& contentTypes); + + /** Construct a URL out of baseUrl, path and query + * The function automatically adds '/' between baseUrl's path and + * \p path if necessary. The query component of \p baseUrl + * is ignored. + */ + static QUrl makeRequestUrl(QUrl baseUrl, const QString& path, + const QUrlQuery& query = {}); + + virtual void beforeStart(const ConnectionData* connData); + virtual void afterStart(const ConnectionData* connData, + QNetworkReply* reply); + 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. + * + * @param reply the reply received from the server + * @return the result of checking the reply + * + * @see gotReply + */ + virtual Status doCheckReply(QNetworkReply* reply) const; + + /** + * Processes the reply. By default, parses the reply into + * a QJsonDocument and calls parseJson() if it's a valid JSON. + * + * @param reply raw contents of a HTTP reply from the server (without + * headers) + * + * @see gotReply, parseJson + */ + virtual Status parseReply(QNetworkReply* reply); + + /** + * Processes the JSON document received from the Matrix server. + * By default returns succesful status without analysing the JSON. + * + * @param json valid JSON document received from the server + * + * @see parseReply + */ + virtual Status parseJson(const QJsonDocument&); + + void setStatus(Status s); + void setStatus(int code, QString message); + + // Q_DECLARE_LOGGING_CATEGORY return different function types + // in different versions + using LoggingCategory = decltype(JOBS)*; + void setLoggingCategory(LoggingCategory lcf); + + // Job objects should only be deleted via QObject::deleteLater + ~BaseJob() override; protected slots: - void timeout(); + void timeout(); private slots: - void sendRequest(bool inBackground); - void checkReply(); - void gotReply(); + void sendRequest(bool inBackground); + void checkReply(); + void gotReply(); private: - void stop(); - void finishJob(); + void stop(); + void finishJob(); - class Private; - QScopedPointer d; + class Private; + QScopedPointer d; }; inline bool isJobRunning(BaseJob* job) { return job && job->error() == BaseJob::Pending; } -} // namespace QMatrixClient +} // namespace QMatrixClient diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp index 2bf9dd8f..12aacb8b 100644 --- a/lib/jobs/downloadfilejob.cpp +++ b/lib/jobs/downloadfilejob.cpp @@ -1,23 +1,24 @@ #include "downloadfilejob.h" -#include #include #include +#include using namespace QMatrixClient; class DownloadFileJob::Private { public: - Private() : tempFile(new QTemporaryFile()) { } + Private() : tempFile(new QTemporaryFile()) {} - explicit Private(const QString& localFilename) - : targetFile(new QFile(localFilename)) - , tempFile(new QFile(targetFile->fileName() + ".qmcdownload")) - { } + explicit Private(const QString& localFilename) + : targetFile(new QFile(localFilename)), + tempFile(new QFile(targetFile->fileName() + ".qmcdownload")) + { + } - QScopedPointer targetFile; - QScopedPointer tempFile; + QScopedPointer targetFile; + QScopedPointer tempFile; }; QUrl DownloadFileJob::makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri) @@ -28,8 +29,8 @@ QUrl DownloadFileJob::makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri) DownloadFileJob::DownloadFileJob(const QString& serverName, const QString& mediaId, const QString& localFilename) - : GetContentJob(serverName, mediaId) - , d(localFilename.isEmpty() ? new Private : new Private(localFilename)) + : GetContentJob(serverName, mediaId), + d(localFilename.isEmpty() ? new Private : new Private(localFilename)) { setObjectName("DownloadFileJob"); } @@ -41,16 +42,15 @@ QString DownloadFileJob::targetFileName() const void DownloadFileJob::beforeStart(const ConnectionData*) { - if (d->targetFile && !d->targetFile->isReadable() && - !d->targetFile->open(QIODevice::WriteOnly)) - { - qCWarning(JOBS) << "Couldn't open the file" - << d->targetFile->fileName() << "for writing"; + if (d->targetFile && !d->targetFile->isReadable() + && !d->targetFile->open(QIODevice::WriteOnly)) { + qCWarning(JOBS) << "Couldn't open the file" << d->targetFile->fileName() + << "for writing"; setStatus(FileError, "Could not open the target file for writing"); return; } - if (!d->tempFile->isReadable() && !d->tempFile->open(QIODevice::WriteOnly)) - { + if (!d->tempFile->isReadable() + && !d->tempFile->open(QIODevice::WriteOnly)) { qCWarning(JOBS) << "Couldn't open the temporary file" << d->tempFile->fileName() << "for writing"; setStatus(FileError, "Could not open the temporary download file"); @@ -61,16 +61,14 @@ void DownloadFileJob::beforeStart(const ConnectionData*) void DownloadFileJob::afterStart(const ConnectionData*, QNetworkReply* reply) { - connect(reply, &QNetworkReply::metaDataChanged, this, [this,reply] { + connect(reply, &QNetworkReply::metaDataChanged, this, [this, reply] { if (!status().good()) return; auto sizeHeader = reply->header(QNetworkRequest::ContentLengthHeader); - if (sizeHeader.isValid()) - { + if (sizeHeader.isValid()) { auto targetSize = sizeHeader.value(); if (targetSize != -1) - if (!d->tempFile->resize(targetSize)) - { + if (!d->tempFile->resize(targetSize)) { qCWarning(JOBS) << "Failed to allocate" << targetSize << "bytes for" << d->tempFile->fileName(); setStatus(FileError, @@ -78,16 +76,15 @@ void DownloadFileJob::afterStart(const ConnectionData*, QNetworkReply* reply) } } }); - connect(reply, &QIODevice::readyRead, this, [this,reply] { + connect(reply, &QIODevice::readyRead, this, [this, reply] { if (!status().good()) return; auto bytes = reply->read(reply->bytesAvailable()); if (!bytes.isEmpty()) d->tempFile->write(bytes); else - qCWarning(JOBS) - << "Unexpected empty chunk when downloading from" - << reply->url() << "to" << d->tempFile->fileName(); + qCWarning(JOBS) << "Unexpected empty chunk when downloading from" + << reply->url() << "to" << d->tempFile->fileName(); }); } @@ -100,22 +97,18 @@ void DownloadFileJob::beforeAbandon(QNetworkReply*) BaseJob::Status DownloadFileJob::parseReply(QNetworkReply*) { - if (d->targetFile) - { + if (d->targetFile) { d->targetFile->close(); - if (!d->targetFile->remove()) - { + if (!d->targetFile->remove()) { qCWarning(JOBS) << "Failed to remove the target file placeholder"; return { FileError, "Couldn't finalise the download" }; } - if (!d->tempFile->rename(d->targetFile->fileName())) - { + if (!d->tempFile->rename(d->targetFile->fileName())) { qCWarning(JOBS) << "Failed to rename" << d->tempFile->fileName() << "to" << d->targetFile->fileName(); return { FileError, "Couldn't finalise the download" }; } - } - else + } else d->tempFile->close(); qCDebug(JOBS) << "Saved a file as" << targetFileName(); return Success; diff --git a/lib/jobs/downloadfilejob.h b/lib/jobs/downloadfilejob.h index ce47ab1c..fd34ba5a 100644 --- a/lib/jobs/downloadfilejob.h +++ b/lib/jobs/downloadfilejob.h @@ -2,29 +2,27 @@ #include "csapi/content-repo.h" -namespace QMatrixClient -{ +namespace QMatrixClient { class DownloadFileJob : public GetContentJob { public: - enum { FileError = BaseJob::UserDefinedError + 1 }; + enum { FileError = BaseJob::UserDefinedError + 1 }; - using GetContentJob::makeRequestUrl; - static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri); + using GetContentJob::makeRequestUrl; + static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri); - DownloadFileJob(const QString& serverName, const QString& mediaId, - const QString& localFilename = {}); + DownloadFileJob(const QString& serverName, const QString& mediaId, + const QString& localFilename = {}); - QString targetFileName() const; + QString targetFileName() const; private: - class Private; - QScopedPointer d; + class Private; + QScopedPointer d; - void beforeStart(const ConnectionData*) override; - void afterStart(const ConnectionData*, - QNetworkReply* reply) override; - void beforeAbandon(QNetworkReply*) override; - Status parseReply(QNetworkReply*) override; + void beforeStart(const ConnectionData*) override; + void afterStart(const ConnectionData*, QNetworkReply* reply) override; + void beforeAbandon(QNetworkReply*) override; + Status parseReply(QNetworkReply*) override; }; } diff --git a/lib/jobs/mediathumbnailjob.cpp b/lib/jobs/mediathumbnailjob.cpp index aeb49839..d3370f1f 100644 --- a/lib/jobs/mediathumbnailjob.cpp +++ b/lib/jobs/mediathumbnailjob.cpp @@ -13,41 +13,42 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mediathumbnailjob.h" using namespace QMatrixClient; -QUrl MediaThumbnailJob::makeRequestUrl(QUrl baseUrl, - const QUrl& mxcUri, QSize requestedSize) +QUrl MediaThumbnailJob::makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri, + QSize requestedSize) { - return makeRequestUrl(std::move(baseUrl), - mxcUri.authority(), mxcUri.path().mid(1), - requestedSize.width(), requestedSize.height()); + return makeRequestUrl(std::move(baseUrl), mxcUri.authority(), + mxcUri.path().mid(1), requestedSize.width(), + requestedSize.height()); } MediaThumbnailJob::MediaThumbnailJob(const QString& serverName, - const QString& mediaId, QSize requestedSize) - : GetContentThumbnailJob(serverName, mediaId, - requestedSize.width(), requestedSize.height()) -{ } + const QString& mediaId, + QSize requestedSize) + : GetContentThumbnailJob(serverName, mediaId, requestedSize.width(), + requestedSize.height()) +{ +} MediaThumbnailJob::MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize) - : MediaThumbnailJob(mxcUri.authority(), mxcUri.path().mid(1), // sans leading '/' + : MediaThumbnailJob(mxcUri.authority(), + mxcUri.path().mid(1), // sans leading '/' requestedSize) -{ } - -QImage MediaThumbnailJob::thumbnail() const { - return _thumbnail; } +QImage MediaThumbnailJob::thumbnail() const { return _thumbnail; } + QImage MediaThumbnailJob::scaledThumbnail(QSize toSize) const { - return _thumbnail.scaled(toSize, - Qt::KeepAspectRatio, Qt::SmoothTransformation); + return _thumbnail.scaled(toSize, Qt::KeepAspectRatio, + Qt::SmoothTransformation); } BaseJob::Status MediaThumbnailJob::parseReply(QNetworkReply* reply) @@ -56,7 +57,7 @@ BaseJob::Status MediaThumbnailJob::parseReply(QNetworkReply* reply) if (!result.good()) return result; - if( _thumbnail.loadFromData(data()->readAll()) ) + if (_thumbnail.loadFromData(data()->readAll())) return Success; return { IncorrectResponseError, "Could not read image data" }; diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h index 7963796e..1dcf8ccb 100644 --- a/lib/jobs/mediathumbnailjob.h +++ b/lib/jobs/mediathumbnailjob.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once @@ -22,26 +22,25 @@ #include -namespace QMatrixClient -{ - class MediaThumbnailJob: public GetContentThumbnailJob +namespace QMatrixClient { + class MediaThumbnailJob : public GetContentThumbnailJob { public: - using GetContentThumbnailJob::makeRequestUrl; - static QUrl makeRequestUrl(QUrl baseUrl, - const QUrl& mxcUri, QSize requestedSize); + using GetContentThumbnailJob::makeRequestUrl; + static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri, + QSize requestedSize); - MediaThumbnailJob(const QString& serverName, const QString& mediaId, - QSize requestedSize); - MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize); + MediaThumbnailJob(const QString& serverName, const QString& mediaId, + QSize requestedSize); + MediaThumbnailJob(const QUrl& mxcUri, QSize requestedSize); - QImage thumbnail() const; - QImage scaledThumbnail(QSize toSize) const; + QImage thumbnail() const; + QImage scaledThumbnail(QSize toSize) const; protected: - Status parseReply(QNetworkReply* reply) override; + Status parseReply(QNetworkReply* reply) override; private: - QImage _thumbnail; + QImage _thumbnail; }; -} // namespace QMatrixClient +} // namespace QMatrixClient diff --git a/lib/jobs/postreadmarkersjob.h b/lib/jobs/postreadmarkersjob.h index 63a8e1d0..3c5cac89 100644 --- a/lib/jobs/postreadmarkersjob.h +++ b/lib/jobs/postreadmarkersjob.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once @@ -27,13 +27,13 @@ using namespace QMatrixClient; class PostReadMarkersJob : public BaseJob { public: - explicit PostReadMarkersJob(const QString& roomId, - const QString& readUpToEventId) - : BaseJob(HttpVerb::Post, "PostReadMarkersJob", - QStringLiteral("_matrix/client/r0/rooms/%1/read_markers") - .arg(roomId)) - { - setRequestData(QJsonObject {{ - QStringLiteral("m.fully_read"), readUpToEventId }}); - } + explicit PostReadMarkersJob(const QString& roomId, + const QString& readUpToEventId) + : BaseJob(HttpVerb::Post, "PostReadMarkersJob", + QStringLiteral("_matrix/client/r0/rooms/%1/read_markers") + .arg(roomId)) + { + setRequestData(QJsonObject { + { QStringLiteral("m.fully_read"), readUpToEventId } }); + } }; diff --git a/lib/jobs/requestdata.cpp b/lib/jobs/requestdata.cpp index 5cb62221..477f49e7 100644 --- a/lib/jobs/requestdata.cpp +++ b/lib/jobs/requestdata.cpp @@ -1,10 +1,10 @@ #include "requestdata.h" +#include #include -#include #include #include -#include +#include using namespace QMatrixClient; @@ -17,22 +17,15 @@ auto fromData(const QByteArray& data) return source; } -template -inline auto fromJson(const JsonDataT& jdata) +template inline auto fromJson(const JsonDataT& jdata) { return fromData(QJsonDocument(jdata).toJson(QJsonDocument::Compact)); } -RequestData::RequestData(const QByteArray& a) - : _source(fromData(a)) -{ } +RequestData::RequestData(const QByteArray& a) : _source(fromData(a)) {} -RequestData::RequestData(const QJsonObject& jo) - : _source(fromJson(jo)) -{ } +RequestData::RequestData(const QJsonObject& jo) : _source(fromJson(jo)) {} -RequestData::RequestData(const QJsonArray& ja) - : _source(fromJson(ja)) -{ } +RequestData::RequestData(const QJsonArray& ja) : _source(fromJson(ja)) {} RequestData::~RequestData() = default; diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h index db011b61..207ff731 100644 --- a/lib/jobs/requestdata.h +++ b/lib/jobs/requestdata.h @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once @@ -26,8 +26,7 @@ class QJsonArray; class QJsonDocument; class QIODevice; -namespace QMatrixClient -{ +namespace QMatrixClient { /** * A simple wrapper that represents the request body. * Provides a unified interface to dump an unstructured byte stream @@ -37,25 +36,23 @@ namespace QMatrixClient class RequestData { public: - RequestData() = default; - RequestData(const QByteArray& a); - RequestData(const QJsonObject& jo); - RequestData(const QJsonArray& ja); - RequestData(QIODevice* source) - : _source(std::unique_ptr(source)) - { } - RequestData(const RequestData&) = delete; - RequestData& operator=(const RequestData&) = delete; - RequestData(RequestData&&) = default; - RequestData& operator=(RequestData&&) = default; - ~RequestData(); + RequestData() = default; + RequestData(const QByteArray& a); + RequestData(const QJsonObject& jo); + RequestData(const QJsonArray& ja); + RequestData(QIODevice* source) + : _source(std::unique_ptr(source)) + { + } + RequestData(const RequestData&) = delete; + RequestData& operator=(const RequestData&) = delete; + RequestData(RequestData&&) = default; + RequestData& operator=(RequestData&&) = default; + ~RequestData(); - QIODevice* source() const - { - return _source.get(); - } + QIODevice* source() const { return _source.get(); } private: - std::unique_ptr _source; + std::unique_ptr _source; }; } // namespace QMatrixClient diff --git a/lib/jobs/syncjob.cpp b/lib/jobs/syncjob.cpp index 84385b55..db11005a 100644 --- a/lib/jobs/syncjob.cpp +++ b/lib/jobs/syncjob.cpp @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "syncjob.h" @@ -29,25 +29,26 @@ SyncJob::SyncJob(const QString& since, const QString& filter, int timeout, { setLoggingCategory(SYNCJOB); QUrlQuery query; - if( !filter.isEmpty() ) + if (!filter.isEmpty()) query.addQueryItem(QStringLiteral("filter"), filter); - if( !presence.isEmpty() ) + if (!presence.isEmpty()) query.addQueryItem(QStringLiteral("set_presence"), presence); - if( timeout >= 0 ) + if (timeout >= 0) query.addQueryItem(QStringLiteral("timeout"), QString::number(timeout)); - if( !since.isEmpty() ) + if (!since.isEmpty()) query.addQueryItem(QStringLiteral("since"), since); setRequestQuery(query); setMaxRetries(std::numeric_limits::max()); } -SyncJob::SyncJob(const QString& since, const Filter& filter, - int timeout, const QString& presence) +SyncJob::SyncJob(const QString& since, const Filter& filter, int timeout, + const QString& presence) : SyncJob(since, QJsonDocument(toJson(filter)).toJson(QJsonDocument::Compact), timeout, presence) -{ } +{ +} BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { @@ -59,4 +60,3 @@ BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) << d.unresolvedRooms().join(','); return BaseJob::IncorrectResponseError; } - diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h index 036b25d0..2afaf0f7 100644 --- a/lib/jobs/syncjob.h +++ b/lib/jobs/syncjob.h @@ -13,33 +13,31 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #pragma once #include "basejob.h" -#include "../syncdata.h" #include "../csapi/definitions/sync_filter.h" +#include "../syncdata.h" -namespace QMatrixClient -{ - class SyncJob: public BaseJob +namespace QMatrixClient { + class SyncJob : public BaseJob { public: - explicit SyncJob(const QString& since = {}, - const QString& filter = {}, - int timeout = -1, const QString& presence = {}); - explicit SyncJob(const QString& since, const Filter& filter, - int timeout = -1, const QString& presence = {}); + explicit SyncJob(const QString& since = {}, const QString& filter = {}, + int timeout = -1, const QString& presence = {}); + explicit SyncJob(const QString& since, const Filter& filter, + int timeout = -1, const QString& presence = {}); - SyncData &&takeData() { return std::move(d); } + SyncData&& takeData() { return std::move(d); } protected: - Status parseJson(const QJsonDocument& data) override; + Status parseJson(const QJsonDocument& data) override; private: - SyncData d; + SyncData d; }; -} // namespace QMatrixClient +} // namespace QMatrixClient -- cgit v1.2.3 From 5722ceaf4bd10c29f1091e3dc5a87f5650ea8c71 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 26 Jun 2019 07:51:08 +0900 Subject: BaseJob::Status: fromHttpCode --- lib/jobs/basejob.cpp | 61 +++++++++++++++++++++++++--------------------------- lib/jobs/basejob.h | 4 ++-- 2 files changed, 31 insertions(+), 34 deletions(-) (limited to 'lib/jobs') diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index a0a3dc29..9c0b431c 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -348,6 +348,34 @@ bool checkContentType(const QByteArray& type, const QByteArrayList& patterns) return false; } +BaseJob::Status BaseJob::Status::fromHttpCode(int httpCode, QString msg) +{ + // clang-format off + return { [httpCode]() -> StatusCode { + if (httpCode / 10 == 41) // 41x errors + return httpCode == 410 ? IncorrectRequestError : NotFoundError; + switch (httpCode) { + case 401: case 403: case 407: + return ContentAccessError; + case 404: + return NotFoundError; + case 400: case 405: case 406: case 426: case 428: case 505: + 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; + } + }(), msg }; + // clang-format on +} + BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const { // QNetworkReply error codes seem to be flawed when it comes to HTTP; @@ -381,38 +409,7 @@ BaseJob::Status BaseJob::doCheckReply(QNetworkReply* reply) const qCWarning(d->logCat).noquote().nospace() << this << urlString; qCWarning(d->logCat).noquote() << " " << httpCode << reason << replyState; - return { [httpCode]() -> StatusCode { - if (httpCode / 10 == 41) - return httpCode == 410 ? IncorrectRequestError - : NotFoundError; - switch (httpCode) { - case 401: - case 403: - case 407: - return ContentAccessError; - case 404: - return NotFoundError; - case 400: - case 405: - case 406: - case 426: - case 428: - case 505: - 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; - } - }(), - reply->errorString() }; + return Status::fromHttpCode(httpCode, reply->errorString()); } BaseJob::Status BaseJob::parseReply(QNetworkReply* reply) diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index 04d79c66..4d379f26 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -116,9 +116,8 @@ public: * along the lines of StatusCode, with additional values * starting at UserDefinedError */ - class Status + struct Status { - public: Status(StatusCode c) : code(c) {} @@ -126,6 +125,7 @@ public: : code(c) , message(std::move(m)) {} + static Status fromHttpCode(int httpCode, QString msg = {}); bool good() const { return code < ErrorLevel; } friend QDebug operator<<(QDebug dbg, const Status& s) -- cgit v1.2.3 From c05ade838f0fce81f2bbe80a3295618a8a26ff52 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 2 Aug 2019 19:59:40 +0900 Subject: Apply the new brace wrapping to source files --- lib/jobs/basejob.cpp | 6 ++---- lib/jobs/basejob.h | 35 +++++++++-------------------------- lib/jobs/downloadfilejob.cpp | 7 ++----- lib/jobs/downloadfilejob.h | 11 +++-------- lib/jobs/mediathumbnailjob.h | 6 ++---- lib/jobs/postreadmarkersjob.h | 3 +-- lib/jobs/requestdata.cpp | 12 +++--------- lib/jobs/requestdata.h | 9 +++------ lib/jobs/syncjob.h | 6 ++---- 9 files changed, 27 insertions(+), 68 deletions(-) (limited to 'lib/jobs') diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index e4a74954..a6471ece 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -32,8 +32,7 @@ using namespace QMatrixClient; -struct NetworkReplyDeleter : public QScopedPointerDeleteLater -{ +struct NetworkReplyDeleter : public QScopedPointerDeleteLater { static inline void cleanup(QNetworkReply* reply) { if (reply && reply->isRunning()) @@ -42,8 +41,7 @@ struct NetworkReplyDeleter : public QScopedPointerDeleteLater } }; -class BaseJob::Private -{ +class BaseJob::Private { public: // Using an idiom from clang-tidy: // http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html diff --git a/lib/jobs/basejob.h b/lib/jobs/basejob.h index f445d087..c85d2d90 100644 --- a/lib/jobs/basejob.h +++ b/lib/jobs/basejob.h @@ -28,32 +28,22 @@ class QNetworkReply; class QSslError; -namespace QMatrixClient -{ +namespace QMatrixClient { class ConnectionData; -enum class HttpVerb -{ - Get, - Put, - Post, - Delete -}; +enum class HttpVerb { Get, Put, Post, Delete }; -struct JobTimeoutConfig -{ +struct JobTimeoutConfig { int jobTimeout; int nextRetryInterval; }; -class BaseJob : public QObject -{ +class BaseJob : public QObject { Q_OBJECT Q_PROPERTY(QUrl requestUrl READ requestUrl CONSTANT) Q_PROPERTY(int maxRetries READ maxRetries WRITE setMaxRetries) public: - enum StatusCode - { + enum StatusCode { NoError = 0 // To be compatible with Qt conventions , Success = 0, @@ -93,8 +83,7 @@ public: * A simple wrapper around QUrlQuery that allows its creation from * a list of string pairs */ - class Query : public QUrlQuery - { + class Query : public QUrlQuery { public: using QUrlQuery::QUrlQuery; Query() = default; @@ -115,16 +104,10 @@ public: * along the lines of StatusCode, with additional values * starting at UserDefinedError */ - class Status - { + class Status { public: - Status(StatusCode c) - : code(c) - {} - Status(int c, QString m) - : code(c) - , message(std::move(m)) - {} + Status(StatusCode c) : code(c) {} + Status(int c, QString m) : code(c), message(std::move(m)) {} bool good() const { return code < ErrorLevel; } friend QDebug operator<<(QDebug dbg, const Status& s) diff --git a/lib/jobs/downloadfilejob.cpp b/lib/jobs/downloadfilejob.cpp index 3dff5a68..9722186c 100644 --- a/lib/jobs/downloadfilejob.cpp +++ b/lib/jobs/downloadfilejob.cpp @@ -6,12 +6,9 @@ using namespace QMatrixClient; -class DownloadFileJob::Private -{ +class DownloadFileJob::Private { public: - Private() - : tempFile(new QTemporaryFile()) - {} + Private() : tempFile(new QTemporaryFile()) {} explicit Private(const QString& localFilename) : targetFile(new QFile(localFilename)) diff --git a/lib/jobs/downloadfilejob.h b/lib/jobs/downloadfilejob.h index 58858448..ebfe5a0d 100644 --- a/lib/jobs/downloadfilejob.h +++ b/lib/jobs/downloadfilejob.h @@ -2,15 +2,10 @@ #include "csapi/content-repo.h" -namespace QMatrixClient -{ -class DownloadFileJob : public GetContentJob -{ +namespace QMatrixClient { +class DownloadFileJob : public GetContentJob { public: - enum - { - FileError = BaseJob::UserDefinedError + 1 - }; + enum { FileError = BaseJob::UserDefinedError + 1 }; using GetContentJob::makeRequestUrl; static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri); diff --git a/lib/jobs/mediathumbnailjob.h b/lib/jobs/mediathumbnailjob.h index eeabe7a9..df0a7f31 100644 --- a/lib/jobs/mediathumbnailjob.h +++ b/lib/jobs/mediathumbnailjob.h @@ -22,10 +22,8 @@ #include -namespace QMatrixClient -{ -class MediaThumbnailJob : public GetContentThumbnailJob -{ +namespace QMatrixClient { +class MediaThumbnailJob : public GetContentThumbnailJob { public: using GetContentThumbnailJob::makeRequestUrl; static QUrl makeRequestUrl(QUrl baseUrl, const QUrl& mxcUri, diff --git a/lib/jobs/postreadmarkersjob.h b/lib/jobs/postreadmarkersjob.h index d53ae66c..cf482a9a 100644 --- a/lib/jobs/postreadmarkersjob.h +++ b/lib/jobs/postreadmarkersjob.h @@ -24,8 +24,7 @@ using namespace QMatrixClient; -class PostReadMarkersJob : public BaseJob -{ +class PostReadMarkersJob : public BaseJob { public: explicit PostReadMarkersJob(const QString& roomId, const QString& readUpToEventId) diff --git a/lib/jobs/requestdata.cpp b/lib/jobs/requestdata.cpp index 8248d6b1..6ad7c007 100644 --- a/lib/jobs/requestdata.cpp +++ b/lib/jobs/requestdata.cpp @@ -23,16 +23,10 @@ inline auto fromJson(const JsonDataT& jdata) return fromData(QJsonDocument(jdata).toJson(QJsonDocument::Compact)); } -RequestData::RequestData(const QByteArray& a) - : _source(fromData(a)) -{} +RequestData::RequestData(const QByteArray& a) : _source(fromData(a)) {} -RequestData::RequestData(const QJsonObject& jo) - : _source(fromJson(jo)) -{} +RequestData::RequestData(const QJsonObject& jo) : _source(fromJson(jo)) {} -RequestData::RequestData(const QJsonArray& ja) - : _source(fromJson(ja)) -{} +RequestData::RequestData(const QJsonArray& ja) : _source(fromJson(ja)) {} RequestData::~RequestData() = default; diff --git a/lib/jobs/requestdata.h b/lib/jobs/requestdata.h index 974a9ddf..55987a3b 100644 --- a/lib/jobs/requestdata.h +++ b/lib/jobs/requestdata.h @@ -26,23 +26,20 @@ class QJsonArray; class QJsonDocument; class QIODevice; -namespace QMatrixClient -{ +namespace QMatrixClient { /** * A simple wrapper that represents the request body. * Provides a unified interface to dump an unstructured byte stream * as well as JSON (and possibly other structures in the future) to * a QByteArray consumed by QNetworkAccessManager request methods. */ -class RequestData -{ +class RequestData { public: RequestData() = default; RequestData(const QByteArray& a); RequestData(const QJsonObject& jo); RequestData(const QJsonArray& ja); - RequestData(QIODevice* source) - : _source(std::unique_ptr(source)) + RequestData(QIODevice* source) : _source(std::unique_ptr(source)) {} RequestData(const RequestData&) = delete; RequestData& operator=(const RequestData&) = delete; diff --git a/lib/jobs/syncjob.h b/lib/jobs/syncjob.h index e2cec8f7..8f925414 100644 --- a/lib/jobs/syncjob.h +++ b/lib/jobs/syncjob.h @@ -22,10 +22,8 @@ #include "../syncdata.h" #include "basejob.h" -namespace QMatrixClient -{ -class SyncJob : public BaseJob -{ +namespace QMatrixClient { +class SyncJob : public BaseJob { public: explicit SyncJob(const QString& since = {}, const QString& filter = {}, int timeout = -1, const QString& presence = {}); -- cgit v1.2.3