Fix a crash when a delayed reply would call a callback for an object that disappeared

pull/196/head
Michael Zanetti 2019-05-30 14:54:06 +02:00
parent 4e11026ea4
commit 0eadb8dcd3
3 changed files with 21 additions and 10 deletions

View File

@ -8,6 +8,7 @@
#include <QSettings>
#include <QUuid>
#include <QTimer>
#include <QPointer>
#include "sigv4utils.h"
@ -820,7 +821,7 @@ void AWSClient::getCredentialsForIdentity(const QString &identityId)
if (qc.method == "fetchDevices") {
fetchDevices();
} else if (qc.method == "postToMQTT") {
postToMQTT(qc.arg1, qc.arg2, qc.callback);
postToMQTT(qc.arg1, qc.arg2, qc.sender, qc.callback);
} else if (qc.method == "deleteAccount") {
deleteAccount();
} else if (qc.method == "registerPushNotificationEndpoint") {
@ -837,7 +838,7 @@ bool AWSClient::tokensExpired() const
return (m_accessTokenExpiry.addSecs(-10) < QDateTime::currentDateTime()) || (m_sessionTokenExpiry.addSecs(-10) < QDateTime::currentDateTime());
}
bool AWSClient::postToMQTT(const QString &boxId, const QString &timestamp, std::function<void(bool)> callback)
bool AWSClient::postToMQTT(const QString &boxId, const QString &timestamp, QObject* sender, std::function<void (bool)> callback)
{
if (!isLoggedIn()) {
qWarning() << "Cannot post to MQTT. Not logged in to AWS";
@ -846,11 +847,13 @@ bool AWSClient::postToMQTT(const QString &boxId, const QString &timestamp, std::
if (tokensExpired()) {
qDebug() << "Cannot post to MQTT. Need to refresh the tokens first";
refreshAccessToken();
QueuedCall::enqueue(m_callQueue, QueuedCall("postToMQTT", boxId, timestamp, callback));
QueuedCall::enqueue(m_callQueue, QueuedCall("postToMQTT", boxId, timestamp, sender, callback));
return true; // So far it looks we're doing ok... let's return true
}
QString topic = QString("%1/%2/proxy").arg(boxId).arg(QString(m_identityId));
QPointer<QObject> senderWatcher = QPointer<QObject>(sender);
// This is somehow broken in AWS...
// The Signature needs to be created with having the topic percentage-encoded twice
// while the actual request needs to go out with it only being encoded once.
@ -882,15 +885,21 @@ bool AWSClient::postToMQTT(const QString &boxId, const QString &timestamp, std::
// }
// qDebug() << "Payload:" << payload;
QNetworkReply *reply = m_nam->post(request, payload);
QTimer::singleShot(5000, reply, [reply, callback](){
QTimer::singleShot(5000, reply, [reply, senderWatcher, callback](){
reply->deleteLater();
qWarning() << "Timeout posting to MQTT";
callback(false);
if (senderWatcher) {
callback(false);
}
});
connect(reply, &QNetworkReply::finished, this, [reply, callback]() {
connect(reply, &QNetworkReply::finished, this, [reply, senderWatcher, callback]() {
reply->deleteLater();
QByteArray data = reply->readAll();
// qDebug() << "MQTT post reply" << data;
if (senderWatcher.isNull()) {
qDebug() << "Request object disappeared. Discarding MQTT reply...";
return;
}
if (reply->error() != QNetworkReply::NoError) {
qWarning() << "MQTT Network reply error" << reply->error() << reply->errorString();
callback(false);
@ -909,7 +918,6 @@ bool AWSClient::postToMQTT(const QString &boxId, const QString &timestamp, std::
return;
}
callback(true);
});
return true;

View File

@ -5,6 +5,7 @@
#include <QNetworkRequest>
#include <QDate>
#include <QAbstractListModel>
#include <QPointer>
class QNetworkAccessManager;
@ -117,7 +118,7 @@ public:
Q_INVOKABLE void fetchDevices();
Q_INVOKABLE bool postToMQTT(const QString &boxId, const QString &timestamp, std::function<void(bool)> callback);
Q_INVOKABLE bool postToMQTT(const QString &boxId, const QString &timestamp, QObject* sender, std::function<void(bool)> callback);
Q_INVOKABLE void getId();
Q_INVOKABLE void registerPushNotificationEndpoint(const QString &registrationId, const QString &deviceDisplayName, const QString mobileDeviceId, const QString &mobileDeviceManufacturer, const QString &mobileDeviceModel);
@ -184,13 +185,14 @@ private:
QueuedCall(const QString &method): method(method) { }
QueuedCall(const QString &method, const QString &arg1): method(method), arg1(arg1) { }
QueuedCall(const QString &method, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5): method(method), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
QueuedCall(const QString &method, const QString &arg1, const QString &arg2, std::function<void(bool)> callback): method(method), arg1(arg1), arg2(arg2), callback(callback) {}
QueuedCall(const QString &method, const QString &arg1, const QString &arg2, QObject* sender, std::function<void(bool)> callback): method(method), arg1(arg1), arg2(arg2), sender(sender), callback(callback) {}
QString method;
QString arg1;
QString arg2;
QString arg3;
QString arg4;
QString arg5;
QPointer<QObject> sender;
std::function<void(bool)> callback;
static void enqueue(QList<QueuedCall> &queue, const QueuedCall &call) {

View File

@ -5,6 +5,7 @@
#include <QUrlQuery>
#include <QHostInfo>
#include <QPointer>
using namespace remoteproxyclient;
@ -52,7 +53,7 @@ bool CloudTransport::connect(const QUrl &url)
m_url = url;
m_timestamp = QDateTime::currentDateTime();
bool postResult = m_awsClient->postToMQTT(url.host(), QString::number(m_timestamp.toMSecsSinceEpoch()), [this](bool success) {
bool postResult = m_awsClient->postToMQTT(url.host(), QString::number(m_timestamp.toMSecsSinceEpoch()), QPointer<QObject>(this), [this](bool success) {
if (success) {
qDebug() << "MQTT Post done. Connecting to remote proxy";
m_remoteproxyConnection->connectServer(QUrl("wss://remoteproxy.nymea.io"));