Qx v0.5.7
Qt Extensions Library
Loading...
Searching...
No Matches
qx-downloadmanager.h
1#ifndef QX_DOWNLOADMANAGER_H
2#define QX_DOWNLOADMANAGER_H
3
4// Shared Lib Support
5#include "qx/network/qx_network_export.h"
6
7// Qt Includes
8#include <QEventLoop>
9#include <QNetworkAccessManager>
10#include <QAuthenticator>
11
12// Intra-component Includes
13#include "qx/network/qx-downloadtask.h"
14#include "qx/network/qx-downloadopreport.h"
15#include "qx/network/qx-downloadmanagerreport.h"
16
17// Extra-component Includes
18#include "qx/core/qx-error.h"
19#include "qx/core/qx-cumulation.h"
20#include "qx/io/qx-filestreamwriter.h"
21
22/* TODO: Try to improve efficiency like making uses of DownloadTask in hashes and the like pointers instead,
23 * and passing them as pointers/references where possible. Cant use a pointer for download task list because
24 * then the manager cant prevent multiple of the same download task from being added. Though, if this would
25 * be the only way to achieve significant gains, it might be worth sacrificing.
26 *
27 * Another approach may be prehashing DownloadTask (provide access to value with method), then have the
28 * download progress cumulations use those hashes as a key instead of a full DownloadTask object. This
29 * could be further optimized by implementing a template class wrapper with qHash implemented such that
30 * it just passes this hash value along so that when used in a QHash computational load is reduced to a
31 * minimum
32 *
33 * I.e https://stackoverflow.com/questions/33188513/how-to-pass-hash-value-into-unordered-map-to-reduce-time-lock-held
34 *
35 * Though since this would require storing the hash with the download task, the space savings would be
36 * somewhat reduced.
37 *
38 * Ultimately allocating the download tasks on the heap and trying to implement an efficient way to detect
39 * duplicates with pointers to the tasks, or simply giving up this detection, may be the way to go.
40 */
41namespace Qx
42{
43
44class QX_NETWORK_EXPORT AsyncDownloadManager: public QObject
45{
46//-QObject Macro (Required for all QObject Derived Classes)-----------------------------------------------------------
47 Q_OBJECT
48
49//-Class Enums------------------------------------------------------------------------------------------------------
50private:
51 enum Status {Initial, Enumerating, Downloading, Aborting, StoppingOnError};
52
53//-Class Structs----------------------------------------------------------------------------------------------------
54private:
55 class Writer
56 {
57 private:
59 std::optional<QCryptographicHash> mHash;
60
61 public:
62 Writer(const QString& d, WriteOptions o, std::optional<QCryptographicHash::Algorithm> a);
63
64 IoOpReport open();
65 IoOpReport write(const QByteArray& d);
66 void close();
67 bool isOpen() const;
68 QString path() const;
69 IoOpReport status() const;
70 QByteArray hash() const;
71 };
72
73//-Class Members------------------------------------------------------------------------------------------------------
74private:
75 // Enumeration
76 static const qint64 PRESUMED_SIZE = 10485760; // 10 MB
77 static const qint64 SIZE_QUERY_TIMEOUT_MS = 500;
78
79 // Errors - Finish
80 static inline const QString ERR_TIMEOUT = u"The data transfer failed to start before the timeout was reached."_s;
81 static inline const QString ERR_CHECKSUM_MISMATCH = u"The file's contents did not produce the expected checksum."_s;
82
83 // Errors - Messages
84 static inline const QString SSL_ERR = u"The following SSL issues occurred while attempting to download %1"_s;
85 static inline const QString CONTINUE_QUES = u"Continue downloading?"_s;
86 static inline const QString AUTH_REQUIRED = u"Authentication is required to connect to %1"_s;
87 static inline const QString PROXY_AUTH_REQUIRED = u"Authentication is required to connect to the proxy %1"_s;
88
89 // Prompts
90 static inline const QString PROMPT_AUTH = u"Authentication is required for %1"_s;
91 static inline const QString PROMPT_PRESHARED_AUTH = u"Pre-shared key authentication is required for %1"_s;
92 static inline const QString PROMPT_PROXY_AUTH = u"Proxy authentication is required for %1"_s;
93
94//-Instance Members---------------------------------------------------------------------------------------------------
95private:
96 // Properties
97 int mMaxSimultaneous; // < 1 is unlimited
98 int mEnumerationTimeout;
99 bool mOverwrite;
100 bool mStopOnError;
101 bool mSkipEnumeration;
102 bool mDeletePartials;
103 // TODO: May also want to have option for removing ALL files upon any failure, even complete ones
104 QCryptographicHash::Algorithm mVerificationMethod;
105
106 // Status
107 Status mStatus;
108
109 // Network Access
111
112 // Downloads
113 QList<DownloadTask> mPendingEnumerants;
114 QList<DownloadTask> mPendingDownloads;
117
118 // Progress
121
122 // Report
123 DownloadManagerReport::Builder mReportBuilder;
124
125//-Constructor-------------------------------------------------------------------------------------------------------
126public:
127 AsyncDownloadManager(QObject* parent = nullptr);
128
129//-Instance Functions----------------------------------------------------------------------------------------------
130private:
131 // Size enumeration
132 void startSizeEnumeration();
133 void pushEnumerationsUntilFinished();
134 void startSizeQuery(DownloadTask task);
135
136 // Download
137 void startTrueDownloads();
138 void pushDownloadsUntilFinished();
139 void startDownload(DownloadTask task);
140 void recordFinishedDownload(DownloadOpReport report);
141
142 // Halting
143 void stopOnError();
144 void forceFinishProgress(const DownloadTask& task);
145
146 // Cleanup
147 void finish();
148 void reset();
149
150public:
151 // Properties
152 int maxSimultaneous() const;
153 QNetworkRequest::RedirectPolicy redirectPolicy() const;
154 int transferTimeout() const;
155 int enumerationTimeout() const;
156 bool isOverwrite() const;
157 bool isStopOnError() const;
158 bool isSkipEnumeration() const;
159 bool isDeletePartialDownloads() const;
160 QCryptographicHash::Algorithm verificationMethod() const;
161 int taskCount() const;
162 bool hasTasks() const;
163 bool isProcessing() const;
164
165 void setMaxSimultaneous(int maxSimultaneous);
166 void setRedirectPolicy(QNetworkRequest::RedirectPolicy redirectPolicy);
167 void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant);
168 void setEnumerationTimeout(int timeout = 500);
169 void setOverwrite(bool overwrite);
170 void setStopOnError(bool stopOnError);
171 void setSkipEnumeration(bool skipEnumeration);
172 void setDeletePartialDownloads(bool deletePartialDownloads);
173 void setVerificationMethod(QCryptographicHash::Algorithm method);
174
175 // Tasks
176 void appendTask(const DownloadTask& task);
177 void clearTasks();
178
179//-Slots------------------------------------------------------------------------------------------------------------
180private slots:
181 // In-progress handlers
182 void sslErrorHandler(QNetworkReply* reply, const QList<QSslError>& errors);
183 void authHandler(QNetworkReply* reply, QAuthenticator* authenticator);
184 void preSharedAuthHandler(QNetworkReply* reply, QSslPreSharedKeyAuthenticator* authenticator);
185 void proxyAuthHandler(const QNetworkProxy& proxy, QAuthenticator* authenticator);
186 void readyReadHandler();
187 void downloadProgressHandler(qint64 bytesCurrent, qint64 bytesTotal);
188
189 // Finished handlers
190 void sizeQueryFinishedHandler(QNetworkReply* reply);
191 void downloadFinishedHandler(QNetworkReply* reply);
192
193public slots:
194 void processQueue();
195 void abort();
196
197//-Signals------------------------------------------------------------------------------------------------------------
198signals:
199 // In-progress signals
200 void sslErrors(Qx::Error errorMsg, bool* ignore);
201 void authenticationRequired(QString prompt, QAuthenticator* authenticator);
204 void downloadProgress(qint64 bytesCurrent);
205 void downloadTotalChanged(quint64 bytesTotal);
207
208 // Finished signal
210};
211
212class QX_NETWORK_EXPORT SyncDownloadManager: public QObject
213{
214//-QObject Macro (Required for all QObject Derived Classes)-----------------------------------------------------------
215 Q_OBJECT
216
217//-Instance Members---------------------------------------------------------------------------------------------------
218private:
219 AsyncDownloadManager* mAsyncDm;
220 QEventLoop mSpinner;
221 DownloadManagerReport mReport;
222
223//-Constructor-------------------------------------------------------------------------------------------------------
224public:
225 SyncDownloadManager(QObject* parent = nullptr);
226
227//-Instance Functions----------------------------------------------------------------------------------------------
228public:
229 // Properties
230 int maxSimultaneous() const;
231 QNetworkRequest::RedirectPolicy redirectPolicy() const;
232 int transferTimeout() const;
233 int enumerationTimeout() const;
234 bool isOverwrite() const;
235 bool isStopOnError() const;
236 bool isSkipEnumeration() const;
237 bool isDeletePartialDownloads() const;
238 QCryptographicHash::Algorithm verificationMethod() const;
239 int taskCount() const;
240 bool hasTasks() const;
241 bool isProcessing() const;
242
243 void setMaxSimultaneous(int maxSimultaneous);
244 void setRedirectPolicy(QNetworkRequest::RedirectPolicy redirectPolicy);
245 void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant);
246 void setEnumerationTimeout(int timeout = 500);
247 void setOverwrite(bool overwrite);
248 void setStopOnError(bool stopOnError);
249 void setSkipEnumeration(bool skipEnumeration);
250 void setDeletePartialDownloads(bool deletePartialDownloads);
251 void setVerificationMethod(QCryptographicHash::Algorithm method);
252
253 // Tasks
254 void appendTask(const DownloadTask& task);
255 void clearTasks();
256
257 // Synchronous processing
258 DownloadManagerReport processQueue();
259
260//-Slots------------------------------------------------------------------------------------------------------------
261private slots:
262 void finishHandler(const Qx::DownloadManagerReport& dmr);
263
264public slots:
265 void abort();
266
267//-Signals------------------------------------------------------------------------------------------------------------
268signals:
269 // In-progress signals
270 void sslErrors(Qx::Error errorMsg, bool* ignore);
271 void authenticationRequired(QString prompt, QAuthenticator* authenticator);
274 void downloadProgress(qint64 bytesCurrent);
275 void downloadTotalChanged(quint64 bytesTotal);
277};
278
279}
280
281
282#endif // QX_DOWNLOADMANAGER_H
The AsyncDownloadManager class is used to queue and process one or more downloads in an asynchronous ...
Definition qx-downloadmanager.h:45
void downloadProgress(qint64 bytesCurrent)
void preSharedKeyAuthenticationRequired(QString prompt, QSslPreSharedKeyAuthenticator *authenticator)
void finished(Qx::DownloadManagerReport report)
void authenticationRequired(QString prompt, QAuthenticator *authenticator)
void downloadTotalChanged(quint64 bytesTotal)
void sslErrors(Qx::Error errorMsg, bool *ignore)
void proxyAuthenticationRequired(QString prompt, QAuthenticator *authenticator)
void downloadFinished(Qx::DownloadOpReport downloadReport)
The Cumulation template class tracks the sum of multiple key-value components that can be changed ind...
Definition qx-cumulation.h:21
The DownloadManagerReport class details the outcome of processing an AsyncDownloadManager or SyncDown...
Definition qx-downloadmanagerreport.h:23
The DownloadOpReport class details the result of a single file download.
Definition qx-downloadopreport.h:17
The Error class acts as an interface for an extensible variety of error objects.
Definition qx-error.h:38
The FileStreamWriter class is a specialized wrapper for QDataStream that narrows and simplifies its u...
Definition qx-filestreamwriter.h:18
The IoOpReport class is a container for details regarding the outcome of an IO operation.
Definition qx-ioopreport.h:53
The SyncDownloadManager class is used to queue and process one or more downloads in a synchronous man...
Definition qx-downloadmanager.h:213
void downloadProgress(qint64 bytesCurrent)
void downloadTotalChanged(quint64 bytesTotal)
void proxyAuthenticationRequired(QString prompt, QAuthenticator *authenticator)
void preSharedKeyAuthenticationRequired(QString prompt, QSslPreSharedKeyAuthenticator *authenticator)
void sslErrors(Qx::Error errorMsg, bool *ignore)
void downloadFinished(Qx::DownloadOpReport downloadReport)
void authenticationRequired(QString prompt, QAuthenticator *authenticator)
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-processwaiter.cpp:5
The qx-error.h header file provides access to the Error interface.
The DownloadTask struct contains the information necessary to download a file from a URL.
Definition qx-downloadtask.h:14