/** * This work is distributed under the Lesser General Public License, * see LICENSE for details * * @author Gwennaël ARBONA **/ #include "downloader.h" /*---------------------------------------------- Constructor & destructor ----------------------------------------------*/ Downloader::Downloader() { } Downloader::~Downloader() { delete ftp; delete chrono; delete timeoutTimer; delete speedUpdateTimer; delete downloadUpdateTimer; } /*---------------------------------------------- Connection handling ----------------------------------------------*/ /*--- Launch thread ---*/ void Downloader::Connect() { qDebug() << "Downloader::Connect"; // Files init QFile::remove(FTP_OLD_RELEASE_NOTES_FILE); QFile::copy(FTP_RELEASE_NOTES_FILE, FTP_OLD_RELEASE_NOTES_FILE); QFile::remove(FTP_RELEASE_NOTES_FILE); QFile::remove(FTP_MANIFEST_FILE); // URL setup ftpClient = new QUrl(); ftpClient->setScheme("ftp"); ftpClient->setPort(21); ftpClient->setHost(FTP_SERVER); ftpClient->setUserName(FTP_USER); // FTP setup currentSpeed = 0.0; currentFtpFile = ""; ftp = new QNetworkAccessManager(); connect(ftp, &QNetworkAccessManager::finished, this, &Downloader::FileFinished); // Timers chrono = new QTime(); timeoutTimer = new QTimer(this); speedUpdateTimer = new QTimer(this); downloadUpdateTimer = new QTimer(this); connect(timeoutTimer, &QTimer::timeout, this, &Downloader::Reconnect); connect(speedUpdateTimer, &QTimer::timeout, this, &Downloader::UpdateSpeedInfo); connect(downloadUpdateTimer, &QTimer::timeout, this, &Downloader::UpdateDownloadInfo); // Chrono chronoSize = 0; chrono->start(); speedUpdateTimer->setSingleShot(true); speedUpdateTimer->start(FTP_SPEED_UPDATE_TIME); downloadUpdateTimer->setSingleShot(true); downloadUpdateTimer->start(FTP_DOWNLOAD_UPDATE_TIME); // Launch Login(""); } /*--- Timeout has expired, restart the current file ---*/ void Downloader::Reconnect() { qDebug() << "Downloader::Reconnect"; // Destroy the FTP handler disconnect(timeoutTimer, &QTimer::timeout, this, &Downloader::Reconnect); disconnect(ftp, &QNetworkAccessManager::finished, this, &Downloader::FileFinished); ftp->deleteLater(); // Restart ftp = new QNetworkAccessManager(); connect(timeoutTimer, &QTimer::timeout, this, &Downloader::Reconnect); connect(ftp, &QNetworkAccessManager::finished, this, &Downloader::FileFinished); emit DownloadFile(currentFtpDir, currentFtpFile); } /*--- Use password to login ---*/ void Downloader::Login(QString pwd) { qDebug() << "Downloader::Login"; password = pwd; ftpClient->setPassword(password); DownloadFile("", FTP_RELEASE_NOTES_FILE); } /*---------------------------------------------- File handling ----------------------------------------------*/ /*--- Prepare download, then issue the FTP commands ---*/ void Downloader::DownloadFile(QString dir, QString file) { qDebug() << "Downloader::DownloadFile"; // Data QUrl fileUrl(*ftpClient); QNetworkRequest r; QDir tempDir("."); // Setup downloadedSize = 0; lastDownloadedSize = 0; currentFtpDir = dir; currentFtpFile = file; currentFile = new QFile(currentFtpDir + currentFtpFile); fileUrl.setPath(FTP_UPDATE_ROOT + currentFtpDir + currentFtpFile); r.setUrl(fileUrl); // Local file preparation if (currentFtpDir.length() > 0) { tempDir.mkpath(currentFtpDir); } if (currentFtpFile.length() > 0 && currentFile->exists()) { currentFile->remove(); } currentFile->open(QIODevice::WriteOnly); // Download command bDownloading = true; reply = ftp->get(r); reply->setReadBufferSize(FTP_PART_SIZE); connect(reply, &QNetworkReply::readyRead, this, &Downloader::FilePart); connect(reply, static_cast(&QNetworkReply::error), this, &Downloader::FileError); // Timers timeoutTimer->setSingleShot(true); timeoutTimer->start(FTP_TIMEOUT); } /*--- Received on FTP part downloaded ---*/ void Downloader::FilePart(void) { int count = currentFile->write(reply->readAll()); timeoutTimer->stop(); timeoutTimer->setSingleShot(true); timeoutTimer->start(FTP_TIMEOUT); downloadedSize += count; chronoSize += count; } /*--- Received when a command has failed ---*/ void Downloader::FileError(QNetworkReply::NetworkError code) { qDebug() << "Downloader::FileError"; switch (code) { case QNetworkReply::NoError: break; case QNetworkReply::ConnectionRefusedError: case QNetworkReply::RemoteHostClosedError: case QNetworkReply::HostNotFoundError: case QNetworkReply::TimeoutError: emit NetworkError("Networking error (" + QString::number(code) + ")", true); break; case QNetworkReply::AuthenticationRequiredError: emit NetworkError("Password required", true); emit PasswordRequired(); bDownloading = false; timeoutTimer->stop(); speedUpdateTimer->stop(); break; case QNetworkReply::ProxyAuthenticationRequiredError: case QNetworkReply::ProxyConnectionRefusedError: case QNetworkReply::ProxyConnectionClosedError: case QNetworkReply::ProxyNotFoundError: case QNetworkReply::ProxyTimeoutError: case QNetworkReply::UnknownProxyError: emit NetworkError("Proxy error (" + QString::number(code) + ")", true); break; default: emit NetworkError("Server error (" + QString::number(code) + ")", true); break; } } /*--- Received when a download has ended ---*/ void Downloader::FileFinished(QNetworkReply* mreply) { qDebug() << "Downloader::FileFinished"; disconnect(reply, &QNetworkReply::readyRead, this, &Downloader::FilePart); disconnect(reply, static_cast(&QNetworkReply::error), this, &Downloader::FileError); mreply->deleteLater(); lastDownloadedSize = 0; downloadedSize = 0; if (bDownloading) { bDownloading = false; timeoutTimer->stop(); currentFile->close(); delete currentFile; emit FileDownloaded(currentFtpFile); } } /*---------------------------------------------- Downloading info ----------------------------------------------*/ /*--- Update current speed ---*/ void Downloader::UpdateSpeedInfo(void) { currentSpeed = ((float)chronoSize / 1024.0) / ((float)chrono->restart() / 1000.0); chronoSize = 0; speedUpdateTimer->start(FTP_SPEED_UPDATE_TIME); } /*--- Update data about the current download ---*/ void Downloader::UpdateDownloadInfo(void) { int sizeDelta = downloadedSize - lastDownloadedSize; emit BytesDownloaded(sizeDelta, currentSpeed); lastDownloadedSize = downloadedSize; downloadUpdateTimer->start(FTP_DOWNLOAD_UPDATE_TIME); }