Skip to content
This repository has been archived by the owner on Feb 12, 2023. It is now read-only.

Commit

Permalink
fix(receipts): Prevent double message send for received receipt
Browse files Browse the repository at this point in the history
Fixes #2726
Register for receipt handling only once, cache receipts that are received before message is writen to history and mark a message as sent once both its receipt has been received and it has been writen to history
  • Loading branch information
anthonybilinski committed Sep 7, 2017
1 parent 89198f5 commit e9d6339
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 15 deletions.
1 change: 0 additions & 1 deletion src/nexus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ void Nexus::showMainGUI()
connect(core, &Core::friendStatusMessageChanged, widget, &Widget::onFriendStatusMessageChanged);
connect(core, &Core::friendRequestReceived, widget, &Widget::onFriendRequestReceived);
connect(core, &Core::friendMessageReceived, widget, &Widget::onFriendMessageReceived);
connect(core, &Core::receiptRecieved, widget, &Widget::onReceiptRecieved);
connect(core, &Core::groupInviteReceived, widget, &Widget::onGroupInviteReceived);
connect(core, &Core::groupMessageReceived, widget, &Widget::onGroupMessageReceived);
connect(core, &Core::groupNamelistChanged, widget, &Widget::onGroupNamelistChanged);
Expand Down
68 changes: 56 additions & 12 deletions src/persistence/offlinemsgengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "src/persistence/settings.h"
#include <QMutexLocker>
#include <QTimer>
#include <QCoreApplication>

/**
* @var static const int OfflineMsgEngine::offlineTimeout
Expand Down Expand Up @@ -52,28 +53,31 @@ void OfflineMsgEngine::dischargeReceipt(int receipt)
{
QMutexLocker ml(&mutex);

Profile* profile = Nexus::getProfile();
auto it = receipts.find(receipt);
if (it != receipts.end()) {
int mID = it.value();
auto msgIt = undeliveredMsgs.find(mID);
if (msgIt != undeliveredMsgs.end()) {
if (profile->isHistoryEnabled())
profile->getHistory()->markAsSent(mID);
msgIt.value().msg->markAsSent(QDateTime::currentDateTime());
undeliveredMsgs.erase(msgIt);
}
receipts.erase(it);
if (it == receipts.end()) {
it = receipts.insert(receipt, Receipt());
} else if (it->bRecepitReceived) {
qWarning() << "Received duplicate receipt";
}
it->bRecepitReceived = true;
processReceipt(receipt);
}

void OfflineMsgEngine::registerReceipt(int receipt, int64_t messageID, ChatMessage::Ptr msg,
const QDateTime& timestamp)
{
QMutexLocker ml(&mutex);

receipts[receipt] = messageID;
auto it = receipts.find(receipt);
if (it == receipts.end()) {
it = receipts.insert(receipt, Receipt());
} else if (it->bRowValid && receipt != 0 /* offline receipt */) {
qWarning() << "Received duplicate registration of receipt";
}
it->rowId = messageID;
it->bRowValid = true;
undeliveredMsgs[messageID] = {msg, timestamp, receipt};
processReceipt(receipt);
}

void OfflineMsgEngine::deliverOfflineMsgs()
Expand Down Expand Up @@ -119,3 +123,43 @@ void OfflineMsgEngine::removeAllReceipts()

receipts.clear();
}

void OfflineMsgEngine::updateTimestamp(int receiptId)
{
QMutexLocker ml(&mutex);

auto receipt = receipts.find(receiptId);
const auto msg = undeliveredMsgs.constFind(receipt->rowId);
if (msg == undeliveredMsgs.end()) {
// this should never occur as registerReceipt adds the msg before processReceipt calls updateTimestamp
qCritical() << "Message was not in undeliveredMsgs map when attempting to update its timestamp!";
return;
}
msg->msg->markAsSent(QDateTime::currentDateTime());
undeliveredMsgs.remove(receipt->rowId);
receipts.erase(receipt);
}

void OfflineMsgEngine::processReceipt(int receiptId)
{
const auto receipt = receipts.constFind(receiptId);
if (receipt == receipts.end()) {
// this should never occur as callers ensure receipts contains receiptId
qCritical() << "Receipt was not added to map prior to attempting to process it!";
return;
}

if (!receipt->bRecepitReceived || !receipt->bRowValid)
return;

Profile* const profile = Nexus::getProfile();
if (profile->isHistoryEnabled()) {
profile->getHistory()->markAsSent(receipt->rowId);
}

if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
updateTimestamp(receiptId);
} else {
QMetaObject::invokeMethod(this, "updateTimestamp", Qt::QueuedConnection, Q_ARG(int, receiptId));
}
}
12 changes: 10 additions & 2 deletions src/persistence/offlinemsgengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,26 @@ class OfflineMsgEngine : public QObject
public slots:
void deliverOfflineMsgs();
void removeAllReceipts();
void updateTimestamp(int receiptId);

private:
void processReceipt(int receiptId);
struct Receipt
{
bool bRowValid{false};
int64_t rowId{0};
bool bRecepitReceived{false};
};

struct MsgPtr
{
ChatMessage::Ptr msg;
QDateTime timestamp;
int receipt;
};

QMutex mutex;
Friend* f;
QHash<int, int64_t> receipts;
QHash<int, Receipt> receipts;
QMap<int64_t, MsgPtr> undeliveredMsgs;

static const int offlineTimeout;
Expand Down

0 comments on commit e9d6339

Please sign in to comment.