2021-07-22 20:15:20 +02:00
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QNetworkReply>
|
|
|
|
|
|
|
|
#include "JsonResponse.h"
|
2023-08-02 18:35:35 +02:00
|
|
|
#include "katabasis/PollServer.h"
|
2021-07-22 20:15:20 +02:00
|
|
|
|
|
|
|
namespace {
|
2023-08-02 18:35:35 +02:00
|
|
|
QMap<QString, QString> toVerificationParams(const QVariantMap& map)
|
2021-07-22 20:15:20 +02:00
|
|
|
{
|
|
|
|
QMap<QString, QString> params;
|
2023-08-02 18:35:35 +02:00
|
|
|
for (QVariantMap::const_iterator i = map.constBegin(); i != map.constEnd(); ++i) {
|
2021-07-22 20:15:20 +02:00
|
|
|
params[i.key()] = i.value().toString();
|
|
|
|
}
|
|
|
|
return params;
|
|
|
|
}
|
2023-08-02 18:35:35 +02:00
|
|
|
} // namespace
|
2021-07-22 20:15:20 +02:00
|
|
|
|
|
|
|
namespace Katabasis {
|
|
|
|
|
2023-08-02 18:35:35 +02:00
|
|
|
PollServer::PollServer(QNetworkAccessManager* manager,
|
|
|
|
const QNetworkRequest& request,
|
|
|
|
const QByteArray& payload,
|
|
|
|
int expiresIn,
|
|
|
|
QObject* parent)
|
|
|
|
: QObject(parent), manager_(manager), request_(request), payload_(payload), expiresIn_(expiresIn)
|
2021-07-22 20:15:20 +02:00
|
|
|
{
|
|
|
|
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";
|
2023-08-02 18:35:35 +02:00
|
|
|
QNetworkReply* reply = manager_->post(request_, payload_);
|
2021-07-22 20:15:20 +02:00
|
|
|
connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void PollServer::onExpiration()
|
|
|
|
{
|
|
|
|
pollTimer.stop();
|
|
|
|
emit serverClosed(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PollServer::onReplyFinished()
|
|
|
|
{
|
2023-08-02 18:35:35 +02:00
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
2021-07-22 20:15:20 +02:00
|
|
|
|
|
|
|
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();
|
2023-08-02 18:35:35 +02:00
|
|
|
} else {
|
2021-07-22 20:15:20 +02:00
|
|
|
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();
|
2023-08-02 18:35:35 +02:00
|
|
|
} else if (error == "authorization_pending") {
|
2021-07-22 20:15:20 +02:00
|
|
|
// 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();
|
2023-08-02 18:35:35 +02:00
|
|
|
} else {
|
2021-07-22 20:15:20 +02:00
|
|
|
expirationTimer.stop();
|
|
|
|
emit serverClosed(true);
|
|
|
|
// let O2 handle the other cases
|
|
|
|
emit verificationReceived(params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
|
2023-08-02 18:35:35 +02:00
|
|
|
} // namespace Katabasis
|