File indexing completed on 2024-05-12 16:28:12

0001 // SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include "filetransferjob.h"
0005 #include "account/account.h"
0006 #include "tokodon_http_debug.h"
0007 #include <KLocalizedString>
0008 #include <QDebug>
0009 #include <QNetworkReply>
0010 #include <QUrl>
0011 
0012 FileTransferJob::FileTransferJob(AbstractAccount *account, const QString &source, const QString &destination)
0013     : KJob()
0014     , m_account(account)
0015     , m_source(source)
0016     , m_destination(destination)
0017     , m_temporaryFile(new QSaveFile(QUrl(destination).toLocalFile()))
0018 {
0019 }
0020 
0021 void FileTransferJob::start()
0022 {
0023     if (auto account = qobject_cast<Account *>(m_account); account) {
0024         auto qnam = account->qnam();
0025 
0026         auto reply = qnam->get(QNetworkRequest(QUrl(m_source)));
0027 
0028         setTotalAmount(Unit::Files, 1);
0029         if (!m_temporaryFile->isReadable() && !m_temporaryFile->open(QIODevice::WriteOnly)) {
0030             qCWarning(TOKODON_HTTP) << "Couldn't open the temporary file" << m_temporaryFile->fileName() << "for writing" << m_temporaryFile->errorString();
0031             setError(FileError);
0032             setErrorText("Could not open the temporary download file");
0033             emitResult();
0034             return;
0035         }
0036         connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 bytesReceived, qint64 bytesTotal) {
0037             if (bytesTotal != -1) {
0038                 setTotalAmount(Unit::Bytes, bytesTotal);
0039             }
0040             setProcessedAmount(Unit::Bytes, bytesReceived);
0041         });
0042 
0043         connect(reply, &QNetworkReply::finished, this, [this, reply]() {
0044             if (reply->error() != QNetworkReply::NoError) {
0045                 setError(FileError);
0046                 setErrorText(reply->errorString());
0047                 emitResult();
0048                 return;
0049             }
0050             if (!m_temporaryFile->commit()) {
0051                 qCWarning(TOKODON_HTTP) << "errror when saving";
0052             }
0053             reply->deleteLater();
0054             emitResult();
0055         });
0056 
0057         connect(reply, &QIODevice::readyRead, this, [this, reply] {
0058             auto bytes = reply->read(reply->bytesAvailable());
0059             if (!bytes.isEmpty()) {
0060                 m_temporaryFile->write(bytes);
0061             } else {
0062                 qCWarning(TOKODON_HTTP) << "Unexpected empty chunk when downloading from" << reply->url() << "to" << m_temporaryFile->fileName();
0063             }
0064         });
0065 
0066         connect(reply, &QNetworkReply::metaDataChanged, this, [this, reply] {
0067             auto sizeHeader = reply->header(QNetworkRequest::ContentLengthHeader);
0068             if (sizeHeader.isValid()) {
0069                 auto targetSize = sizeHeader.toLongLong();
0070                 if (targetSize != -1) {
0071                     if (!m_temporaryFile->resize(targetSize)) {
0072                         qCWarning(TOKODON_HTTP) << "Failed to allocate" << targetSize << "bytes for" << m_temporaryFile->fileName();
0073                         setError(FileError);
0074                         setErrorText("Could not reserve disk space for download");
0075                         emitResult();
0076                     }
0077                 }
0078             }
0079         });
0080 
0081         Q_EMIT description(this,
0082                            i18nc("Job heading, like 'Copying'", "Downloading"),
0083                            {i18nc("The URL being downloaded/uploaded", "Source"), m_source},
0084                            {i18nc("The location being downloaded to", "Destination"), m_destination});
0085     }
0086 }