diff --git a/src/github.cpp b/src/github.cpp index 4c67aec..9bdc766 100644 --- a/src/github.cpp +++ b/src/github.cpp @@ -1,8 +1,6 @@ #include #include #include -#include -#include #include "github.h" #include @@ -124,55 +122,75 @@ void GitHub::request(Method method, const QString &path, const QByteArray &data, const std::function &callback, bool relative) { - // make sure the timer is a child of this so it's deleted correctly and + // make sure the timer is owned by this so it's deleted correctly and // doesn't fire after the GitHub object is destroyed; this happens when // restarting MO by switching instances, for example QTimer *timer = new QTimer(this); - timer->setSingleShot(true); - timer->setInterval(30000); + timer->setInterval(10000); + QNetworkReply *reply = genReply(method, path, data, relative); - // remember this reply + // remember this reply so it can be deleted in the destructor if necessary m_replies.push_back(reply); - connect(reply, &QNetworkReply::finished, [this, reply, timer, method, data, callback]() { - QJsonDocument result = handleReply(reply); - QJsonObject object = result.object(); - timer->stop(); - if (object.value("http_status").toDouble() == 301.0) { - request(method, object.value("redirection").toString(), data, callback, - false); - } else { - callback(result); - } + Request req = {method, data, callback, timer, reply}; - deleteReply(reply); - }); + // finished + connect(reply, &QNetworkReply::finished, [this, req]{ onFinished(req); }); - connect(reply, - static_cast( - &QNetworkReply::error), - [this, reply, timer, callback](QNetworkReply::NetworkError error) { - qDebug("network error %d", error); - timer->stop(); - reply->disconnect(); - callback(QJsonDocument( - QJsonObject({{"network_error", reply->errorString()}}))); + // error + connect( + reply, qOverload(&QNetworkReply::error), + [this, req](auto&& error){ onError(req, error); }); - deleteReply(reply); - }); - - connect(timer, &QTimer::timeout, [this, reply]() { - qDebug("timeout"); - - // don't delete the reply, abort will fire the error() handler above - reply->abort(); - }); + // timeout + connect(timer, &QTimer::timeout, [this, req]{ onTimeout(req); }); timer->start(); } +void GitHub::onFinished(const Request& req) +{ + QJsonDocument result = handleReply(req.reply); + QJsonObject object = result.object(); + + req.timer->stop(); + + if (object.value("http_status").toInt() == 301) { + request( + req.method, object.value("redirection").toString(), + req.data, req.callback, false); + } else { + req.callback(result); + } + + deleteReply(req.reply); +} + +void GitHub::onError(const Request& req, QNetworkReply::NetworkError error) +{ + qDebug("network error %d", error); + + req.timer->stop(); + req.reply->disconnect(); + + QJsonObject root({{"network_error", req.reply->errorString()}}); + QJsonDocument doc(root); + + req.callback(doc); + + deleteReply(req.reply); +} + +void GitHub::onTimeout(const Request& req) +{ + qDebug("timeout"); + + // don't delete the reply, abort will fire the error() handler above + req.reply->abort(); +} + void GitHub::deleteReply(QNetworkReply* reply) { // remove from the list diff --git a/src/github.h b/src/github.h index 9faaca2..b8d5ffb 100644 --- a/src/github.h +++ b/src/github.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include class GitHubException : public std::exception @@ -85,10 +87,23 @@ private: const QByteArray &data, bool relative); private: + struct Request + { + Method method = Method::GET; + QByteArray data; + std::function callback; + QTimer* timer = nullptr; + QNetworkReply* reply = nullptr; + }; + QNetworkAccessManager *m_AccessManager; // remember the replies that are in flight and delete them in the destructor std::vector m_replies; + void onFinished(const Request& req); + void onError(const Request& req, QNetworkReply::NetworkError error); + void onTimeout(const Request& req); + void deleteReply(QNetworkReply* reply); };