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