1
0
forked from blue/squawk

working on file upload

This commit is contained in:
Blue 2019-09-23 15:09:15 +03:00
parent 100b2e8943
commit 7c32056918
11 changed files with 326 additions and 144 deletions

View File

@ -30,6 +30,7 @@
#include <QXmppClient.h>
#include <QXmppBookmarkManager.h>
#include <QXmppBookmarkSet.h>
#include <QXmppHttpUploadIq.h>
#include "../global.h"
#include "contact.h"
#include "conference.h"

View File

@ -23,7 +23,8 @@ Core::NetworkAccess::NetworkAccess(QObject* parent):
running(false),
manager(0),
files("files"),
downloads()
downloads(),
uploads()
{
}
@ -34,9 +35,9 @@ Core::NetworkAccess::~NetworkAccess()
void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url)
{
std::map<QString, Download*>::iterator itr = downloads.find(url);
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
if (itr != downloads.end()) {
Download* dwn = itr->second;
Transfer* dwn = itr->second;
std::set<QString>::const_iterator mItr = dwn->messages.find(messageId);
if (mItr == dwn->messages.end()) {
dwn->messages.insert(messageId);
@ -63,9 +64,9 @@ void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const Q
void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QString& url)
{
std::map<QString, Download*>::iterator itr = downloads.find(url);
std::map<QString, Transfer*>::iterator itr = downloads.find(url);
if (itr != downloads.end()) {
Download* dwn = itr->second;
Transfer* dwn = itr->second;
std::set<QString>::const_iterator mItr = dwn->messages.find(messageId);
if (mItr == dwn->messages.end()) {
dwn->messages.insert(messageId);
@ -85,7 +86,7 @@ void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QSt
startDownload(messageId, url);
} catch (Archive::Unknown e) {
qDebug() << "Error requesting file path:" << e.what();
startDownload(messageId, url);
emit downloadFileError(messageId, QString("Database error: ") + e.what());
}
}
}
@ -107,7 +108,7 @@ void Core::NetworkAccess::stop()
manager = 0;
running = false;
for (std::map<QString, Download*>::const_iterator itr = downloads.begin(), end = downloads.end(); itr != end; ++itr) {
for (std::map<QString, Transfer*>::const_iterator itr = downloads.begin(), end = downloads.end(); itr != end; ++itr) {
itr->second->success = false;
itr->second->reply->abort(); //assuming it's gonna call onRequestFinished slot
}
@ -118,11 +119,11 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
{
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
if (itr == downloads.end()) {
qDebug() << "an error downloading" << url << ": the request had some progress but seems like noone is waiting for it, skipping";
} else {
Download* dwn = itr->second;
Transfer* dwn = itr->second;
qreal received = bytesReceived;
qreal total = bytesTotal;
qreal progress = received/total;
@ -133,15 +134,28 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
}
}
void Core::NetworkAccess::onRequestError(QNetworkReply::NetworkError code)
void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
{
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
if (itr == downloads.end()) {
qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping";
} else {
QString errorText;
QString errorText = getErrorText(code);
if (errorText.size() > 0) {
itr->second->success = false;
Transfer* dwn = itr->second;
for (std::set<QString>::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) {
emit downloadFileError(*mItr, errorText);
}
}
}
}
QString Core::NetworkAccess::getErrorText(QNetworkReply::NetworkError code)
{
QString errorText("");
switch (code) {
case QNetworkReply::NoError:
//this never is supposed to happen
@ -256,26 +270,20 @@ void Core::NetworkAccess::onRequestError(QNetworkReply::NetworkError code)
errorText = "Unknown server error";
break;
}
if (errorText.size() > 0) {
itr->second->success = false;
Download* dwn = itr->second;
for (std::set<QString>::const_iterator mItr = dwn->messages.begin(), end = dwn->messages.end(); mItr != end; ++mItr) {
emit downloadFileError(*mItr, errorText);
}
}
}
return errorText;
}
void Core::NetworkAccess::onRequestFinished()
void Core::NetworkAccess::onDownloadFinished()
{
QString path("");
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Download*>::const_iterator itr = downloads.find(url);
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
if (itr == downloads.end()) {
qDebug() << "an error downloading" << url << ": the request is done but seems like noone is waiting for it, skipping";
} else {
Download* dwn = itr->second;
Transfer* dwn = itr->second;
if (dwn->success) {
qDebug() << "download success for" << url;
QStringList hops = url.split("/");
@ -320,13 +328,130 @@ void Core::NetworkAccess::onRequestFinished()
void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url)
{
Download* dwn = new Download({{messageId}, 0, 0, true});
Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", 0});
QNetworkRequest req(url);
dwn->reply = manager->get(req);
connect(dwn->reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(onDownloadProgress(qint64, qint64)));
connect(dwn->reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onRequestError(QNetworkReply::NetworkError)));
connect(dwn->reply, SIGNAL(finished()), SLOT(onRequestFinished()));
connect(dwn->reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onDownloadError(QNetworkReply::NetworkError)));
connect(dwn->reply, SIGNAL(finished()), SLOT(onDownloadFinished()));
downloads.insert(std::make_pair(url, dwn));
emit downloadFileProgress(messageId, 0);
}
void Core::NetworkAccess::onUploadError(QNetworkReply::NetworkError code)
{
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
if (itr == uploads.end()) {
qDebug() << "an error uploading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping";
} else {
QString errorText = getErrorText(code);
if (errorText.size() > 0) {
itr->second->success = false;
Transfer* upl = itr->second;
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
emit uploadFileError(*mItr, errorText);
}
}
}
}
void Core::NetworkAccess::onUploadFinished()
{
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
if (itr == downloads.end()) {
qDebug() << "an error uploading" << url << ": the request is done but seems like noone is waiting for it, skipping";
} else {
Transfer* upl = itr->second;
if (upl->success) {
qDebug() << "upload success for" << url;
files.addRecord(url, upl->path);
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
emit fileLocalPathResponse(*mItr, upl->path);
}
}
upl->reply->deleteLater();
upl->file->close();
upl->file->deleteLater();
delete upl;
uploads.erase(itr);
}
}
void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
QNetworkReply* rpl = static_cast<QNetworkReply*>(sender());
QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
if (itr == uploads.end()) {
qDebug() << "an error downloading" << url << ": the request had some progress but seems like noone is waiting for it, skipping";
} else {
Transfer* upl = itr->second;
qreal received = bytesReceived;
qreal total = bytesTotal;
qreal progress = received/total;
upl->progress = progress;
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
emit uploadFileProgress(*mItr, progress);
}
}
}
void Core::NetworkAccess::startUpload(const QString& messageId, const QString& url, const QString& path)
{
Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, 0});
QNetworkRequest req(url);
QFile* file = new QFile(path);
if (file->open(QIODevice::ReadOnly)) {
upl->reply = manager->put(req, file);
connect(upl->reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(onUploadProgress(qint64, qint64)));
connect(upl->reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onUploadError(QNetworkReply::NetworkError)));
connect(upl->reply, SIGNAL(finished()), SLOT(onUploadFinished()));
uploads.insert(std::make_pair(url, upl));
emit downloadFileProgress(messageId, 0);
} else {
qDebug() << "couldn't upload file" << path;
emit uploadFileError(messageId, "Error opening file");
delete file;
}
}
void Core::NetworkAccess::uploadFileRequest(const QString& messageId, const QString& url, const QString& path)
{
std::map<QString, Transfer*>::iterator itr = uploads.find(url);
if (itr != uploads.end()) {
Transfer* upl = itr->second;
std::set<QString>::const_iterator mItr = upl->messages.find(messageId);
if (mItr == upl->messages.end()) {
upl->messages.insert(messageId);
}
emit uploadFileProgress(messageId, upl->progress);
} else {
try {
QString ePath = files.getRecord(url);
if (ePath == path) {
emit fileLocalPathResponse(messageId, path);
} else {
files.changeRecord(url, path);
}
QFileInfo info(path);
if (info.exists() && info.isFile()) {
emit fileLocalPathResponse(messageId, path);
} else {
files.removeRecord(url);
startDownload(messageId, url);
}
} catch (Archive::NotFound e) {
startUpload(messageId, url, path);
} catch (Archive::Unknown e) {
qDebug() << "Error requesting file path on upload:" << e.what();
emit uploadFileError(messageId, QString("Database error: ") + e.what());
}
}
}

View File

@ -39,7 +39,7 @@ namespace Core {
class NetworkAccess : public QObject
{
Q_OBJECT
struct Download;
struct Transfer;
public:
NetworkAccess(QObject* parent = nullptr);
virtual ~NetworkAccess();
@ -51,30 +51,41 @@ signals:
void fileLocalPathResponse(const QString& messageId, const QString& path);
void downloadFileProgress(const QString& messageId, qreal value);
void downloadFileError(const QString& messageId, const QString& path);
void uploadFileProgress(const QString& messageId, qreal value);
void uploadFileError(const QString& messageId, const QString& path);
public slots:
void fileLocalPathRequest(const QString& messageId, const QString& url);
void downladFileRequest(const QString& messageId, const QString& url);
void uploadFileRequest(const QString& messageId, const QString& url, const QString& path);
private:
void startDownload(const QString& messageId, const QString& url);
void startUpload(const QString& messageId, const QString& url, const QString& path);
QString getErrorText(QNetworkReply::NetworkError code);
private slots:
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void onRequestError(QNetworkReply::NetworkError code);
void onRequestFinished();
void onDownloadError(QNetworkReply::NetworkError code);
void onDownloadFinished();
void onUploadProgress(qint64 bytesReceived, qint64 bytesTotal);
void onUploadError(QNetworkReply::NetworkError code);
void onUploadFinished();
private:
bool running;
QNetworkAccessManager* manager;
Storage files;
std::map<QString, Download*> downloads;
std::map<QString, Transfer*> downloads;
std::map<QString, Transfer*> uploads;
struct Download {
struct Transfer {
std::set<QString> messages;
qreal progress;
QNetworkReply* reply;
bool success;
QString path;
QFile* file;
};
};

View File

@ -31,6 +31,8 @@ Core::Squawk::Squawk(QObject* parent):
connect(&network, SIGNAL(fileLocalPathResponse(const QString&, const QString&)), this, SIGNAL(fileLocalPathResponse(const QString&, const QString&)));
connect(&network, SIGNAL(downloadFileProgress(const QString&, qreal)), this, SIGNAL(downloadFileProgress(const QString&, qreal)));
connect(&network, SIGNAL(downloadFileError(const QString&, const QString&)), this, SIGNAL(downloadFileError(const QString&, const QString&)));
connect(&network, SIGNAL(uploadFileProgress(const QString&, qreal)), this, SIGNAL(uploadFileProgress(const QString&, qreal)));
connect(&network, SIGNAL(uploadFileError(const QString&, const QString&)), this, SIGNAL(uploadFileError(const QString&, const QString&)));
}
Core::Squawk::~Squawk()
@ -276,6 +278,11 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da
itr->second->sendMessage(data);
}
void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data, const QString& path)
{
}
void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before)
{
AccountsMap::const_iterator itr = amap.find(account);
@ -368,7 +375,6 @@ void Core::Squawk::removeAccountRequest(const QString& name)
acc->deleteLater();
}
void Core::Squawk::subscribeContact(const QString& account, const QString& jid, const QString& reason)
{
AccountsMap::const_iterator itr = amap.find(account);

View File

@ -65,6 +65,8 @@ signals:
void fileLocalPathResponse(const QString& messageId, const QString& path);
void downloadFileError(const QString& messageId, const QString& error);
void downloadFileProgress(const QString& messageId, qreal value);
void uploadFileError(const QString& messageId, const QString& error);
void uploadFileProgress(const QString& messageId, qreal value);
public slots:
void start();
@ -76,6 +78,7 @@ public slots:
void disconnectAccount(const QString& account);
void changeState(int state);
void sendMessage(const QString& account, const Shared::Message& data);
void sendMessage(const QString& account, const Shared::Message& data, const QString& path);
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);

View File

@ -73,7 +73,7 @@ void Core::Storage::close()
void Core::Storage::addRecord(const QString& key, const QString& value)
{
if (!opened) {
throw Archive::Closed("addElement", name.toStdString());
throw Archive::Closed("addRecord", name.toStdString());
}
const std::string& id = key.toStdString();
const std::string& val = value.toStdString();
@ -99,6 +99,33 @@ void Core::Storage::addRecord(const QString& key, const QString& value)
}
}
void Core::Storage::changeRecord(const QString& key, const QString& value)
{
if (!opened) {
throw Archive::Closed("changeRecord", name.toStdString());
}
const std::string& id = key.toStdString();
const std::string& val = value.toStdString();
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.c_str();
lmdbData.mv_size = val.size();
lmdbData.mv_data = (char*)val.c_str();
MDB_txn *txn;
mdb_txn_begin(environment, NULL, 0, &txn);
int rc;
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, 0);
if (rc != 0) {
mdb_txn_abort(txn);
if (rc) {
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
}
} else {
mdb_txn_commit(txn);
}
}
QString Core::Storage::getRecord(const QString& key) const
{
if (!opened) {

View File

@ -39,6 +39,7 @@ public:
void close();
void addRecord(const QString& key, const QString& value);
void changeRecord(const QString& key, const QString& value);
void removeRecord(const QString& key);
QString getRecord(const QString& key) const;

View File

@ -70,6 +70,8 @@ int main(int argc, char *argv[])
QObject::connect(&w, SIGNAL(disconnectAccount(const QString&)), squawk, SLOT(disconnectAccount(const QString&)));
QObject::connect(&w, SIGNAL(changeState(int)), squawk, SLOT(changeState(int)));
QObject::connect(&w, SIGNAL(sendMessage(const QString&, const Shared::Message&)), squawk, SLOT(sendMessage(const QString&, const Shared::Message&)));
QObject::connect(&w, SIGNAL(sendMessage(const QString&, const Shared::Message&, const QString&)),
squawk, SLOT(sendMessage(const QString&, const Shared::Message&, const QString&)));
QObject::connect(&w, SIGNAL(requestArchive(const QString&, const QString&, int, const QString&)),
squawk, SLOT(requestArchive(const QString&, const QString&, int, const QString&)));
QObject::connect(&w, SIGNAL(subscribeContact(const QString&, const QString&, const QString&)),
@ -125,9 +127,6 @@ int main(int argc, char *argv[])
QObject::connect(squawk, SIGNAL(downloadFileProgress(const QString&, qreal)), &w, SLOT(downloadFileProgress(const QString&, qreal)));
QObject::connect(squawk, SIGNAL(downloadFileError(const QString&, const QString&)), &w, SLOT(downloadFileError(const QString&, const QString&)));
//qDebug() << QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
coreThread->start();
int result = app.exec();

View File

@ -285,6 +285,7 @@ void Squawk::onRosterItemDoubleClicked(const QModelIndex& item)
connect(conv, SIGNAL(destroyed(QObject*)), this, SLOT(onConversationClosed(QObject*)));
connect(conv, SIGNAL(sendMessage(const Shared::Message&)), this, SLOT(onConversationMessage(const Shared::Message&)));
connect(conv, SIGNAL(sendMessage(const Shared::Message&, const QString&)), this, SLOT(onConversationMessage(const Shared::Message&, const QString&)));
connect(conv, SIGNAL(requestArchive(const QString&)), this, SLOT(onConversationRequestArchive(const QString&)));
connect(conv, SIGNAL(requestLocalFile(const QString&, const QString&)), this, SLOT(onConversationRequestLocalFile(const QString&, const QString&)));
connect(conv, SIGNAL(downloadFile(const QString&, const QString&)), this, SLOT(onConversationDownloadFile(const QString&, const QString&)));
@ -468,10 +469,15 @@ void Squawk::notify(const QString& account, const Shared::Message& msg)
void Squawk::onConversationMessage(const Shared::Message& msg)
{
Conversation* conv = static_cast<Conversation*>(sender());
emit sendMessage(conv->getAccount(), msg);
}
void Squawk::onConversationMessage(const Shared::Message& msg, const QString& path)
{
Conversation* conv = static_cast<Conversation*>(sender());
emit sendMessage(conv->getAccount(), msg, path);
}
void Squawk::onConversationRequestArchive(const QString& before)
{
Conversation* conv = static_cast<Conversation*>(sender());

View File

@ -57,6 +57,7 @@ signals:
void disconnectAccount(const QString&);
void changeState(int state);
void sendMessage(const QString& account, const Shared::Message& data);
void sendMessage(const QString& account, const Shared::Message& data, const QString& path);
void requestArchive(const QString& account, const QString& jid, int count, const QString& before);
void subscribeContact(const QString& account, const QString& jid, const QString& reason);
void unsubscribeContact(const QString& account, const QString& jid, const QString& reason);
@ -121,6 +122,7 @@ private slots:
void onComboboxActivated(int index);
void onRosterItemDoubleClicked(const QModelIndex& item);
void onConversationMessage(const Shared::Message& msg);
void onConversationMessage(const Shared::Message& msg, const QString& path);
void onConversationRequestArchive(const QString& before);
void onRosterContextMenu(const QPoint& point);
void onConversationShown();

View File

@ -80,6 +80,7 @@ public:
signals:
void sendMessage(const Shared::Message& message);
void sendMessage(const Shared::Message& message, const QString& path);
void requestArchive(const QString& before);
void shown();
void requestLocalFile(const QString& messageId, const QString& url);