fileUpload #30

Manually merged
blue merged 7 commits from fileUpload into master 2019-11-16 18:03:48 +00:00
5 changed files with 164 additions and 16 deletions
Showing only changes of commit 3f710e26d0 - Show all commits

View File

@ -23,7 +23,7 @@
using namespace Core; using namespace Core;
Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent): Account::Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, NetworkAccess* p_net, QObject* parent):
QObject(parent), QObject(parent),
name(p_name), name(p_name),
achiveQueries(), achiveQueries(),
@ -38,15 +38,19 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
bm(new QXmppBookmarkManager()), bm(new QXmppBookmarkManager()),
rm(client.findExtension<QXmppRosterManager>()), rm(client.findExtension<QXmppRosterManager>()),
vm(client.findExtension<QXmppVCardManager>()), vm(client.findExtension<QXmppVCardManager>()),
um(new QXmppUploadRequestManager()),
contacts(), contacts(),
conferences(), conferences(),
maxReconnectTimes(0), maxReconnectTimes(0),
reconnectTimes(0), reconnectTimes(0),
queuedContacts(), queuedContacts(),
outOfRosterContacts(), outOfRosterContacts(),
pendingMessages(),
uploadingSlotsQueue(),
avatarHash(), avatarHash(),
avatarType(), avatarType(),
ownVCardRequestInProgress(false) ownVCardRequestInProgress(false),
network(p_net)
{ {
config.setUser(p_login); config.setUser(p_login);
config.setDomain(p_server); config.setDomain(p_server);
@ -85,6 +89,10 @@ Account::Account(const QString& p_login, const QString& p_server, const QString&
QObject::connect(vm, &QXmppVCardManager::vCardReceived, this, &Account::onVCardReceived); QObject::connect(vm, &QXmppVCardManager::vCardReceived, this, &Account::onVCardReceived);
//QObject::connect(&vm, &QXmppVCardManager::clientVCardReceived, this, &Account::onOwnVCardReceived); //for some reason it doesn't work, launching from common handler //QObject::connect(&vm, &QXmppVCardManager::clientVCardReceived, this, &Account::onOwnVCardReceived); //for some reason it doesn't work, launching from common handler
client.addExtension(um);
QObject::connect(um, &QXmppUploadRequestManager::slotReceived, this, &Account::onUploadSlotReceived);
QObject::connect(um, &QXmppUploadRequestManager::requestFailed, this, &Account::onUploadSlotRequestFailed);
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
path += "/" + name; path += "/" + name;
QDir dir(path); QDir dir(path);
@ -141,6 +149,7 @@ Account::~Account()
delete itr->second; delete itr->second;
} }
delete um;
delete bm; delete bm;
delete mm; delete mm;
delete am; delete am;
@ -623,6 +632,44 @@ void Core::Account::sendMessage(const Shared::Message& data)
} }
} }
void Core::Account::sendMessage(const Shared::Message& data, const QString& path)
{
if (state == Shared::connected) {
QString url = network->getFileRemoteUrl(path);
if (url.size() != 0) {
sendMessageWithLocalUploadedFile(data, url);
} else {
if (network->isUploading(path, data.getId())) {
pendingMessages.emplace(data.getId(), data);
} else {
if (um->serviceFound()) {
QFileInfo file(path);
if (file.exists() && file.isReadable()) {
uploadingSlotsQueue.emplace_back(path, data);
if (uploadingSlotsQueue.size() == 1) {
um->requestUploadSlot(file);
}
} else {
qDebug() << "Requested upload slot in account" << name << "for file" << path << "but the file doesn't exist or is not readable";
}
} else {
qDebug() << "Requested upload slot in account" << name << "for file" << path << "but upload manager didn't discover any upload services";
}
}
}
} else {
qDebug() << "An attempt to send message with not connected account " << name << ", skipping";
}
}
void Core::Account::sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url)
{
msg.setOutOfBandUrl(url);
sendMessage(msg);
//TODO removal/progress update
}
void Core::Account::onCarbonMessageReceived(const QXmppMessage& msg) void Core::Account::onCarbonMessageReceived(const QXmppMessage& msg)
{ {
handleChatMessage(msg, false, true); handleChatMessage(msg, false, true);
@ -1551,3 +1598,45 @@ void Core::Account::uploadVCard(const Shared::VCard& card)
vm->setClientVCard(iq); vm->setClientVCard(iq);
onOwnVCardReceived(iq); onOwnVCardReceived(iq);
} }
void Core::Account::onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot)
{
if (uploadingSlotsQueue.size() == 0) {
qDebug() << "HTTP Upload manager of account" << name << "reports about success requesting upload slot, but none was requested";
} else {
const std::pair<QString, Shared::Message>& pair = uploadingSlotsQueue.front();
const QString& mId = pair.second.getId();
network->uploadFile(mId, pair.first, slot.putUrl(), slot.getUrl(), slot.putHeaders());
pendingMessages.emplace(mId, pair.second);
uploadingSlotsQueue.pop_front();
if (uploadingSlotsQueue.size() > 0) {
um->requestUploadSlot(uploadingSlotsQueue.front().first);
}
}
}
void Core::Account::onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request)
{
if (uploadingSlotsQueue.size() == 0) {
qDebug() << "HTTP Upload manager of account" << name << "reports about an error requesting upload slot, but none was requested";
qDebug() << request.error().text();
} else {
const std::pair<QString, Shared::Message>& pair = uploadingSlotsQueue.front();
qDebug() << "Error requesting upload slot for file" << pair.first << "in account" << name << ":" << request.error().text();
if (uploadingSlotsQueue.size() > 0) {
um->requestUploadSlot(uploadingSlotsQueue.front().first);
}
uploadingSlotsQueue.pop_front();
}
}
void Core::Account::onFileUploaded(const QString& messageId, const QString& url)
{
std::map<QString, Shared::Message>::const_iterator itr = pendingMessages.find(messageId);
if (itr != pendingMessages.end()) {
sendMessageWithLocalUploadedFile(itr->second, url);
pendingMessages.erase(itr);
}
}

View File

@ -36,12 +36,14 @@
#include <QXmppClient.h> #include <QXmppClient.h>
#include <QXmppBookmarkManager.h> #include <QXmppBookmarkManager.h>
#include <QXmppBookmarkSet.h> #include <QXmppBookmarkSet.h>
#include <QXmppUploadRequestManager.h>
#include <QXmppHttpUploadIq.h> #include <QXmppHttpUploadIq.h>
#include <QXmppVCardIq.h> #include <QXmppVCardIq.h>
#include <QXmppVCardManager.h> #include <QXmppVCardManager.h>
#include "../global.h" #include "global.h"
#include "contact.h" #include "contact.h"
#include "conference.h" #include "conference.h"
#include "networkaccess.h"
namespace Core namespace Core
{ {
@ -50,7 +52,7 @@ class Account : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, QObject* parent = 0); Account(const QString& p_login, const QString& p_server, const QString& p_password, const QString& p_name, NetworkAccess* p_net, QObject* parent = 0);
~Account(); ~Account();
void connect(); void connect();
@ -74,6 +76,7 @@ public:
void setAvailability(Shared::Availability avail); void setAvailability(Shared::Availability avail);
QString getFullJid() const; QString getFullJid() const;
void sendMessage(const Shared::Message& data); void sendMessage(const Shared::Message& data);
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);
void subscribeToContact(const QString& jid, const QString& reason); void subscribeToContact(const QString& jid, const QString& reason);
@ -113,6 +116,7 @@ signals:
void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data); void changeRoomParticipant(const QString& jid, const QString& nickName, const QMap<QString, QVariant>& data);
void removeRoomParticipant(const QString& jid, const QString& nickName); void removeRoomParticipant(const QString& jid, const QString& nickName);
void receivedVCard(const QString& jid, const Shared::VCard& card); void receivedVCard(const QString& jid, const Shared::VCard& card);
void uploadFile(const QFileInfo& file, const QUrl& set, const QUrl& get, QMap<QString, QString> headers);
private: private:
QString name; QString name;
@ -128,6 +132,7 @@ private:
QXmppBookmarkManager* bm; QXmppBookmarkManager* bm;
QXmppRosterManager* rm; QXmppRosterManager* rm;
QXmppVCardManager* vm; QXmppVCardManager* vm;
QXmppUploadRequestManager* um;
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;
@ -136,10 +141,13 @@ private:
std::map<QString, QString> queuedContacts; std::map<QString, QString> queuedContacts;
std::set<QString> outOfRosterContacts; std::set<QString> outOfRosterContacts;
std::set<QString> pendingVCardRequests; std::set<QString> pendingVCardRequests;
std::map<QString, Shared::Message> pendingMessages;
std::deque<std::pair<QString, Shared::Message>> uploadingSlotsQueue;
QString avatarHash; QString avatarHash;
QString avatarType; QString avatarType;
bool ownVCardRequestInProgress; bool ownVCardRequestInProgress;
NetworkAccess* network;
private slots: private slots:
void onClientConnected(); void onClientConnected();
@ -185,6 +193,11 @@ private slots:
void onVCardReceived(const QXmppVCardIq& card); void onVCardReceived(const QXmppVCardIq& card);
void onOwnVCardReceived(const QXmppVCardIq& card); void onOwnVCardReceived(const QXmppVCardIq& card);
void onUploadSlotReceived(const QXmppHttpUploadSlotIq& slot);
void onUploadSlotRequestFailed(const QXmppHttpUploadRequestIq& request);
void onFileUploaded(const QString& messageId, const QString& url);
void onFileUploadError(const QString& messageId, const QString& path);
private: private:
void addedAccount(const QString &bareJid); void addedAccount(const QString &bareJid);
void handleNewContact(Contact* contact); void handleNewContact(Contact* contact);
@ -200,7 +213,7 @@ private:
void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: "); void logMessage(const QXmppMessage& msg, const QString& reason = "Message wasn't handled: ");
void storeConferences(); void storeConferences();
void clearConferences(); void clearConferences();
void sendMessageWithLocalUploadedFile(Shared::Message msg, const QString& url);
}; };
void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card); void initializeVCard(Shared::VCard& vCard, const QXmppVCardIq& card);

View File

@ -121,7 +121,7 @@ void Core::NetworkAccess::onDownloadProgress(qint64 bytesReceived, qint64 bytesT
QString url = rpl->url().toString(); QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url); std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
if (itr == downloads.end()) { if (itr == downloads.end()) {
qDebug() << "an error downloading" << url << ": the request had some progress but seems like noone is waiting for it, skipping"; qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
} else { } else {
Transfer* dwn = itr->second; Transfer* dwn = itr->second;
qreal received = bytesReceived; qreal received = bytesReceived;
@ -140,7 +140,7 @@ void Core::NetworkAccess::onDownloadError(QNetworkReply::NetworkError code)
QString url = rpl->url().toString(); QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = downloads.find(url); std::map<QString, Transfer*>::const_iterator itr = downloads.find(url);
if (itr == downloads.end()) { if (itr == downloads.end()) {
qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like noone is waiting for it, skipping"; qDebug() << "an error downloading" << url << ": the request is reporting an error but seems like no one is waiting for it, skipping";
} else { } else {
QString errorText = getErrorText(code); QString errorText = getErrorText(code);
if (errorText.size() > 0) { if (errorText.size() > 0) {
@ -328,7 +328,7 @@ void Core::NetworkAccess::onDownloadFinished()
void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url) void Core::NetworkAccess::startDownload(const QString& messageId, const QString& url)
{ {
Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", 0}); Transfer* dwn = new Transfer({{messageId}, 0, 0, true, "", url, 0});
QNetworkRequest req(url); QNetworkRequest req(url);
dwn->reply = manager->get(req); dwn->reply = manager->get(req);
connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress); connect(dwn->reply, &QNetworkReply::downloadProgress, this, &NetworkAccess::onDownloadProgress);
@ -363,15 +363,16 @@ void Core::NetworkAccess::onUploadFinished()
QString url = rpl->url().toString(); QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url); std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
if (itr == downloads.end()) { if (itr == downloads.end()) {
qDebug() << "an error uploading" << url << ": the request is done but seems like noone is waiting for it, skipping"; qDebug() << "an error uploading" << url << ": the request is done but seems like no one is waiting for it, skipping";
} else { } else {
Transfer* upl = itr->second; Transfer* upl = itr->second;
if (upl->success) { if (upl->success) {
qDebug() << "upload success for" << url; qDebug() << "upload success for" << url;
files.addRecord(url, upl->path); files.addRecord(upl->url, upl->path);
for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) { for (std::set<QString>::const_iterator mItr = upl->messages.begin(), end = upl->messages.end(); mItr != end; ++mItr) {
emit fileLocalPathResponse(*mItr, upl->path); emit fileLocalPathResponse(*mItr, upl->path);
emit uploadFileComplete(*mItr, upl->url);
} }
} }
@ -389,7 +390,7 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot
QString url = rpl->url().toString(); QString url = rpl->url().toString();
std::map<QString, Transfer*>::const_iterator itr = uploads.find(url); std::map<QString, Transfer*>::const_iterator itr = uploads.find(url);
if (itr == uploads.end()) { if (itr == uploads.end()) {
qDebug() << "an error downloading" << url << ": the request had some progress but seems like noone is waiting for it, skipping"; qDebug() << "an error downloading" << url << ": the request had some progress but seems like no one is waiting for it, skipping";
} else { } else {
Transfer* upl = itr->second; Transfer* upl = itr->second;
qreal received = bytesReceived; qreal received = bytesReceived;
@ -404,15 +405,15 @@ void Core::NetworkAccess::onUploadProgress(qint64 bytesReceived, qint64 bytesTot
void Core::NetworkAccess::startUpload(const QString& messageId, const QString& url, const QString& path) void Core::NetworkAccess::startUpload(const QString& messageId, const QString& url, const QString& path)
{ {
Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, 0}); Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, url, 0});
QNetworkRequest req(url); QNetworkRequest req(url);
QFile* file = new QFile(path); QFile* file = new QFile(path);
if (file->open(QIODevice::ReadOnly)) { if (file->open(QIODevice::ReadOnly)) {
upl->reply = manager->put(req, file); upl->reply = manager->put(req, file);
connect(upl->reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(onUploadProgress(qint64, qint64))); connect(upl->reply, &QNetworkReply::uploadProgress, this, &NetworkAccess::onUploadProgress);
connect(upl->reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(onUploadError(QNetworkReply::NetworkError))); connect(upl->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onUploadError);
connect(upl->reply, SIGNAL(finished()), SLOT(onUploadFinished())); connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished);
uploads.insert(std::make_pair(url, upl)); uploads.insert(std::make_pair(url, upl));
emit downloadFileProgress(messageId, 0); emit downloadFileProgress(messageId, 0);
} else { } else {
@ -455,3 +456,36 @@ void Core::NetworkAccess::uploadFileRequest(const QString& messageId, const QStr
} }
} }
} }
QString Core::NetworkAccess::getFileRemoteUrl(const QString& path)
{
return ""; //TODO this is a way not to upload some file more then 1 time, here I'm supposed to return that file GET url
}
bool Core::NetworkAccess::isUploading(const QString& path, const QString& messageId)
{
return false; //TODO this is a way to avoid parallel uploading of the same files by different chats
// message is is supposed to be added to the uploading messageids list
// the result should be true if there was an uploading file with this path
// message id can be empty, then it's just to check and not to add
}
void Core::NetworkAccess::uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap<QString, QString> headers)
{
Transfer* upl = new Transfer({{messageId}, 0, 0, true, path, get.toString(), 0});
QNetworkRequest req(put);
QFile* file = new QFile(path);
if (file->open(QIODevice::ReadOnly)) {
upl->reply = manager->put(req, file);
connect(upl->reply, &QNetworkReply::uploadProgress, this, &NetworkAccess::onUploadProgress);
connect(upl->reply, qOverload<QNetworkReply::NetworkError>(&QNetworkReply::error), this, &NetworkAccess::onUploadError);
connect(upl->reply, &QNetworkReply::finished, this, &NetworkAccess::onUploadFinished);
uploads.insert(std::make_pair(put.toString(), upl));
emit downloadFileProgress(messageId, 0);
} else {
qDebug() << "couldn't upload file" << path;
emit uploadFileError(messageId, "Error opening file");
delete file;
}
}

View File

@ -47,12 +47,17 @@ public:
void start(); void start();
void stop(); void stop();
QString getFileRemoteUrl(const QString& path);
bool isUploading(const QString& path, const QString& messageId = "");
void uploadFile(const QString& messageId, const QString& path, const QUrl& put, const QUrl& get, const QMap<QString, QString> headers);
signals: signals:
void fileLocalPathResponse(const QString& messageId, const QString& path); void fileLocalPathResponse(const QString& messageId, const QString& path);
void downloadFileProgress(const QString& messageId, qreal value); void downloadFileProgress(const QString& messageId, qreal value);
void downloadFileError(const QString& messageId, const QString& path); void downloadFileError(const QString& messageId, const QString& path);
void uploadFileProgress(const QString& messageId, qreal value); void uploadFileProgress(const QString& messageId, qreal value);
void uploadFileError(const QString& messageId, const QString& path); void uploadFileError(const QString& messageId, const QString& path);
void uploadFileComplete(const QString& messageId, const QString& url);
public slots: public slots:
void fileLocalPathRequest(const QString& messageId, const QString& url); void fileLocalPathRequest(const QString& messageId, const QString& url);
@ -85,6 +90,7 @@ private:
QNetworkReply* reply; QNetworkReply* reply;
bool success; bool success;
QString path; QString path;
QString url;
QFile* file; QFile* file;
}; };
}; };

View File

@ -106,7 +106,7 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const
QSettings settings; QSettings settings;
unsigned int reconnects = settings.value("reconnects", 2).toUInt(); unsigned int reconnects = settings.value("reconnects", 2).toUInt();
Account* acc = new Account(login, server, password, name); Account* acc = new Account(login, server, password, name, &network);
acc->setResource(resource); acc->setResource(resource);
acc->setReconnectTimes(reconnects); acc->setReconnectTimes(reconnects);
accounts.push_back(acc); accounts.push_back(acc);
@ -285,7 +285,13 @@ void Core::Squawk::sendMessage(const QString& account, const Shared::Message& da
void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data, const QString& path) void Core::Squawk::sendMessage(const QString& account, const Shared::Message& data, const QString& path)
{ {
AccountsMap::const_iterator itr = amap.find(account);
if (itr == amap.end()) {
qDebug("An attempt to send a message with non existing account, skipping");
return;
}
itr->second->sendMessage(data, path);
} }
void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before) void Core::Squawk::requestArchive(const QString& account, const QString& jid, int count, const QString& before)