mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-03-22 03:58:50 -04:00
230 lines
7.5 KiB
C++
230 lines
7.5 KiB
C++
|
|
#include "FileDownload.hpp"
|
|
#include <QCoreApplication>
|
|
#include <QUrl>
|
|
#include <QNetworkRequest>
|
|
#include <QtNetwork/QNetworkAccessManager>
|
|
#include <QtNetwork/QNetworkReply>
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <QIODevice>
|
|
#include "qt_helpers.hpp"
|
|
#include "Logger.hpp"
|
|
|
|
FileDownload::FileDownload() : QObject(nullptr)
|
|
{
|
|
redirect_count_ = 0;
|
|
url_valid_ = false;
|
|
}
|
|
|
|
FileDownload::~FileDownload()
|
|
{
|
|
}
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
|
void FileDownload::errorOccurred(QNetworkReply::NetworkError code)
|
|
{
|
|
LOG_INFO(QString{"FileDownload [%1]: errorOccurred %2 -> %3"}.arg(user_agent_).arg(code).arg(reply_->errorString()));
|
|
Q_EMIT error (reply_->errorString ());
|
|
destfile_.cancelWriting ();
|
|
destfile_.commit ();
|
|
}
|
|
#else
|
|
void FileDownload::obsoleteError()
|
|
{
|
|
LOG_INFO(QString{"FileDownload [%1]: error -> %3"}.arg(user_agent_).arg(reply_->errorString()));
|
|
Q_EMIT error (reply_->errorString ());
|
|
destfile_.cancelWriting ();
|
|
destfile_.commit ();
|
|
}
|
|
#endif
|
|
|
|
void FileDownload::configure(QNetworkAccessManager *network_manager, const QString &source_url, const QString &destination_path, const QString &user_agent)
|
|
{
|
|
manager_ = network_manager;
|
|
source_url_ = source_url;
|
|
destination_filename_ = destination_path;
|
|
user_agent_ = user_agent;
|
|
}
|
|
|
|
void FileDownload::store()
|
|
{
|
|
if (destfile_.isOpen())
|
|
destfile_.write (reply_->read (reply_->bytesAvailable ()));
|
|
else
|
|
LOG_INFO(QString{ "FileDownload [%1]: file is not open."}.arg(user_agent_));
|
|
}
|
|
|
|
void FileDownload::replyComplete()
|
|
{
|
|
QFileInfo destination_file(destination_filename_);
|
|
QDir tmpdir_(destination_file.absoluteFilePath());
|
|
|
|
LOG_DEBUG(QString{ "FileDownload [%1]: replyComplete"}.arg(user_agent_));
|
|
if (!reply_)
|
|
{
|
|
Q_EMIT load_finished ();
|
|
return; // we probably deleted it in an earlier call
|
|
}
|
|
|
|
QUrl redirect_url {reply_->attribute (QNetworkRequest::RedirectionTargetAttribute).toUrl ()};
|
|
|
|
if (reply_->error () == QNetworkReply::NoError && !redirect_url.isEmpty ())
|
|
{
|
|
if ("https" == redirect_url.scheme () && !QSslSocket::supportsSsl ())
|
|
{
|
|
Q_EMIT download_error (tr ("Network Error - SSL/TLS support not installed, cannot fetch:\n\'%1\'")
|
|
.arg (redirect_url.toDisplayString ()));
|
|
url_valid_ = false; // reset
|
|
Q_EMIT load_finished ();
|
|
}
|
|
else if (++redirect_count_ < 10) // maintain sanity
|
|
{
|
|
// follow redirect
|
|
download (reply_->url ().resolved (redirect_url));
|
|
}
|
|
else
|
|
{
|
|
Q_EMIT download_error (tr ("Network Error - Too many redirects:\n\'%1\'")
|
|
.arg (redirect_url.toDisplayString ()));
|
|
url_valid_ = false; // reset
|
|
Q_EMIT load_finished ();
|
|
}
|
|
}
|
|
else if (reply_->error () != QNetworkReply::NoError)
|
|
{
|
|
destfile_.cancelWriting();
|
|
destfile_.commit();
|
|
url_valid_ = false; // reset
|
|
// report errors that are not due to abort
|
|
if (QNetworkReply::OperationCanceledError != reply_->error ())
|
|
{
|
|
Q_EMIT download_error (tr ("Network Error:\n%1")
|
|
.arg (reply_->errorString ()));
|
|
}
|
|
Q_EMIT load_finished ();
|
|
}
|
|
else
|
|
{
|
|
if (!url_valid_)
|
|
{
|
|
// now get the body content
|
|
url_valid_ = true;
|
|
download (reply_->url ().resolved (redirect_url));
|
|
}
|
|
else // the body has completed. Save it.
|
|
{
|
|
url_valid_ = false; // reset
|
|
// load the database asynchronously
|
|
// future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_.fileName ());
|
|
LOG_INFO(QString{ "FileDownload [%1]: complete. File path is %2"}.arg(user_agent_).arg(destfile_.fileName()));
|
|
destfile_.commit();
|
|
emit complete(destination_filename_);
|
|
}
|
|
}
|
|
|
|
if (reply_ && reply_->isFinished ())
|
|
{
|
|
reply_->deleteLater ();
|
|
}
|
|
|
|
}
|
|
|
|
void FileDownload::downloadComplete(QNetworkReply *data)
|
|
{
|
|
// make a temp file in the same place as the file we're downloading. Needs to be on the same
|
|
// filesystem as where we eventually want to 'mv' it.
|
|
|
|
QUrl r = request_.url();
|
|
LOG_INFO(QString{"FileDownload [%1]: finished %2 of %3 -> %4 (%5)"}.arg(user_agent_).arg(data->operation()).arg(source_url_).arg(destination_filename_).arg(r.url()));
|
|
|
|
#ifdef DEBUG_FILEDOWNLOAD
|
|
LOG_INFO("Request Headers:");
|
|
Q_FOREACH (const QByteArray& hdr, request_.rawHeaderList()) {
|
|
LOG_INFO(QString{ "%1 -> %2"}.arg(QString(hdr)).arg(QString(request_.rawHeader(hdr))));
|
|
}
|
|
|
|
LOG_INFO("Response Headers:");
|
|
Q_FOREACH (const QByteArray& hdr, reply_->rawHeaderList()) {
|
|
LOG_INFO(QString{ "%1 -> %2"}.arg(QString(hdr)).arg(QString(reply_->rawHeader(hdr))));
|
|
}
|
|
#endif
|
|
data->deleteLater();
|
|
}
|
|
|
|
void FileDownload::start_download()
|
|
{
|
|
url_valid_ = false;
|
|
download(QUrl(source_url_));
|
|
}
|
|
|
|
void FileDownload::download(QUrl qurl)
|
|
{
|
|
request_.setUrl(qurl);
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
|
if (QNetworkAccessManager::Accessible != manager_->networkAccessible ())
|
|
{
|
|
// try and recover network access for QNAM
|
|
manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
|
|
}
|
|
#endif
|
|
|
|
LOG_INFO(QString{"FileDownload [%1]: Starting download of %2 to %3"}.arg(user_agent_).arg(source_url_).arg(destination_filename_));
|
|
|
|
request_.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
|
request_.setRawHeader("Accept", "*/*");
|
|
request_.setRawHeader ("User-Agent", user_agent_.toLocal8Bit()); // Must have a UA for some sites, like country-files
|
|
|
|
if (!url_valid_)
|
|
{
|
|
reply_ = manager_->head(request_);
|
|
}
|
|
else
|
|
{
|
|
reply_ = manager_->get (request_);
|
|
}
|
|
|
|
QObject::connect(manager_, &QNetworkAccessManager::finished, this, &FileDownload::downloadComplete, Qt::UniqueConnection);
|
|
QObject::connect(reply_, &QNetworkReply::downloadProgress, this, &FileDownload::downloadProgress, Qt::UniqueConnection);
|
|
QObject::connect(reply_, &QNetworkReply::finished, this, &FileDownload::replyComplete, Qt::UniqueConnection);
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
|
QObject::connect(reply_, &QNetworkReply::errorOccurred,this, &FileDownload::errorOccurred, Qt::UniqueConnection);
|
|
#else
|
|
QObject::connect(reply_, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &FileDownload::obsoleteError, Qt::UniqueConnection);
|
|
#endif
|
|
QObject::connect(reply_, &QNetworkReply::readyRead, this, &FileDownload::store, Qt::UniqueConnection);
|
|
|
|
QFileInfo destination_file(destination_filename_);
|
|
QString const tmpfile_base = destination_file.fileName();
|
|
QString const &tmpfile_path = destination_file.absolutePath();
|
|
QDir tmpdir{};
|
|
if (!tmpdir.mkpath(tmpfile_path))
|
|
{
|
|
LOG_INFO(QString{"FileDownload [%1]: Directory %2 does not exist"}.arg(user_agent_).arg(tmpfile_path).arg(
|
|
destfile_.errorString()));
|
|
}
|
|
|
|
if (url_valid_) {
|
|
destfile_.setFileName(destination_file.absoluteFilePath());
|
|
if (!destfile_.open(QSaveFile::WriteOnly | QIODevice::WriteOnly)) {
|
|
LOG_INFO(QString{"FileDownload [%1]: Unable to open %2: %3"}.arg(user_agent_).arg(destfile_.fileName()).arg(
|
|
destfile_.errorString()));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FileDownload::downloadProgress(qint64 received, qint64 total)
|
|
{
|
|
LOG_DEBUG(QString{"FileDownload: [%1] Progress %2 from %3, total %4, so far %5"}.arg(user_agent_).arg(destination_filename_).arg(source_url_).arg(total).arg(received));
|
|
Q_EMIT progress(QString{"%4 bytes downloaded"}.arg(received));
|
|
}
|
|
|
|
void FileDownload::abort ()
|
|
{
|
|
if (reply_ && reply_->isRunning ())
|
|
{
|
|
reply_->abort ();
|
|
}
|
|
}
|