1
0
forked from blue/squawk

Message receipt manager not takes care of the message reception, switched on embedded reconnect

This commit is contained in:
Blue 2020-03-27 23:59:30 +03:00
parent 57d6e3adab
commit fe1ae8567a
7 changed files with 113 additions and 56 deletions

View File

@ -40,6 +40,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
vm(client.findExtension<QXmppVCardManager>()), vm(client.findExtension<QXmppVCardManager>()),
um(new QXmppUploadRequestManager()), um(new QXmppUploadRequestManager()),
dm(client.findExtension<QXmppDiscoveryManager>()), dm(client.findExtension<QXmppDiscoveryManager>()),
rcpm(new QXmppMessageReceiptManager()),
contacts(), contacts(),
conferences(), conferences(),
maxReconnectTimes(0), maxReconnectTimes(0),
@ -58,6 +59,7 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
config.setDomain(p_server); config.setDomain(p_server);
config.setPassword(p_password); config.setPassword(p_password);
config.setAutoAcceptSubscriptions(true); config.setAutoAcceptSubscriptions(true);
config.setAutoReconnectionEnabled(false);
QObject::connect(&client, &QXmppClient::connected, this, &Account::onClientConnected); QObject::connect(&client, &QXmppClient::connected, this, &Account::onClientConnected);
QObject::connect(&client, &QXmppClient::disconnected, this, &Account::onClientDisconnected); QObject::connect(&client, &QXmppClient::disconnected, this, &Account::onClientDisconnected);
@ -101,6 +103,10 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
QObject::connect(network, &NetworkAccess::uploadFileComplete, this, &Account::onFileUploaded); QObject::connect(network, &NetworkAccess::uploadFileComplete, this, &Account::onFileUploaded);
QObject::connect(network, &NetworkAccess::uploadFileError, this, &Account::onFileUploadError); QObject::connect(network, &NetworkAccess::uploadFileError, this, &Account::onFileUploadError);
client.addExtension(rcpm);
QObject::connect(rcpm, &QXmppMessageReceiptManager::messageDelivered, this, &Account::onReceiptReceived);
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
path += "/" + name; path += "/" + name;
QDir dir(path); QDir dir(path);
@ -160,6 +166,8 @@ Account::~Account()
delete itr->second; delete itr->second;
} }
delete rcpm;
delete dm;
delete um; delete um;
delete bm; delete bm;
delete mm; delete mm;
@ -200,8 +208,8 @@ void Core::Account::onClientConnected()
if (state == Shared::connecting) { if (state == Shared::connecting) {
reconnectTimes = maxReconnectTimes; reconnectTimes = maxReconnectTimes;
state = Shared::connected; state = Shared::connected;
cm->setCarbonsEnabled(true);
dm->requestItems(getServer()); dm->requestItems(getServer());
dm->requestInfo(getServer());
emit connectionStateChanged(state); emit connectionStateChanged(state);
} else { } else {
qDebug() << "Something weird had happened - xmpp client reported about successful connection but account wasn't in" << state << "state"; qDebug() << "Something weird had happened - xmpp client reported about successful connection but account wasn't in" << state << "state";
@ -560,14 +568,15 @@ void Core::Account::onMessageReceived(const QXmppMessage& msg)
if (itr != pendingStateMessages.end()) { if (itr != pendingStateMessages.end()) {
QString jid = itr->second; QString jid = itr->second;
RosterItem* cnt = getRosterItem(jid); RosterItem* cnt = getRosterItem(jid);
if (cnt != 0) { QMap<QString, QVariant> cData = {
cnt->changeMessageState(id, Shared::Message::State::error);
}
;
emit changeMessage(jid, id, {
{"state", static_cast<uint>(Shared::Message::State::error)}, {"state", static_cast<uint>(Shared::Message::State::error)},
{"errorText", msg.error().text()} {"errorText", msg.error().text()}
}); };
if (cnt != 0) {
cnt->changeMessage(id, cData);
}
;
emit changeMessage(jid, id, cData);
pendingStateMessages.erase(itr); pendingStateMessages.erase(itr);
handled = true; handled = true;
} else { } else {
@ -610,35 +619,43 @@ QString Core::Account::getFullJid() const
return getLogin() + "@" + getServer() + "/" + getResource(); return getLogin() + "@" + getServer() + "/" + getResource();
} }
void Core::Account::sendMessage(const Shared::Message& data) void Core::Account::sendMessage(Shared::Message data)
{ {
QString jid = data.getPenPalJid();
QString id = data.getId();
RosterItem* ri = getRosterItem(jid);
if (state == Shared::connected) { if (state == Shared::connected) {
QXmppMessage msg(getFullJid(), data.getTo(), data.getBody(), data.getThread()); QXmppMessage msg(getFullJid(), data.getTo(), data.getBody(), data.getThread());
msg.setId(data.getId()); msg.setId(id);
msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible msg.setType(static_cast<QXmppMessage::Type>(data.getType())); //it is safe here, my type is compatible
msg.setOutOfBandUrl(data.getOutOfBandUrl()); msg.setOutOfBandUrl(data.getOutOfBandUrl());
msg.setReceiptRequested(true);
RosterItem* ri = 0; bool sent = client.sendPacket(msg);
std::map<QString, Contact*>::const_iterator itr = contacts.find(data.getPenPalJid());
if (itr != contacts.end()) { if (sent) {
ri = itr->second; data.setState(Shared::Message::State::sent);
} else { } else {
std::map<QString, Conference*>::const_iterator ritr = conferences.find(data.getPenPalJid()); data.setState(Shared::Message::State::error);
if (ritr != conferences.end()) { data.setErrorText("Couldn't send message via QXMPP library check out logs");
ri = ritr->second;
}
} }
if (ri != 0) { if (ri != 0) {
ri->appendMessageToArchive(data); ri->appendMessageToArchive(data);
pendingStateMessages.insert(std::make_pair(data.getId(), data.getPenPalJid())); if (sent) {
pendingStateMessages.insert(std::make_pair(id, jid));
}
} }
client.sendPacket(msg);
} else { } else {
qDebug() << "An attempt to send message with not connected account " << name << ", skipping"; data.setState(Shared::Message::State::error);
data.setErrorText("You are is offline or reconnecting");
} }
emit changeMessage(jid, id, {
{"state", static_cast<uint>(data.getState())},
{"errorText", data.getErrorText()}
});
} }
void Core::Account::sendMessage(const Shared::Message& data, const QString& path) void Core::Account::sendMessage(const Shared::Message& data, const QString& path)
@ -659,7 +676,7 @@ void Core::Account::sendMessage(const Shared::Message& data, const QString& path
um->requestUploadSlot(file); um->requestUploadSlot(file);
} }
} else { } else {
emit onFileUploadError(data.getId(), "Uploading file dissapeared or your system user has no permission to read it"); emit onFileUploadError(data.getId(), "Uploading file no longer exists or your system user has no permission to read it");
qDebug() << "Requested upload slot in account" << name << "for file" << path << "but the file doesn't exist or is not readable"; qDebug() << "Requested upload slot in account" << name << "for file" << path << "but the file doesn't exist or is not readable";
} }
} else { } else {
@ -717,18 +734,17 @@ bool Core::Account::handleChatMessage(const QXmppMessage& msg, bool outgoing, bo
})); }));
handleNewContact(cnt); handleNewContact(cnt);
} }
if (outgoing) {
if (forwarded) {
sMsg.setState(Shared::Message::State::sent);
}
} else {
sMsg.setState(Shared::Message::State::delivered);
}
cnt->appendMessageToArchive(sMsg); cnt->appendMessageToArchive(sMsg);
emit message(sMsg); emit message(sMsg);
if (!forwarded && !outgoing) {
if (msg.isReceiptRequested() && id.size() > 0) {
QXmppMessage receipt(getFullJid(), msg.from(), "");
receipt.setReceiptId(id);
client.sendPacket(receipt);
}
}
return true; return true;
} }
return false; return false;
@ -752,9 +768,10 @@ bool Core::Account::handleGroupMessage(const QXmppMessage& msg, bool outgoing, b
std::map<QString, QString>::const_iterator pItr = pendingStateMessages.find(id); std::map<QString, QString>::const_iterator pItr = pendingStateMessages.find(id);
if (pItr != pendingStateMessages.end()) { if (pItr != pendingStateMessages.end()) {
cnt->changeMessageState(id, Shared::Message::State::delivered); QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
cnt->changeMessage(id, cData);
pendingStateMessages.erase(pItr); pendingStateMessages.erase(pItr);
emit changeMessage(jid, id, {{"state", static_cast<uint>(Shared::Message::State::delivered)}}); emit changeMessage(jid, id, cData);
} else { } else {
cnt->appendMessageToArchive(sMsg); cnt->appendMessageToArchive(sMsg);
QDateTime minAgo = QDateTime::currentDateTime().addSecs(-60); QDateTime minAgo = QDateTime::currentDateTime().addSecs(-60);
@ -765,14 +782,6 @@ bool Core::Account::handleGroupMessage(const QXmppMessage& msg, bool outgoing, b
} }
} }
if (!forwarded && !outgoing) {
if (msg.isReceiptRequested() && id.size() > 0) {
QXmppMessage receipt(getFullJid(), msg.from(), "");
receipt.setReceiptId(id);
client.sendPacket(receipt);
}
}
return true; return true;
} }
return false; return false;
@ -1658,11 +1667,32 @@ void Core::Account::onFileUploadError(const QString& messageId, const QString& e
void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items) void Core::Account::onDiscoveryItemsReceived(const QXmppDiscoveryIq& items)
{ {
for (QXmppDiscoveryIq::Item item : items.items()) { for (QXmppDiscoveryIq::Item item : items.items()) {
if (item.jid() != getServer()) {
dm->requestInfo(item.jid()); dm->requestInfo(item.jid());
} }
} }
}
void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info) void Core::Account::onDiscoveryInfoReceived(const QXmppDiscoveryIq& info)
{ {
if (info.from() == getServer()) {
if (info.features().contains("urn:xmpp:carbons:2")) {
cm->setCarbonsEnabled(true);
} }
}
}
void Core::Account::onReceiptReceived(const QString& jid, const QString& id)
{
std::map<QString, QString>::const_iterator itr = pendingStateMessages.find(id);
if (itr != pendingStateMessages.end()) {
QMap<QString, QVariant> cData = {{"state", static_cast<uint>(Shared::Message::State::delivered)}};
RosterItem* ri = getRosterItem(itr->second);
if (ri != 0) {
ri->changeMessage(id, cData);
}
pendingStateMessages.erase(itr);
emit changeMessage(itr->second, id, cData);
}
}

View File

@ -41,6 +41,8 @@
#include <QXmppHttpUploadIq.h> #include <QXmppHttpUploadIq.h>
#include <QXmppVCardIq.h> #include <QXmppVCardIq.h>
#include <QXmppVCardManager.h> #include <QXmppVCardManager.h>
#include <QXmppMessageReceiptManager.h>
#include "global.h" #include "global.h"
#include "contact.h" #include "contact.h"
#include "conference.h" #include "conference.h"
@ -76,7 +78,7 @@ public:
void setResource(const QString& p_resource); void setResource(const QString& p_resource);
void setAvailability(Shared::Availability avail); void setAvailability(Shared::Availability avail);
QString getFullJid() const; QString getFullJid() const;
void sendMessage(const Shared::Message& data); void sendMessage(Shared::Message data);
void sendMessage(const Shared::Message& data, const QString& path); void sendMessage(const Shared::Message& data, const QString& path);
void requestArchive(const QString& jid, int count, const QString& before); void requestArchive(const QString& jid, int count, const QString& before);
void setReconnectTimes(unsigned int times); void setReconnectTimes(unsigned int times);
@ -139,6 +141,7 @@ private:
QXmppVCardManager* vm; QXmppVCardManager* vm;
QXmppUploadRequestManager* um; QXmppUploadRequestManager* um;
QXmppDiscoveryManager* dm; QXmppDiscoveryManager* dm;
QXmppMessageReceiptManager* rcpm;
std::map<QString, Contact*> contacts; std::map<QString, Contact*> contacts;
std::map<QString, Conference*> conferences; std::map<QString, Conference*> conferences;
unsigned int maxReconnectTimes; unsigned int maxReconnectTimes;
@ -207,6 +210,8 @@ private slots:
void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items); void onDiscoveryItemsReceived (const QXmppDiscoveryIq& items);
void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info); void onDiscoveryInfoReceived (const QXmppDiscoveryIq& info);
void onReceiptReceived(const QString& jid, const QString &id);
private: private:
void addedAccount(const QString &bareJid); void addedAccount(const QString &bareJid);
void handleNewContact(Contact* contact); void handleNewContact(Contact* contact);

View File

@ -208,7 +208,7 @@ Shared::Message Core::Archive::getMessage(const std::string& id, MDB_txn* txn)
} }
} }
void Core::Archive::setMessageState(const QString& id, Shared::Message::State state) void Core::Archive::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
{ {
if (!opened) { if (!opened) {
throw Closed("setMessageState", jid.toStdString()); throw Closed("setMessageState", jid.toStdString());
@ -220,21 +220,42 @@ void Core::Archive::setMessageState(const QString& id, Shared::Message::State st
std::string strId(id.toStdString()); std::string strId(id.toStdString());
try { try {
Shared::Message msg = getMessage(strId, txn); Shared::Message msg = getMessage(strId, txn);
msg.setState(state); QDateTime oTime = msg.getTime();
bool idChange = msg.change(data);
MDB_val lmdbKey, lmdbData; MDB_val lmdbKey, lmdbData;
QByteArray ba; QByteArray ba;
QDataStream ds(&ba, QIODevice::WriteOnly); QDataStream ds(&ba, QIODevice::WriteOnly);
msg.serialize(ds); msg.serialize(ds);
lmdbKey.mv_size = strId.size(); lmdbKey.mv_size = strId.size();
lmdbKey.mv_data = (char*)strId.c_str(); lmdbKey.mv_data = (char*)strId.c_str();
int rc;
if (idChange) {
rc = mdb_del(txn, main, &lmdbKey, &lmdbData);
if (rc == 0) {
strId = msg.getId().toStdString();
lmdbKey.mv_size = strId.size();
lmdbKey.mv_data = (char*)strId.c_str();
quint64 stamp = oTime.toMSecsSinceEpoch();
lmdbData.mv_data = (quint8*)&stamp;
lmdbData.mv_size = 8;
rc = mdb_put(txn, order, &lmdbData, &lmdbKey, 0);
if (rc != 0) {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
} else {
throw Unknown(jid.toStdString(), mdb_strerror(rc));
}
}
lmdbData.mv_size = ba.size(); lmdbData.mv_size = ba.size();
lmdbData.mv_data = (uint8_t*)ba.data(); lmdbData.mv_data = (uint8_t*)ba.data();
int rc = mdb_put(txn, main, &lmdbKey, &lmdbData, 0); rc = mdb_put(txn, main, &lmdbKey, &lmdbData, 0);
if (rc == 0) { if (rc == 0) {
rc = mdb_txn_commit(txn); rc = mdb_txn_commit(txn);
} else { } else {
mdb_txn_abort(txn);
throw Unknown(jid.toStdString(), mdb_strerror(rc)); throw Unknown(jid.toStdString(), mdb_strerror(rc));
} }

View File

@ -24,9 +24,9 @@
#include <QMimeDatabase> #include <QMimeDatabase>
#include <QMimeType> #include <QMimeType>
#include "../global.h" #include "global.h"
#include "exception.h"
#include <lmdb.h> #include <lmdb.h>
#include "../exception.h"
#include <list> #include <list>
namespace Core { namespace Core {
@ -46,7 +46,7 @@ public:
bool addElement(const Shared::Message& message); bool addElement(const Shared::Message& message);
unsigned int addElements(const std::list<Shared::Message>& messages); unsigned int addElements(const std::list<Shared::Message>& messages);
Shared::Message getElement(const QString& id); Shared::Message getElement(const QString& id);
void setMessageState(const QString& id, Shared::Message::State state); void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
Shared::Message oldest(); Shared::Message oldest();
QString oldestId(); QString oldestId();
Shared::Message newest(); Shared::Message newest();

View File

@ -221,12 +221,12 @@ void Core::RosterItem::appendMessageToArchive(const Shared::Message& msg)
} }
} }
void Core::RosterItem::changeMessageState(const QString& id, Shared::Message::State newState) void Core::RosterItem::changeMessage(const QString& id, const QMap<QString, QVariant>& data)
{ {
bool found = false; bool found = false;
for (Shared::Message& msg : appendCache) { for (Shared::Message& msg : appendCache) {
if (msg.getId() == id) { if (msg.getId() == id) {
msg.setState(newState); msg.change(data);
found = true; found = true;
break; break;
} }
@ -235,7 +235,7 @@ void Core::RosterItem::changeMessageState(const QString& id, Shared::Message::St
if (!found) { if (!found) {
for (Shared::Message& msg : hisoryCache) { for (Shared::Message& msg : hisoryCache) {
if (msg.getId() == id) { if (msg.getId() == id) {
msg.setState(newState); msg.change(data);
found = true; found = true;
break; break;
} }
@ -244,7 +244,7 @@ void Core::RosterItem::changeMessageState(const QString& id, Shared::Message::St
if (!found) { if (!found) {
try { try {
archive->setMessageState(id, newState); archive->changeMessage(id, data);
found = true; found = true;
} catch (const Archive::NotFound& e) { } catch (const Archive::NotFound& e) {
qDebug() << "An attempt to change state to the message" << id << "but it couldn't be found"; qDebug() << "An attempt to change state to the message" << id << "but it couldn't be found";
@ -254,7 +254,7 @@ void Core::RosterItem::changeMessageState(const QString& id, Shared::Message::St
if (found) { if (found) {
for (Shared::Message& msg : responseCache) { for (Shared::Message& msg : responseCache) {
if (msg.getId() == id) { if (msg.getId() == id) {
msg.setState(newState); msg.change(data);
break; break;
} }
} }

View File

@ -72,7 +72,7 @@ public:
virtual Shared::VCard handleResponseVCard(const QXmppVCardIq& card, const QString& resource); virtual Shared::VCard handleResponseVCard(const QXmppVCardIq& card, const QString& resource);
virtual void handlePresence(const QXmppPresence& pres) = 0; virtual void handlePresence(const QXmppPresence& pres) = 0;
void changeMessageState(const QString& id, Shared::Message::State newState); void changeMessage(const QString& id, const QMap<QString, QVariant>& data);
signals: signals:
void nameChanged(const QString& name); void nameChanged(const QString& name);

View File

@ -71,6 +71,7 @@ void Chat::handleSendMessage(const QString& text)
msg.setOutgoing(true); msg.setOutgoing(true);
msg.generateRandomId(); msg.generateRandomId();
msg.setCurrentTime(); msg.setCurrentTime();
msg.setState(Shared::Message::State::pending);
addMessage(msg); addMessage(msg);
emit sendMessage(msg); emit sendMessage(msg);
} }