2023-03-09 15:10:20 -05:00
# include "FileDownload.hpp"
# include <QCoreApplication>
# include <QUrl>
# include <QNetworkRequest>
2023-03-15 23:42:03 -04:00
# include <QtNetwork/QNetworkAccessManager>
# include <QtNetwork/QNetworkReply>
2023-03-09 15:10:20 -05:00
# include <QFileInfo>
# include <QDir>
2023-03-16 23:49:08 -04:00
# include <QIODevice>
2023-03-09 15:10:20 -05:00
# include "qt_helpers.hpp"
# include "Logger.hpp"
FileDownload : : FileDownload ( ) : QObject ( nullptr )
{
2023-03-15 23:42:03 -04:00
redirect_count_ = 0 ;
url_valid_ = false ;
2023-03-09 15:10:20 -05:00
}
FileDownload : : ~ FileDownload ( )
{
}
2023-03-17 10:52:03 -04:00
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
2023-03-09 15:10:20 -05:00
void FileDownload : : errorOccurred ( QNetworkReply : : NetworkError code )
{
2023-03-15 23:42:03 -04:00
LOG_INFO ( QString { " FileDownload [%1]: errorOccurred %2 -> %3 " } . arg ( user_agent_ ) . arg ( code ) . arg ( reply_ - > errorString ( ) ) ) ;
Q_EMIT error ( reply_ - > errorString ( ) ) ;
2023-03-16 22:13:59 -04:00
destfile_ . cancelWriting ( ) ;
destfile_ . commit ( ) ;
2023-03-09 15:10:20 -05:00
}
2023-03-17 10:52:03 -04:00
# 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
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
void FileDownload : : configure ( QNetworkAccessManager * network_manager , const QString & source_url , const QString & destination_path , const QString & user_agent )
2023-03-09 15:10:20 -05:00
{
2023-03-15 23:42:03 -04:00
manager_ = network_manager ;
2023-03-09 15:10:20 -05:00
source_url_ = source_url ;
destination_filename_ = destination_path ;
2023-03-15 23:42:03 -04:00
user_agent_ = user_agent ;
2023-03-09 15:10:20 -05:00
}
void FileDownload : : store ( )
{
2023-03-16 22:13:59 -04:00
if ( destfile_ . isOpen ( ) )
destfile_ . write ( reply_ - > read ( reply_ - > bytesAvailable ( ) ) ) ;
2023-03-09 15:10:20 -05:00
else
2023-03-16 22:13:59 -04:00
LOG_INFO ( QString { " FileDownload [%1]: file is not open. " } . arg ( user_agent_ ) ) ;
2023-03-09 15:10:20 -05:00
}
void FileDownload : : replyComplete ( )
{
2023-03-15 23:42:03 -04:00
QFileInfo destination_file ( destination_filename_ ) ;
2023-03-16 22:13:59 -04:00
QDir tmpdir_ ( destination_file . absoluteFilePath ( ) ) ;
2023-03-15 23:42:03 -04:00
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 )
{
2023-03-16 22:13:59 -04:00
destfile_ . cancelWriting ( ) ;
destfile_ . commit ( ) ;
2023-03-15 23:42:03 -04:00
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 ());
2023-03-16 22:13:59 -04:00
LOG_INFO ( QString { " FileDownload [%1]: complete. File path is %2 " } . arg ( user_agent_ ) . arg ( destfile_ . fileName ( ) ) ) ;
destfile_ . commit ( ) ;
2023-03-15 23:42:03 -04:00
emit complete ( destination_filename_ ) ;
}
}
2023-03-09 15:10:20 -05:00
if ( reply_ & & reply_ - > isFinished ( ) )
{
reply_ - > deleteLater ( ) ;
}
2023-03-15 23:42:03 -04:00
2023-03-09 15:10:20 -05:00
}
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.
2023-03-15 23:42:03 -04:00
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 ( ) ) ) ;
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
# ifdef DEBUG_FILEDOWNLOAD
2023-03-09 15:10:20 -05:00
LOG_INFO ( " Request Headers: " ) ;
2023-03-15 23:42:03 -04:00
Q_FOREACH ( const QByteArray & hdr , request_ . rawHeaderList ( ) ) {
LOG_INFO ( QString { " %1 -> %2 " } . arg ( QString ( hdr ) ) . arg ( QString ( request_ . rawHeader ( hdr ) ) ) ) ;
}
2023-03-09 15:10:20 -05:00
LOG_INFO ( " Response Headers: " ) ;
Q_FOREACH ( const QByteArray & hdr , reply_ - > rawHeaderList ( ) ) {
LOG_INFO ( QString { " %1 -> %2 " } . arg ( QString ( hdr ) ) . arg ( QString ( reply_ - > rawHeader ( hdr ) ) ) ) ;
}
2023-03-15 23:42:03 -04:00
# endif
2023-03-09 15:10:20 -05:00
data - > deleteLater ( ) ;
}
2023-03-15 23:42:03 -04:00
void FileDownload : : start_download ( )
2023-03-09 15:10:20 -05:00
{
2023-03-15 23:42:03 -04:00
url_valid_ = false ;
download ( QUrl ( source_url_ ) ) ;
}
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
void FileDownload : : download ( QUrl qurl )
{
request_ . setUrl ( qurl ) ;
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
# 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
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
LOG_INFO ( QString { " FileDownload [%1]: Starting download of %2 to %3 " } . arg ( user_agent_ ) . arg ( source_url_ ) . arg ( destination_filename_ ) ) ;
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
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
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
if ( ! url_valid_ )
{
reply_ = manager_ - > head ( request_ ) ;
}
else
{
reply_ = manager_ - > get ( request_ ) ;
}
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
QObject : : connect ( manager_ , & QNetworkAccessManager : : finished , this , & FileDownload : : downloadComplete , Qt : : UniqueConnection ) ;
QObject : : connect ( reply_ , & QNetworkReply : : downloadProgress , this , & FileDownload : : downloadProgress , Qt : : UniqueConnection ) ;
2023-03-17 07:00:05 -04:00
QObject : : connect ( reply_ , & QNetworkReply : : finished , this , & FileDownload : : replyComplete , Qt : : UniqueConnection ) ;
2023-03-16 22:13:59 -04:00
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
2023-03-17 07:00:05 -04:00
QObject : : connect ( reply_ , & QNetworkReply : : errorOccurred , this , & FileDownload : : errorOccurred , Qt : : UniqueConnection ) ;
2023-03-16 22:13:59 -04:00
# else
2023-03-17 10:52:03 -04:00
QObject : : connect ( reply_ , QOverload < QNetworkReply : : NetworkError > : : of ( & QNetworkReply : : error ) , this , & FileDownload : : obsoleteError , Qt : : UniqueConnection ) ;
2023-03-16 22:13:59 -04:00
# endif
2023-03-17 07:00:05 -04:00
QObject : : connect ( reply_ , & QNetworkReply : : readyRead , this , & FileDownload : : store , Qt : : UniqueConnection ) ;
2023-03-09 15:10:20 -05:00
2023-03-15 23:42:03 -04:00
QFileInfo destination_file ( destination_filename_ ) ;
QString const tmpfile_base = destination_file . fileName ( ) ;
2023-03-16 23:49:08 -04:00
QString const & tmpfile_path = destination_file . absolutePath ( ) ;
QDir tmpdir { } ;
if ( ! tmpdir . mkpath ( tmpfile_path ) )
2023-03-09 15:10:20 -05:00
{
2023-03-16 23:49:08 -04:00
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 ;
}
2023-03-09 15:10:20 -05:00
}
}
void FileDownload : : downloadProgress ( qint64 received , qint64 total )
{
2023-03-15 23:42:03 -04:00
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 ) ) ;
2023-03-09 15:10:20 -05:00
}
2023-03-15 23:42:03 -04:00
void FileDownload : : abort ( )
{
if ( reply_ & & reply_ - > isRunning ( ) )
{
reply_ - > abort ( ) ;
}
2023-03-17 07:00:05 -04:00
}