download files error handling

This commit is contained in:
Blue 2019-09-18 16:27:47 +03:00
parent cc54c6393a
commit 2089d6af86
13 changed files with 199 additions and 9 deletions

View File

@ -21,7 +21,7 @@
Core::NetworkAccess::NetworkAccess(QObject* parent): Core::NetworkAccess::NetworkAccess(QObject* parent):
QObject(parent), QObject(parent),
running(false), running(false),
manager(), manager(0),
files("files"), files("files"),
downloads() downloads()
{ {
@ -29,7 +29,7 @@ Core::NetworkAccess::NetworkAccess(QObject* parent):
Core::NetworkAccess::~NetworkAccess() Core::NetworkAccess::~NetworkAccess()
{ {
stop();
} }
void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url) void Core::NetworkAccess::fileLocalPathRequest(const QString& messageId, const QString& url)
@ -93,6 +93,7 @@ void Core::NetworkAccess::downladFileRequest(const QString& messageId, const QSt
void Core::NetworkAccess::start() void Core::NetworkAccess::start()
{ {
if (!running) { if (!running) {
manager = new QNetworkAccessManager();
files.open(); files.open();
running = true; running = true;
} }
@ -102,7 +103,14 @@ void Core::NetworkAccess::stop()
{ {
if (running) { if (running) {
files.close(); files.close();
manager->deleteLater();
manager = 0;
running = false; running = false;
for (std::map<QString, Download*>::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
}
} }
} }
@ -133,7 +141,128 @@ void Core::NetworkAccess::onRequestError(QNetworkReply::NetworkError code)
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 noone is waiting for it, skipping";
} else { } else {
QString errorText;
switch (code) {
case QNetworkReply::NoError:
//this never is supposed to happen
break;
// network layer errors [relating to the destination server] (1-99):
case QNetworkReply::ConnectionRefusedError:
errorText = "Connection refused";
break;
case QNetworkReply::RemoteHostClosedError:
errorText = "Remote server closed the connection";
break;
case QNetworkReply::HostNotFoundError:
errorText = "Remote host is not found";
break;
case QNetworkReply::TimeoutError:
errorText = "Connection was closed because it timed out";
break;
case QNetworkReply::OperationCanceledError:
//this means I closed it myself by abort() or close(), don't think I need to notify here
break;
case QNetworkReply::SslHandshakeFailedError:
errorText = "Security error"; //TODO need to handle sslErrors signal to get a better description here
break;
case QNetworkReply::TemporaryNetworkFailureError:
//this means the connection is lost by opened route, but it's going to be resumed, not sure I need to notify
break;
case QNetworkReply::NetworkSessionFailedError:
errorText = "Outgoing connection problem";
break;
case QNetworkReply::BackgroundRequestNotAllowedError:
errorText = "Background request is not allowed";
break;
case QNetworkReply::TooManyRedirectsError:
errorText = "The request was redirected too many times";
break;
case QNetworkReply::InsecureRedirectError:
errorText = "The request was redirected to insecure connection";
break;
case QNetworkReply::UnknownNetworkError:
errorText = "Unknown network error";
break;
// proxy errors (101-199):
case QNetworkReply::ProxyConnectionRefusedError:
errorText = "The connection to the proxy server was refused";
break;
case QNetworkReply::ProxyConnectionClosedError:
errorText = "Proxy server closed the connection";
break;
case QNetworkReply::ProxyNotFoundError:
errorText = "Proxy host was not found";
break;
case QNetworkReply::ProxyTimeoutError:
errorText = "Connection to the proxy server was closed because it timed out";
break;
case QNetworkReply::ProxyAuthenticationRequiredError:
errorText = "Couldn't connect to proxy server, authentication is required";
break;
case QNetworkReply::UnknownProxyError:
errorText = "Unknown proxy error";
break;
// content errors (201-299):
case QNetworkReply::ContentAccessDenied:
errorText = "The access to file is denied";
break;
case QNetworkReply::ContentOperationNotPermittedError:
errorText = "The operation over requesting file is not permitted";
break;
case QNetworkReply::ContentNotFoundError:
errorText = "The file was not found";
break;
case QNetworkReply::AuthenticationRequiredError:
errorText = "Couldn't access the file, authentication is required";
break;
case QNetworkReply::ContentReSendError:
errorText = "Sending error, one more attempt will probably solve this problem";
break;
case QNetworkReply::ContentConflictError:
errorText = "The request could not be completed due to a conflict with the current state of the resource";
break;
case QNetworkReply::ContentGoneError:
errorText = "The requested resource is no longer available at the server";
break;
case QNetworkReply::UnknownContentError:
errorText = "Unknown content error";
break;
// protocol errors
case QNetworkReply::ProtocolUnknownError:
errorText = "Unknown protocol error";
break;
case QNetworkReply::ProtocolInvalidOperationError:
errorText = "Requested operation is not permitted in this protocol";
break;
case QNetworkReply::ProtocolFailure:
errorText = "Low level protocol error";
break;
// Server side errors (401-499)
case QNetworkReply::InternalServerError:
errorText = "Internal server error";
break;
case QNetworkReply::OperationNotImplementedError:
errorText = "Server doesn't support requested operation";
break;
case QNetworkReply::ServiceUnavailableError:
errorText = "The server is not available for this operation right now";
break;
case QNetworkReply::UnknownServerError:
errorText = "Unknown server error";
break;
}
if (errorText.size() > 0) {
itr->second->success = false; 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);
}
}
} }
} }
@ -193,7 +322,7 @@ void Core::NetworkAccess::startDownload(const QString& messageId, const QString&
{ {
Download* dwn = new Download({{messageId}, 0, 0, true}); Download* dwn = new Download({{messageId}, 0, 0, true});
QNetworkRequest req(url); QNetworkRequest req(url);
dwn->reply = manager.get(req); dwn->reply = manager->get(req);
connect(dwn->reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(onDownloadProgress(qint64, qint64))); 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(error(QNetworkReply::NetworkError)), SLOT(onRequestError(QNetworkReply::NetworkError)));
connect(dwn->reply, SIGNAL(finished()), SLOT(onRequestFinished())); connect(dwn->reply, SIGNAL(finished()), SLOT(onRequestFinished()));

View File

@ -50,6 +50,7 @@ public:
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);
public slots: public slots:
void fileLocalPathRequest(const QString& messageId, const QString& url); void fileLocalPathRequest(const QString& messageId, const QString& url);
@ -65,7 +66,7 @@ private slots:
private: private:
bool running; bool running;
QNetworkAccessManager manager; QNetworkAccessManager* manager;
Storage files; Storage files;
std::map<QString, Download*> downloads; std::map<QString, Download*> downloads;

View File

@ -30,6 +30,7 @@ Core::Squawk::Squawk(QObject* parent):
{ {
connect(&network, SIGNAL(fileLocalPathResponse(const QString&, const QString&)), this, SIGNAL(fileLocalPathResponse(const QString&, const QString&))); 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(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&)));
} }
Core::Squawk::~Squawk() Core::Squawk::~Squawk()

View File

@ -63,6 +63,7 @@ signals:
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
void fileLocalPathResponse(const QString& messageId, const QString& path); void fileLocalPathResponse(const QString& messageId, const QString& path);
void downloadFileError(const QString& messageId, const QString& error);
void downloadFileProgress(const QString& messageId, qreal value); void downloadFileProgress(const QString& messageId, qreal value);
public slots: public slots:

View File

@ -123,6 +123,7 @@ int main(int argc, char *argv[])
&w, SLOT(removeRoomParticipant(const QString&, const QString&, const QString&))); &w, SLOT(removeRoomParticipant(const QString&, const QString&, const QString&)));
QObject::connect(squawk, SIGNAL(fileLocalPathResponse(const QString&, const QString&)), &w, SLOT(fileLocalPathResponse(const QString&, const QString&))); QObject::connect(squawk, SIGNAL(fileLocalPathResponse(const QString&, const QString&)), &w, SLOT(fileLocalPathResponse(const QString&, const QString&)));
QObject::connect(squawk, SIGNAL(downloadFileProgress(const QString&, qreal)), &w, SLOT(downloadFileProgress(const QString&, qreal))); 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); //qDebug() << QStandardPaths::writableLocation(QStandardPaths::CacheLocation);

View File

@ -369,6 +369,25 @@ void Squawk::downloadFileProgress(const QString& messageId, qreal value)
} }
} }
void Squawk::downloadFileError(const QString& messageId, const QString& error)
{
std::map<QString, std::set<Models::Roster::ElId>>::const_iterator itr = requestedFiles.find(messageId);
if (itr == requestedFiles.end()) {
qDebug() << "downloadFileError in UI Squawk but there is nobody waiting for that id" << messageId << ", skipping";
return;
} else {
const std::set<Models::Roster::ElId>& convs = itr->second;
for (std::set<Models::Roster::ElId>::const_iterator cItr = convs.begin(), cEnd = convs.end(); cItr != cEnd; ++cItr) {
const Models::Roster::ElId& id = *cItr;
Conversations::const_iterator c = conversations.find(id);
if (c != conversations.end()) {
c->second->downloadError(messageId, error);
}
}
requestedFiles.erase(itr);
}
}
void Squawk::fileLocalPathResponse(const QString& messageId, const QString& path) void Squawk::fileLocalPathResponse(const QString& messageId, const QString& path)
{ {
std::map<QString, std::set<Models::Roster::ElId>>::const_iterator itr = requestedFiles.find(messageId); std::map<QString, std::set<Models::Roster::ElId>>::const_iterator itr = requestedFiles.find(messageId);
@ -376,8 +395,7 @@ void Squawk::fileLocalPathResponse(const QString& messageId, const QString& path
qDebug() << "fileLocalPathResponse in UI Squawk but there is nobody waiting for that path, skipping"; qDebug() << "fileLocalPathResponse in UI Squawk but there is nobody waiting for that path, skipping";
return; return;
} else { } else {
std::set<Models::Roster::ElId> convs = itr->second; const std::set<Models::Roster::ElId>& convs = itr->second;
requestedFiles.erase(itr);
for (std::set<Models::Roster::ElId>::const_iterator cItr = convs.begin(), cEnd = convs.end(); cItr != cEnd; ++cItr) { for (std::set<Models::Roster::ElId>::const_iterator cItr = convs.begin(), cEnd = convs.end(); cItr != cEnd; ++cItr) {
const Models::Roster::ElId& id = *cItr; const Models::Roster::ElId& id = *cItr;
Conversations::const_iterator c = conversations.find(id); Conversations::const_iterator c = conversations.find(id);
@ -385,6 +403,8 @@ void Squawk::fileLocalPathResponse(const QString& messageId, const QString& path
c->second->responseLocalFile(messageId, path); c->second->responseLocalFile(messageId, path);
} }
} }
requestedFiles.erase(itr);
} }
} }

View File

@ -91,6 +91,7 @@ public slots:
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
void fileLocalPathResponse(const QString& messageId, const QString& path); void fileLocalPathResponse(const QString& messageId, const QString& path);
void downloadFileError(const QString& messageId, const QString& error);
void downloadFileProgress(const QString& messageId, qreal value); void downloadFileProgress(const QString& messageId, qreal value);
private: private:

View File

@ -290,6 +290,11 @@ void Conversation::responseDownloadProgress(const QString& messageId, qreal prog
line->responseDownloadProgress(messageId, progress); line->responseDownloadProgress(messageId, progress);
} }
void Conversation::downloadError(const QString& messageId, const QString& error)
{
line->downloadError(messageId, error);
}
void Conversation::responseLocalFile(const QString& messageId, const QString& path) void Conversation::responseLocalFile(const QString& messageId, const QString& path)
{ {
line->responseLocalFile(messageId, path); line->responseLocalFile(messageId, path);

View File

@ -72,6 +72,7 @@ public:
void responseArchive(const std::list<Shared::Message> list); void responseArchive(const std::list<Shared::Message> list);
void showEvent(QShowEvent * event) override; void showEvent(QShowEvent * event) override;
void responseLocalFile(const QString& messageId, const QString& path); void responseLocalFile(const QString& messageId, const QString& path);
void downloadError(const QString& messageId, const QString& error);
void responseDownloadProgress(const QString& messageId, qreal progress); void responseDownloadProgress(const QString& messageId, qreal progress);
signals: signals:

View File

@ -38,10 +38,12 @@ Message::Message(const Shared::Message& source, bool outgoing, const QString& p_
file(0), file(0),
progress(0), progress(0),
fileComment(new QLabel()), fileComment(new QLabel()),
errorText(""),
hasDownloadButton(false), hasDownloadButton(false),
hasProgress(false), hasProgress(false),
hasFile(false), hasFile(false),
commentAdded(false) commentAdded(false),
errorDownloadingFile(false)
{ {
body->setBackgroundRole(QPalette::AlternateBase); body->setBackgroundRole(QPalette::AlternateBase);
body->setAutoFillBackground(true); body->setAutoFillBackground(true);
@ -117,7 +119,12 @@ void Message::addDownloadDialog()
} }
downloadButton = new QPushButton(QIcon::fromTheme("download"), "Download"); downloadButton = new QPushButton(QIcon::fromTheme("download"), "Download");
downloadButton->setToolTip("<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>"); downloadButton->setToolTip("<a href=\"" + msg.getOutOfBandUrl() + "\">" + msg.getOutOfBandUrl() + "</a>");
if (errorDownloadingFile) {
fileComment->setWordWrap(true);
fileComment->setText("Error downloading file: " + errorText + "\nYou can try again");
} else {
fileComment->setText(sender->text() + " is offering you to download a file"); fileComment->setText(sender->text() + " is offering you to download a file");
}
fileComment->show(); fileComment->show();
connect(downloadButton, SIGNAL(clicked()), this, SLOT(onDownload())); connect(downloadButton, SIGNAL(clicked()), this, SLOT(onDownload()));
bodyLayout->insertWidget(2, fileComment); bodyLayout->insertWidget(2, fileComment);
@ -208,6 +215,7 @@ void Message::hideDownload()
downloadButton->deleteLater(); downloadButton->deleteLater();
downloadButton = 0; downloadButton = 0;
hasDownloadButton = false; hasDownloadButton = false;
errorDownloadingFile = false;
} }
} }
@ -228,3 +236,10 @@ void Message::hideProgress()
hasProgress = false;; hasProgress = false;;
} }
} }
void Message::showError(const QString& error)
{
errorDownloadingFile = true;
errorText = error;
addDownloadDialog();
}

View File

@ -49,6 +49,7 @@ public:
void addDownloadDialog(); void addDownloadDialog();
void showFile(const QString& path); void showFile(const QString& path);
void showError(const QString& error);
void setProgress(qreal value); void setProgress(qreal value);
signals: signals:
@ -66,10 +67,12 @@ private:
QLabel* file; QLabel* file;
QProgressBar* progress; QProgressBar* progress;
QLabel* fileComment; QLabel* fileComment;
QString errorText;
bool hasDownloadButton; bool hasDownloadButton;
bool hasProgress; bool hasProgress;
bool hasFile; bool hasFile;
bool commentAdded; bool commentAdded;
bool errorDownloadingFile;
private slots: private slots:
void onDownload(); void onDownload();

View File

@ -246,3 +246,14 @@ void MessageLine::responseLocalFile(const QString& messageId, const QString& pat
} }
} }
} }
void MessageLine::downloadError(const QString& messageId, const QString& error)
{
Index::const_iterator itr = messageIndex.find(messageId);
if (itr == messageIndex.end()) {
} else {
itr->second->showError(error);
}
}

View File

@ -53,6 +53,7 @@ public:
void showBusyIndicator(); void showBusyIndicator();
void hideBusyIndicator(); void hideBusyIndicator();
void responseLocalFile(const QString& messageId, const QString& path); void responseLocalFile(const QString& messageId, const QString& path);
void downloadError(const QString& messageId, const QString& error);
void responseDownloadProgress(const QString& messageId, qreal progress); void responseDownloadProgress(const QString& messageId, qreal progress);
signals: signals: