File indexing completed on 2025-01-19 03:55:39

0001 #include <QNetworkAccessManager>
0002 #include <QNetworkReply>
0003 
0004 #include "o2pollserver.h"
0005 #include "o0jsonresponse.h"
0006 
0007 static QMap<QString, QString> toVerificationParams(const QVariantMap &map)
0008 {
0009     QMap<QString, QString> params;
0010     for (QVariantMap::const_iterator i = map.constBegin();
0011          i != map.constEnd(); ++i)
0012     {
0013         params[i.key()] = i.value().toString();
0014     }
0015     return params;
0016 }
0017 
0018 O2PollServer::O2PollServer(QNetworkAccessManager *manager, const QNetworkRequest &request, const QByteArray &payload, int expiresIn, QObject *parent)
0019     : QObject(parent)
0020     , manager_(manager)
0021     , request_(request)
0022     , payload_(payload)
0023     , expiresIn_(expiresIn)
0024 {
0025     expirationTimer.setTimerType(Qt::VeryCoarseTimer);
0026     expirationTimer.setInterval(expiresIn * 1000);
0027     expirationTimer.setSingleShot(true);
0028     connect(&expirationTimer, SIGNAL(timeout()), this, SLOT(onExpiration()));
0029     expirationTimer.start();
0030 
0031     pollTimer.setTimerType(Qt::VeryCoarseTimer);
0032     pollTimer.setInterval(5 * 1000);
0033     pollTimer.setSingleShot(true);
0034     connect(&pollTimer, SIGNAL(timeout()), this, SLOT(onPollTimeout()));
0035 }
0036 
0037 int O2PollServer::interval() const
0038 {
0039     return pollTimer.interval() / 1000;
0040 }
0041 
0042 void O2PollServer::setInterval(int interval)
0043 {
0044     pollTimer.setInterval(interval * 1000);
0045 }
0046 
0047 void O2PollServer::startPolling()
0048 {
0049     if (expirationTimer.isActive()) {
0050         pollTimer.start();
0051     }
0052 }
0053 
0054 void O2PollServer::onPollTimeout()
0055 {
0056     qDebug() << "O2PollServer::onPollTimeout: retrying";
0057     QNetworkReply * reply = manager_->post(request_, payload_);
0058     connect(reply, SIGNAL(finished()), this, SLOT(onReplyFinished()));
0059 }
0060 
0061 void O2PollServer::onExpiration()
0062 {
0063     pollTimer.stop();
0064     Q_EMIT serverClosed(false);
0065 }
0066 
0067 void O2PollServer::onReplyFinished()
0068 {
0069     QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
0070 
0071     if (!reply) {
0072         qDebug() << "O2PollServer::onReplyFinished: reply is null";
0073         return;
0074     }
0075 
0076     QByteArray replyData = reply->readAll();
0077     QMap<QString, QString> params = toVerificationParams(parseJsonResponse(replyData));
0078 
0079     // Dump replyData
0080     // SENSITIVE DATA in RelWithDebInfo or Debug builds
0081     // qDebug() << "O2PollServer::onReplyFinished: replyData\n";
0082     // qDebug() << QString( replyData );
0083 
0084     if (reply->error() == QNetworkReply::TimeoutError) {
0085         // rfc8628#section-3.2
0086         // "On encountering a connection timeout, clients MUST unilaterally
0087         // reduce their polling frequency before retrying.  The use of an
0088         // exponential backoff algorithm to achieve this, such as doubling the
0089         // polling interval on each such connection timeout, is RECOMMENDED."
0090         setInterval(interval() * 2);
0091         pollTimer.start();
0092     }
0093     else {
0094         QString error = params.value("error");
0095         if (error == "slow_down") {
0096             // rfc8628#section-3.2
0097             // "A variant of 'authorization_pending', the authorization request is
0098             // still pending and polling should continue, but the interval MUST
0099             // be increased by 5 seconds for this and all subsequent requests."
0100             setInterval(interval() + 5);
0101             pollTimer.start();
0102         }
0103         else if (error == "authorization_pending") {
0104             // keep trying - rfc8628#section-3.2
0105             // "The authorization request is still pending as the end user hasn't
0106             // yet completed the user-interaction steps (Section 3.3)."
0107             pollTimer.start();
0108         }
0109         else {
0110             expirationTimer.stop();
0111             Q_EMIT serverClosed(true);
0112             // let O2 handle the other cases
0113             Q_EMIT verificationReceived(params);
0114         }
0115     }
0116     reply->deleteLater();
0117 }
0118 
0119 #include "moc_o2pollserver.cpp"