#ifndef DOWNLOADTHREAD_H #define DOWNLOADTHREAD_H /* * SPDX-License-Identifier: Apache-2.0 * Copyright (C) 2020 Raspberry Pi (Trading) Limited */ #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include "windows/winfile.h" #endif #ifdef Q_OS_DARWIN #include "mac/macfile.h" #endif class DownloadThread : public QThread { Q_OBJECT public: /* * Constructor * * - url: URL to download * - localfilename: File name to save downloaded file as. If empty, store data in memory buffer */ explicit DownloadThread(const QByteArray &url, const QByteArray &localfilename = "", const QByteArray &expectedHash = "", QObject *parent = nullptr); /* * Destructor * * Waits until download is complete * If this is not desired, call cancelDownload() first */ virtual ~DownloadThread(); /* * Cancel download * * Async function. Returns immedeately, but can take a second before download actually stops */ virtual void cancelDownload(); /* * Set proxy server. * Specify a string like this: user:pass@proxyserver:8080/ * Used globally, for all connections */ static void setProxy(const QByteArray &proxy); /* * Returns proxy server used */ static QByteArray proxy(); /* * Set user-agent header string */ void setUserAgent(const QByteArray &ua); /* * Returns true if download has been successful */ bool successfull(); /* * Returns the downloaded data if saved to memory buffer instead of file */ QByteArray data(); /* * Delete downloaded file */ void deleteDownloadedFile(); /* * Return last-modified date (if available) as unix timestamp * (seconds since 1970) */ time_t lastModified(); /* * Return current server time as unix timestamp */ time_t serverTime(); /* * Enable/disable verification */ void setVerifyEnabled(bool verify); /* * Enable disk cache */ void setCacheFile(const QString &filename, qint64 filesize = 0); /* * Thread safe download progress query functions */ uint64_t dlNow(); uint64_t dlTotal(); uint64_t verifyNow(); uint64_t verifyTotal(); uint64_t bytesWritten(); virtual bool isImage(); signals: void success(); void error(QString msg); void cacheFileUpdated(QByteArray sha256); void finalizing(); protected: virtual void run(); virtual void _onDownloadSuccess(); virtual void _onDownloadError(const QString &msg); size_t _writeFile(const char *buf, size_t len); void _writeComplete(); bool _verify(); int _authopen(const QByteArray &filename); bool _openAndPrepareDevice(); void _writeCache(const char *buf, size_t len); /* * libcurl callbacks */ virtual size_t _writeData(const char *buf, size_t len); bool _progress(curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); void _header(const std::string &header); static size_t _curl_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata); static int _curl_xferinfo_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); static size_t _curl_header_callback( void *ptr, size_t size, size_t nmemb, void *userdata); CURL *_c; curl_off_t _startOffset; std::atomic _lastDlTotal, _lastDlNow, _verifyTotal, _lastVerifyNow, _bytesWritten; QByteArray _url, _useragent, _buf, _filename, _lastError, _expectedHash; char *_firstBlock; size_t _firstBlockSize; static QByteArray _proxy; static int _curlCount; bool _cancelled, _successful, _verifyEnabled, _cacheEnabled; time_t _lastModified, _serverTime, _lastFailureTime; QElapsedTimer _timer; #ifdef Q_OS_WIN WinFile _file, _volumeFile; #elif defined(Q_OS_DARWIN) MacFile _file; #else QFile _file; #endif QFile _cachefile; QCryptographicHash _writehash, _verifyhash; }; #endif // DOWNLOADTHREAD_H