diff options
Diffstat (limited to 'libraries/katabasis/src/PollServer.cpp')
-rw-r--r-- | libraries/katabasis/src/PollServer.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/libraries/katabasis/src/PollServer.cpp b/libraries/katabasis/src/PollServer.cpp new file mode 100644 index 00000000..1083c599 --- /dev/null +++ b/libraries/katabasis/src/PollServer.cpp @@ -0,0 +1,123 @@ +#include <QNetworkAccessManager> +#include <QNetworkReply> + +#include "katabasis/PollServer.h" +#include "JsonResponse.h" + +namespace { +QMap<QString, QString> toVerificationParams(const QVariantMap &map) +{ + QMap<QString, QString> params; + for (QVariantMap::const_iterator i = map.constBegin(); + i != map.constEnd(); ++i) + { + params[i.key()] = i.value().toString(); + } + return params; +} +} + +namespace Katabasis { + +PollServer::PollServer(QNetworkAccessManager *manager, const QNetworkRequest &request, const QByteArray &payload, int expiresIn, QObject *parent) + : QObject(parent) + , manager_(manager) + , request_(request) + , payload_(payload) + , expiresIn_(expiresIn) +{ + expirationTimer.setTimerType(Qt::VeryCoarseTimer); + expirationTimer.setInterval(expiresIn * 1000); + expirationTimer.setSingleShot(true); + connect(&expirationTimer, SIGNAL(timeout()), this, SLOT(onExpiration())); + expirationTimer.start(); + + pollTimer.setTimerType(Qt::VeryCoarseTimer); + pollTimer.setInterval(5 * 1000); + pollTimer.setSingleShot(true); + connect(&pollTimer, SIGNAL(timeout()), this, SLOT(onPollTimeout())); +} + +int PollServer::interval() const +{ + return pollTimer.interval() / 1000; +} + +void PollServer::setInterval(int interval) +{ + pollTimer.setInterval(interval * 1000); +} + +void PollServer::startPolling() +{ + if (expirationTimer.isActive()) { + pollTimer.start(); + } +} + +void PollServer::onPollTimeout() +{ + qDebug() << "PollServer::onPollTimeout: retrying"; + QNetworkReply * reply = manager_->post(request_, payload_); + connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished())); +} + +void PollServer::onExpiration() +{ + pollTimer.stop(); + emit serverClosed(false); +} + +void PollServer::onReplyFinished() +{ + QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); + + if (!reply) { + qDebug() << "PollServer::onReplyFinished: reply is null"; + return; + } + + QByteArray replyData = reply->readAll(); + QMap<QString, QString> params = toVerificationParams(parseJsonResponse(replyData)); + + // Dump replyData + // SENSITIVE DATA in RelWithDebInfo or Debug builds + // qDebug() << "PollServer::onReplyFinished: replyData\n"; + // qDebug() << QString( replyData ); + + if (reply->error() == QNetworkReply::TimeoutError) { + // rfc8628#section-3.2 + // "On encountering a connection timeout, clients MUST unilaterally + // reduce their polling frequency before retrying. The use of an + // exponential backoff algorithm to achieve this, such as doubling the + // polling interval on each such connection timeout, is RECOMMENDED." + setInterval(interval() * 2); + pollTimer.start(); + } + else { + QString error = params.value("error"); + if (error == "slow_down") { + // rfc8628#section-3.2 + // "A variant of 'authorization_pending', the authorization request is + // still pending and polling should continue, but the interval MUST + // be increased by 5 seconds for this and all subsequent requests." + setInterval(interval() + 5); + pollTimer.start(); + } + else if (error == "authorization_pending") { + // keep trying - rfc8628#section-3.2 + // "The authorization request is still pending as the end user hasn't + // yet completed the user-interaction steps (Section 3.3)." + pollTimer.start(); + } + else { + expirationTimer.stop(); + emit serverClosed(true); + // let O2 handle the other cases + emit verificationReceived(params); + } + } + reply->deleteLater(); +} + +} |