diff --git a/src/base/search/searchdownloadhandler.cpp b/src/base/search/searchdownloadhandler.cpp index 42869579f..27823d9b9 100644 --- a/src/base/search/searchdownloadhandler.cpp +++ b/src/base/search/searchdownloadhandler.cpp @@ -28,9 +28,11 @@ #include "searchdownloadhandler.h" +#include #include #include "base/global.h" +#include "base/logger.h" #include "base/path.h" #include "base/utils/foreignapps.h" #include "base/utils/fs.h" @@ -38,6 +40,8 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager) : QObject(manager) + , m_pluginName {pluginName} + , m_url {url} , m_manager {manager} , m_downloadProcess {new QProcess(this)} { @@ -58,10 +62,17 @@ SearchDownloadHandler::SearchDownloadHandler(const QString &pluginName, const QS m_downloadProcess->start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly); } -void SearchDownloadHandler::downloadProcessFinished(int exitcode) +void SearchDownloadHandler::downloadProcessFinished(const int exitcode) { - QString path; + const auto errMsg = QString::fromUtf8(m_downloadProcess->readAllStandardError()).trimmed(); + if (!errMsg.isEmpty()) + { + qWarning("%s", qUtf8Printable(errMsg)); + LogMsg(tr("Error occurred when downloading torrent via search engine. Engine: \"%1\". URL: \"%2\". Error: \"%3\".") + .arg(m_pluginName, m_url, errMsg), Log::WARNING); + } + QString path; if ((exitcode == 0) && (m_downloadProcess->exitStatus() == QProcess::NormalExit)) { const QString line = QString::fromUtf8(m_downloadProcess->readAllStandardOutput()).trimmed(); @@ -70,5 +81,5 @@ void SearchDownloadHandler::downloadProcessFinished(int exitcode) path = parts[0].toString(); } - emit downloadFinished(path); + emit downloadFinished(path, errMsg); } diff --git a/src/base/search/searchdownloadhandler.h b/src/base/search/searchdownloadhandler.h index 426560e0a..9dd9e58db 100644 --- a/src/base/search/searchdownloadhandler.h +++ b/src/base/search/searchdownloadhandler.h @@ -29,6 +29,7 @@ #pragma once #include +#include class QProcess; @@ -44,11 +45,13 @@ class SearchDownloadHandler : public QObject SearchDownloadHandler(const QString &pluginName, const QString &url, SearchPluginManager *manager); signals: - void downloadFinished(const QString &path); + void downloadFinished(const QString &path, const QString &errorMessage); private: void downloadProcessFinished(int exitcode); + QString m_pluginName; + QString m_url; SearchPluginManager *m_manager = nullptr; QProcess *m_downloadProcess = nullptr; }; diff --git a/src/base/search/searchhandler.cpp b/src/base/search/searchhandler.cpp index d1d9fb4b7..670c2b42a 100644 --- a/src/base/search/searchhandler.cpp +++ b/src/base/search/searchhandler.cpp @@ -31,12 +31,14 @@ #include +#include #include #include #include #include #include "base/global.h" +#include "base/logger.h" #include "base/path.h" #include "base/utils/bytearray.h" #include "base/utils/foreignapps.h" @@ -59,6 +61,26 @@ namespace PL_PUB_DATE, NB_PLUGIN_COLUMNS }; + + QString toString(const QProcess::ProcessError error) + { + switch (error) + { + case QProcess::FailedToStart: + return SearchHandler::tr("Process failed to start"); + case QProcess::Crashed: + return SearchHandler::tr("Process crashed"); + case QProcess::Timedout: + return SearchHandler::tr("Process timed out"); + case QProcess::WriteError: + return SearchHandler::tr("Process write error"); + case QProcess::ReadError: + return SearchHandler::tr("Process read error"); + case QProcess::UnknownError: + return SearchHandler::tr("Process unknown error"); + } + return {}; + }; } SearchHandler::SearchHandler(const QString &pattern, const QString &category, const QStringList &usedPlugins, SearchPluginManager *manager) @@ -86,7 +108,16 @@ SearchHandler::SearchHandler(const QString &pattern, const QString &category, co }; m_searchProcess->setArguments(params + m_pattern.split(u' ')); - connect(m_searchProcess, &QProcess::errorOccurred, this, &SearchHandler::processFailed); + connect(m_searchProcess, &QProcess::errorOccurred, this, [this](const QProcess::ProcessError error) + { + if (!m_searchCancelled) + { + const auto errMsg = toString(error); + LogMsg(tr("Search process failed. Search query: \"%1\". Category: \"%2\". Engines: \"%3\". Error: \"%4\".") + .arg(m_pattern, m_category, m_usedPlugins.join(u", "), errMsg), Log::WARNING); + emit searchFailed(errMsg); + } + }); connect(m_searchProcess, &QProcess::readyReadStandardOutput, this, &SearchHandler::readSearchOutput); connect(m_searchProcess, qOverload(&QProcess::finished) , this, &SearchHandler::processFinished); @@ -127,12 +158,20 @@ void SearchHandler::processFinished(const int exitcode) { m_searchTimeout->stop(); + const auto errMsg = QString::fromUtf8(m_searchProcess->readAllStandardError()).trimmed(); + if (!errMsg.isEmpty()) + { + qWarning("%s", qUtf8Printable(errMsg)); + LogMsg(tr("Error occurred in search engine. Search query: \"%1\". Category: \"%2\". Engines: \"%3\". Error: \"%4\".") + .arg(m_pattern, m_category, m_usedPlugins.join(u", "), errMsg), Log::WARNING); + } + if (m_searchCancelled) emit searchFinished(true); else if ((m_searchProcess->exitStatus() == QProcess::NormalExit) && (exitcode == 0)) emit searchFinished(false); else - emit searchFailed(); + emit searchFailed(errMsg); } // search QProcess return output as soon as it gets new @@ -161,12 +200,6 @@ void SearchHandler::readSearchOutput() } } -void SearchHandler::processFailed() -{ - if (!m_searchCancelled) - emit searchFailed(); -} - // Parse one line of search results list // Line is in the following form: // file url | file name | file size | nb seeds | nb leechers | Search engine url diff --git a/src/base/search/searchhandler.h b/src/base/search/searchhandler.h index fe6fe9d76..7af9f928e 100644 --- a/src/base/search/searchhandler.h +++ b/src/base/search/searchhandler.h @@ -74,12 +74,11 @@ public: signals: void searchFinished(bool cancelled = false); - void searchFailed(); + void searchFailed(const QString &errorMessage); void newSearchResults(const QList &results); private: void readSearchOutput(); - void processFailed(); void processFinished(int exitcode); bool parseSearchResult(QByteArrayView line, SearchResult &searchResult); diff --git a/src/base/search/searchpluginmanager.cpp b/src/base/search/searchpluginmanager.cpp index 8fc7de188..bd4b14352 100644 --- a/src/base/search/searchpluginmanager.cpp +++ b/src/base/search/searchpluginmanager.cpp @@ -31,6 +31,7 @@ #include +#include #include #include #include @@ -559,6 +560,13 @@ void SearchPluginManager::update() nova.start(Utils::ForeignApps::pythonInfo().executablePath.data(), params, QIODevice::ReadOnly); nova.waitForFinished(); + if (const auto errMsg = QString::fromUtf8(nova.readAllStandardError()).trimmed() + ; !errMsg.isEmpty()) + { + qWarning("%s", qUtf8Printable(errMsg)); + LogMsg(tr("Error occurred when fetching search engine capabilities. Error: \"%1\".").arg(errMsg), Log::WARNING); + } + const auto capabilities = QString::fromUtf8(nova.readAllStandardOutput()); QDomDocument xmlDoc; if (!xmlDoc.setContent(capabilities)) diff --git a/src/gui/search/searchjobwidget.cpp b/src/gui/search/searchjobwidget.cpp index 5544ea150..c71ec7b2f 100644 --- a/src/gui/search/searchjobwidget.cpp +++ b/src/gui/search/searchjobwidget.cpp @@ -64,10 +64,12 @@ namespace return QApplication::palette().color(QPalette::Disabled, QPalette::WindowText); } - QString statusText(SearchJobWidget::Status st) + QString statusText(const SearchJobWidget::Status st) { switch (st) { + case SearchJobWidget::Status::Ready: + break; case SearchJobWidget::Status::Ongoing: return SearchJobWidget::tr("Searching..."); case SearchJobWidget::Status::Finished: @@ -78,9 +80,8 @@ namespace return SearchJobWidget::tr("An error occurred during search..."); case SearchJobWidget::Status::NoResults: return SearchJobWidget::tr("Search returned no results"); - default: - return {}; } + return {}; } } @@ -402,7 +403,7 @@ void SearchJobWidget::copyField(const int column) const QApplication::clipboard()->setText(list.join(u'\n')); } -void SearchJobWidget::setStatus(Status value) +void SearchJobWidget::setStatus(const Status value) { if (m_status == value) return; @@ -426,9 +427,12 @@ void SearchJobWidget::downloadTorrent(const QModelIndex &rowIndex, const AddTorr else { SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(engineName, torrentUrl); - connect(downloadHandler, &SearchDownloadHandler::downloadFinished - , this, [this, option](const QString &source) { addTorrentToSession(source, option); }); - connect(downloadHandler, &SearchDownloadHandler::downloadFinished, downloadHandler, &SearchDownloadHandler::deleteLater); + connect(downloadHandler, &SearchDownloadHandler::downloadFinished, this + , [this, downloadHandler, option](const QString &source, [[maybe_unused]] const QString &errorMessage) + { + addTorrentToSession(source, option); + downloadHandler->deleteLater(); + }); } setRowVisited(rowIndex.row()); @@ -631,7 +635,7 @@ void SearchJobWidget::searchFinished(bool cancelled) setStatus(Status::Finished); } -void SearchJobWidget::searchFailed() +void SearchJobWidget::searchFailed([[maybe_unused]] const QString &errorMessage) { setStatus(Status::Error); } diff --git a/src/gui/search/searchjobwidget.h b/src/gui/search/searchjobwidget.h index f6b879fce..f2842f470 100644 --- a/src/gui/search/searchjobwidget.h +++ b/src/gui/search/searchjobwidget.h @@ -112,7 +112,7 @@ private: void contextMenuEvent(QContextMenuEvent *event) override; void onItemDoubleClicked(const QModelIndex &index); void searchFinished(bool cancelled); - void searchFailed(); + void searchFailed(const QString &errorMessage); void appendSearchResults(const QList &results); void updateResultsCount(); void setStatus(Status value); diff --git a/src/webui/api/searchcontroller.cpp b/src/webui/api/searchcontroller.cpp index c8c5298f2..0257b16ec 100644 --- a/src/webui/api/searchcontroller.cpp +++ b/src/webui/api/searchcontroller.cpp @@ -114,8 +114,8 @@ void SearchController::startAction() const auto id = generateSearchId(); const std::shared_ptr searchHandler {SearchPluginManager::instance()->startSearch(pattern, category, pluginsToUse)}; - QObject::connect(searchHandler.get(), &SearchHandler::searchFinished, this, [id, this]() { m_activeSearches.remove(id); }); - QObject::connect(searchHandler.get(), &SearchHandler::searchFailed, this, [id, this]() { m_activeSearches.remove(id); }); + connect(searchHandler.get(), &SearchHandler::searchFinished, this, [this, id] { m_activeSearches.remove(id); }); + connect(searchHandler.get(), &SearchHandler::searchFailed, this, [this, id]([[maybe_unused]] const QString &errorMessage) { m_activeSearches.remove(id); }); m_searchHandlers.insert(id, searchHandler); @@ -235,8 +235,8 @@ void SearchController::downloadTorrentAction() else { SearchDownloadHandler *downloadHandler = SearchPluginManager::instance()->downloadTorrent(pluginName, torrentUrl); - connect(downloadHandler, &SearchDownloadHandler::downloadFinished - , this, [this, downloadHandler](const QString &source) + connect(downloadHandler, &SearchDownloadHandler::downloadFinished, this + , [this, downloadHandler](const QString &source, [[maybe_unused]] const QString &errorMessage) { app()->addTorrentManager()->addTorrent(source); downloadHandler->deleteLater();