RabbitCommon v2.2.6
Loading...
Searching...
No Matches
Download.cpp
1#include "Download.h"
2
3#include <QStandardPaths>
4#include <QCoreApplication>
5#include <QDir>
6#include <QLoggingCategory>
7#include <QNetworkProxyFactory>
8
9namespace RabbitCommon {
10
11static Q_LOGGING_CATEGORY(log, "RabbitCommon.DownloadFile")
12
13CDownload::CDownload(QObject *parent)
14 : QObject{parent},
15 m_bSequence(false),
16 m_nBytesReceived(0)
17{}
18
19int CDownload::Start(QVector<QUrl> urls, QString szFileName, bool bSequence)
20{
21 int nRet = 0;
22 if(urls.isEmpty())
23 {
24 m_szError = "Urls is empty.";
25 qCritical(log) << m_szError;
26 return -1;
27 }
28 /*
29 QString szPath = urls[0].path();
30 QString szFile = szPath.mid(szPath.lastIndexOf("/"));
31 foreach(auto u, urls)
32 {
33 QString p = u.path();
34 QString f = p.mid(p.lastIndexOf("/"));
35 if(f != szFileName)
36 {
37 m_szError = "Urls is not same file:" + szFileName + "!=" + f;
38 qCritical(log) << m_szError;
39 return;
40 }
41 }//*/
42
43 m_Url = urls;
44 m_szFileName = szFileName;
45 m_bSequence = bSequence;
46 if(m_bSequence)
47 {
48 nRet = DownloadFile(0, m_Url[0]);
49 } else {
50 for(int i = 0; i < m_Url.length(); i++)
51 DownloadFile(i, m_Url[i]);
52 }
53 return nRet;
54}
55
56CDownload::~CDownload()
57{
58 QMap<QNetworkReply*, int>::Iterator it;
59 it = m_Reply.begin();
60 while(it != m_Reply.end())
61 {
62 QNetworkReply* r = it.key();
63 CloseReply(r, true);
64 it = m_Reply.begin();
65 }
66
67 foreach(auto f, m_DownloadFile)
68 {
69 if(f->isOpen())
70 f->close();
71 }
72}
73
74int CDownload::DownloadFile(int nIndex, const QUrl &url, bool bRedirection)
75{
76 int nRet = 0;
77
78 m_nBytesReceived = 0;
79 QSharedPointer<QFile> file;
80 if(bRedirection)
81 {
82 if(nIndex < 0 || nIndex >= m_DownloadFile.size())
83 {
84 m_szError = "The index["
85 + QString::number(nIndex)
86 + "] is out of bounds. [0 -"
87 + QString::number(m_DownloadFile.length())
88 + "]";
89 qCritical(log) << m_szError;
90 emit sigError(-1, m_szError);
91 return -1;
92 }
93 file = m_DownloadFile.at(nIndex);
94 if(!file)
95 {
96 m_szError = "file is null. index: "
97 + QString::number(nIndex);
98 qCritical(log) << m_szError;
99 emit sigError(-2, m_szError);
100 return -2;
101 }
102 } else {
103 if(nIndex < m_DownloadFile.size())
104 {
105 m_szError = "The index[" + QString::number(nIndex)
106 + "] is in of bounds. [0 -"
107 + QString::number(m_DownloadFile.length())
108 + "]";
109 qCritical(log) << m_szError;
110 return -3;
111 }
112 QString szTmp
113 = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
114 szTmp = szTmp + QDir::separator() + "Rabbit"
115 + QDir::separator() + qApp->applicationName()
116 + QDir::separator() + QString::number(nIndex);
117 QDir d;
118 if(!d.exists(szTmp))
119 d.mkpath(szTmp);
120 QString szPath = url.path();
121 if(m_szFileName.isEmpty())
122 {
123 m_szFileName = szPath.mid(szPath.lastIndexOf("/"));
124 }
125 if(m_szFileName.left(1) != "/" && m_szFileName.left(1) != "\\")
126 m_szFileName = QDir::separator() + m_szFileName;
127 QString szFile = szTmp + m_szFileName;
128
129 file = QSharedPointer<QFile>(new QFile(), &QObject::deleteLater);
130 if(!file)
131 {
132 m_szError = "new QFile fail";
133 qCritical(log) << m_szError;
134 return -4;
135 }
136 file->setFileName(szFile);
137 m_DownloadFile.insert(nIndex, file);
138 }
139
140 if(!file)
141 {
142 m_szError = "file is null. index:" + QString::number(nIndex) ;
143 qCritical(log) << m_szError;
144 return -5;
145 }
146
147 qInfo(log) << "Download file:"
148 << nIndex << url
149 << "(redirection:" << bRedirection << ")"
150 << file->fileName();
151
152 if(file->isOpen())
153 file->close();
154
155 if(url.isLocalFile())
156 {
157 qDebug(log) << "Is local file:" << url;
158 file->setFileName(url.toLocalFile());
159 if(QFile::exists(file->fileName()))
160 {
161 emit sigFinished(file->fileName());
162 return 0;
163 }
164
165 QString szErr = tr("The file is not exists: ") + file->fileName();
166 qCritical(log) << szErr;
167 emit sigError(-6, szErr);
168 return -6;
169 }
170
171 if(!file->open(QIODevice::WriteOnly))
172 {
173 m_szError = "Open file fail: " + file->fileName();
174 qDebug(log) << m_szError;
175 return -1;
176 }
177
178 QNetworkRequest request(url);
179 //https://blog.csdn.net/itjobtxq/article/details/8244509
180 /*QSslConfiguration config;
181 config.setPeerVerifyMode(QSslSocket::VerifyNone);
182 config.setProtocol(QSsl::AnyProtocol);
183 request.setSslConfiguration(config);
184 */
185
186 //* TODO: add set proxy
187
188 //*/
189 QNetworkReply* pReply = m_NetManager.get(request);
190 if(!pReply)
191 return -1;
192
193 m_Reply.insert(pReply, nIndex);
194
195 bool check = false;
196 check = connect(pReply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
197 Q_ASSERT(check);
198 check = connect(pReply, SIGNAL(downloadProgress(qint64, qint64)),
199 this, SLOT(slotDownloadProgress(qint64, qint64)));
200 Q_ASSERT(check);
201 check = connect(pReply,
202 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
203 SIGNAL(errorOccurred(QNetworkReply::NetworkError)),
204 #else
205 SIGNAL(error(QNetworkReply::NetworkError)),
206 #endif
207 this, SLOT(slotError(QNetworkReply::NetworkError)));
208 Q_ASSERT(check);
209 check = connect(pReply, SIGNAL(sslErrors(const QList<QSslError>)),
210 this, SLOT(slotSslError(const QList<QSslError>)));
211 Q_ASSERT(check);
212 check = connect(pReply, SIGNAL(finished()),
213 this, SLOT(slotFinished()));
214 Q_ASSERT(check);
215
216 return nRet;
217}
218
219void CDownload::slotReadyRead()
220{
221 //qDebug(log) << "CDownload::slotReadyRead()";
222 QNetworkReply* pReply = dynamic_cast<QNetworkReply*>(this->sender());
223 if(m_Reply.find(pReply) == m_Reply.end())
224 {
225 qCritical(log) << "The reply isn't exits";
226 return;
227 }
228 QSharedPointer<QFile> file = m_DownloadFile[m_Reply[pReply]];
229 if(!file)
230 {
231 qCritical(log) << "The file isn't exits.";
232 return;
233 }
234 if(file && file->isOpen())
235 {
236 QByteArray d = pReply->readAll();
237 //qDebug(log) << d;
238 file->write(d);
239 }
240}
241
242void CDownload::slotFinished()
243{
244 QNetworkReply* pReply = dynamic_cast<QNetworkReply*>(this->sender());
245 if(m_Reply.find(pReply) == m_Reply.end())
246 {
247 qCritical(log) << "The reply isn't exits" << pReply->url();
248 return;
249 }
250 int nIndex = m_Reply[pReply];
251 qInfo(log) << "Download finished:" << nIndex << pReply->url();
252
253 QVariant redirectionTarget;
254 if(pReply)
255 redirectionTarget = pReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
256
257 CloseReply(pReply);
258
259 if(redirectionTarget.isValid())
260 {
261 QUrl u = redirectionTarget.toUrl();
262 if(u.isValid())
263 {
264 qDebug(log) << "redirectionTarget:url:" << u;
265 DownloadFile(nIndex, u, true);
266 }
267 return;
268 }
269
270 if(!m_bSequence)
271 {
272 // Clean other reply
273 QMap<QNetworkReply*, int>::Iterator it;
274 it = m_Reply.begin();
275 while(it != m_Reply.end())
276 {
277 QNetworkReply* r = it.key();
278 CloseReply(r, true);
279 it = m_Reply.begin();
280 }
281 }
282
283 QSharedPointer<QFile> file = m_DownloadFile[nIndex];
284 if(!file)
285 {
286 qCritical(log) << "The file isn't exits. index:" << nIndex;
287 return;
288 }
289 file->close();
290 emit sigFinished(file->fileName());
291}
292
293void CDownload::slotError(QNetworkReply::NetworkError e)
294{
295 QNetworkReply* pReply = dynamic_cast<QNetworkReply*>(this->sender());
296 if(m_Reply.find(pReply) == m_Reply.end())
297 {
298 qCritical(log) << "Network error: The reply isn't exits."
299 << pReply->url() << "NetworkError:" << e;
300 return;
301 }
302
303 int nIndex = m_Reply[pReply];
304 QString szErr = pReply->errorString();
305 qDebug(log) << "Network error[" << e << "]:" << szErr
306 << "index:" << nIndex << pReply->url();
307 CloseReply(pReply);
308
309 QSharedPointer<QFile> file = m_DownloadFile[nIndex];
310 if(!file)
311 {
312 qCritical(log) << "Network error: The file is null. index: "
313 + QString::number(nIndex);
314 return;
315 }
316 file->close();
317
318 if(m_bSequence && (nIndex < m_Url.size() - 1))
319 {
320 nIndex++;
321 DownloadFile(nIndex, m_Url[nIndex]);
322 return;
323 }
324
325 if(m_Reply.empty())
326 {
327 if(m_szError.isEmpty()) {
328 m_szError = "Network error: ";
329 if(!szErr.isEmpty())
330 m_szError += szErr + "; ";
331 m_szError += "from " + m_Url[nIndex].toString()
332 + " to " + file->fileName();
333 }
334 emit sigError(e, m_szError);
335 }
336}
337
338void CDownload::slotSslError(const QList<QSslError> e)
339{
340 QNetworkReply* pReply = dynamic_cast<QNetworkReply*>(this->sender());
341 if(m_Reply.find(pReply) == m_Reply.end())
342 {
343 qCritical(log) << "ssl error: The reply isn't exits. QSslError:" << e;
344 return;
345 }
346 int nIndex = m_Reply[pReply];
347 QString szErr = pReply->errorString();
348 qDebug(log) << "ssl error[" << e << "]:" << szErr
349 << "index:" << nIndex << pReply->url();
350 CloseReply(pReply);
351 QSharedPointer<QFile> file = m_DownloadFile[nIndex];
352 if(!file)
353 {
354 qCritical(log) << "ssl error: The file null. index: "
355 + QString::number(nIndex);
356 return;
357 }
358 file->close();
359
360 if(m_bSequence && (nIndex < m_Url.size() - 1))
361 {
362 nIndex++;
363 DownloadFile(nIndex, m_Url[nIndex]);
364 return;
365 }
366
367 if(m_Reply.empty())
368 {
369 QString sErr;
370 foreach(QSslError s, e)
371 sErr += s.errorString() + " ";
372 m_szError = sErr;
373 if(m_szError.isEmpty())
374 {
375 m_szError = "ssl error: ";
376 if(!szErr.isEmpty())
377 m_szError += szErr + "; ";
378 m_szError += "from " + m_Url[nIndex].toString()
379 + " to " + file->fileName();
380 }
381 emit sigError(-1, m_szError);
382 }
383}
384
385void CDownload::slotDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
386{
387 QNetworkReply* pReply = dynamic_cast<QNetworkReply*>(this->sender());
388 if(!pReply)
389 {
390 qCritical(log) << "slotDownloadProgress: The sender is not reply";
391 return;
392 }
393 if(m_Reply.find(pReply) == m_Reply.end())
394 {
395 qCritical(log) << "slotDownloadProgress: The reply isn't exits"
396 << pReply->url();
397 return;
398 }
399 int nIndex = m_Reply[pReply];
400 QSharedPointer<QFile> file = m_DownloadFile[nIndex];
401 if(!file)
402 {
403 qCritical(log) << "slotDownloadProgress: The file null. index: "
404 + QString::number(nIndex);
405 return;
406 }
407
408 if(bytesTotal > 0)
409 {
410 if(m_nBytesReceived < bytesReceived)
411 {
412 m_nBytesReceived = bytesReceived;
413 emit sigDownloadProgress(m_nBytesReceived, bytesTotal);
414 }
415 qDebug(log) << tr("Downloading %1% [%2/%3]")
416 .arg(QString::number(bytesReceived * 100 / bytesTotal))
417 .arg(QString::number(bytesReceived)).arg(QString::number(bytesTotal))
418 << m_Url[nIndex] << file->fileName();
419 }
420}
421
422int CDownload::CloseReply(QNetworkReply *pReply, bool bAbort)
423{
424 if(pReply)
425 {
426 m_Reply.remove(pReply);
427 pReply->disconnect();
428 if(bAbort && pReply->isRunning())
429 pReply->abort();
430 pReply->deleteLater();
431 }
432 return 0;
433}
434
435} // namespace RabbitCommon
int Start(QVector< QUrl > urls, QString szFileName=QString(), bool bSequence=false)
Definition Download.cpp:19
void sigFinished(const QString szFile)
int DownloadFile(int nIndex, const QUrl &url, bool bRedirection=false)
DownloadFile.
Definition Download.cpp:74