|
1 /** |
|
2 This file is part of CWRT package ** |
|
3 |
|
4 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** |
|
5 |
|
6 This program is free software: you can redistribute it and/or modify |
|
7 it under the terms of the GNU (Lesser) General Public License as |
|
8 published by the Free Software Foundation, version 2.1 of the License. |
|
9 This program is distributed in the hope that it will be useful, but |
|
10 WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 (Lesser) General Public License for more details. You should have |
|
13 received a copy of the GNU (Lesser) General Public License along |
|
14 with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 */ |
|
16 |
|
17 #include "clientdownload.h" |
|
18 #include "downloadmanager.h" |
|
19 #include "downloadbackend.h" |
|
20 #include "downloadcore.h" |
|
21 #include "downloadfactory.h" |
|
22 #include "downloadstore.h" |
|
23 #include <QCoreApplication> |
|
24 #include <QDateTime> |
|
25 |
|
26 //private implementation |
|
27 class DownloadBackendPrivate |
|
28 { |
|
29 DM_DECLARE_PUBLIC(DownloadBackend); |
|
30 public: |
|
31 DownloadBackendPrivate(); |
|
32 ~DownloadBackendPrivate(); |
|
33 |
|
34 DownloadCore *m_downloadCore; // not owned |
|
35 ClientDownload *m_download; //// not owned, only reference |
|
36 DownloadInfo *m_dlInfo; // not owned |
|
37 qint64 m_totalSize; // total size of the download |
|
38 qint64 m_currentDownloadedSize; // current downloaded size |
|
39 qint64 m_lastPausedSize; |
|
40 DownloadState m_downloadState; // state of the download |
|
41 bool m_infoDeleted; // flag to indicate the info deletion |
|
42 QDateTime m_startTime; // download start/resumed time |
|
43 QDateTime m_endTime; // download completed time |
|
44 int m_progressCounter; |
|
45 }; |
|
46 |
|
47 DownloadBackendPrivate::DownloadBackendPrivate() |
|
48 { |
|
49 m_downloadCore = 0; |
|
50 m_download = 0; |
|
51 m_dlInfo = 0; |
|
52 m_totalSize = 0; |
|
53 m_currentDownloadedSize = 0; |
|
54 m_lastPausedSize =0; |
|
55 m_infoDeleted = false; |
|
56 m_progressCounter = 1; |
|
57 } |
|
58 |
|
59 DownloadBackendPrivate::~DownloadBackendPrivate() |
|
60 { |
|
61 #if 0 //m_downloadCore may be stale. |
|
62 if(m_downloadCore) |
|
63 { |
|
64 // cancel if there is any transaction |
|
65 m_downloadCore->abort(); |
|
66 } |
|
67 #endif |
|
68 } |
|
69 |
|
70 DownloadBackend::DownloadBackend(DownloadCore *dlCore, ClientDownload* dl) |
|
71 { |
|
72 DM_INITIALIZE(DownloadBackend); |
|
73 priv->m_downloadCore = dlCore; |
|
74 priv->m_download = dl; |
|
75 priv->m_dlInfo = dl->downloadInfo(); |
|
76 // connect all the signals from network |
|
77 connect(dlCore, SIGNAL(downloadProgress(qint64 , qint64 )), this, SLOT(bytesRecieved(qint64 , qint64 ))); |
|
78 connect(dlCore, SIGNAL(finished()), this, SLOT(handleFinished())); |
|
79 connect(dlCore, SIGNAL(metaDataChanged()), this, SLOT(headerReceived())); |
|
80 connect(dlCore, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError))); |
|
81 connect(dlCore, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(bytesUploaded(qint64, qint64))); |
|
82 |
|
83 // save the content type and url |
|
84 setValue(DownloadInfo::EContentType, priv->m_downloadCore->contentType()); |
|
85 setValue(DownloadInfo::EUrl, priv->m_downloadCore->url()); |
|
86 setValue(DownloadInfo::EETag, priv->m_downloadCore->entityTag()); |
|
87 postEvent(Started, NULL); |
|
88 } |
|
89 |
|
90 DownloadBackend::~DownloadBackend() |
|
91 { |
|
92 DM_UNINITIALIZE(DownloadBackend); |
|
93 } |
|
94 |
|
95 int DownloadBackend::pause() |
|
96 { |
|
97 DM_PRIVATE(DownloadBackend); |
|
98 setDownloadState(DlPaused); |
|
99 priv->m_downloadCore->abort(); |
|
100 return 0; |
|
101 } |
|
102 |
|
103 int DownloadBackend::resume() |
|
104 { |
|
105 DM_PRIVATE(DownloadBackend); |
|
106 setDownloadState(DlInprogress); |
|
107 // save the content type and url |
|
108 setValue(DownloadInfo::EUrl, priv->m_downloadCore->url()); |
|
109 setValue(DownloadInfo::EContentType, priv->m_downloadCore->contentType()); |
|
110 priv->m_lastPausedSize = priv->m_currentDownloadedSize; |
|
111 priv->m_downloadCore->resumeDownload(priv->m_currentDownloadedSize); |
|
112 priv->m_startTime = QDateTime::currentDateTime(); |
|
113 postEvent(Progress, NULL); |
|
114 return 0; |
|
115 } |
|
116 |
|
117 int DownloadBackend::cancel() |
|
118 { |
|
119 DM_PRIVATE(DownloadBackend); |
|
120 setDownloadState(DlCancelled); |
|
121 // cancel the transaction |
|
122 priv->m_downloadCore->abort(); |
|
123 // delete the temporary storage |
|
124 deleteStore(); |
|
125 // reset the states |
|
126 priv->m_totalSize = 0; |
|
127 priv->m_currentDownloadedSize = 0; |
|
128 priv->m_lastPausedSize = 0; |
|
129 return 0; |
|
130 } |
|
131 |
|
132 QVariant DownloadBackend::getAttribute(DownloadAttribute attr) |
|
133 { |
|
134 DM_PRIVATE(DownloadBackend); |
|
135 switch(attr) |
|
136 { |
|
137 case DlDownloadedSize: |
|
138 { |
|
139 return QVariant(priv->m_currentDownloadedSize); |
|
140 } |
|
141 case DlTotalSize: |
|
142 { |
|
143 return QVariant(priv->m_totalSize); |
|
144 } |
|
145 case DlDownloadState: |
|
146 { |
|
147 return QVariant(priv->m_downloadState); |
|
148 } |
|
149 case DlSourceUrl: |
|
150 { |
|
151 return QVariant(priv->m_downloadCore->url()); |
|
152 } |
|
153 case DlContentType: |
|
154 { |
|
155 return QVariant(priv->m_downloadCore->contentType()); |
|
156 } |
|
157 case DlStartTime: |
|
158 { |
|
159 return QVariant(priv->m_startTime); |
|
160 } |
|
161 case DlEndTime: |
|
162 { |
|
163 if (priv->m_downloadState == DlCompleted) |
|
164 return priv->m_endTime; |
|
165 else |
|
166 return QVariant(); |
|
167 } |
|
168 case DlElapsedTime: |
|
169 { |
|
170 if (priv->m_downloadState == DlCompleted) |
|
171 return QVariant((priv->m_endTime.toTime_t()-priv->m_startTime.toTime_t())); |
|
172 |
|
173 if (priv->m_downloadState != DlInprogress) |
|
174 return QVariant(); |
|
175 QDateTime currentTime = QDateTime::currentDateTime(); |
|
176 uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t(); |
|
177 return QVariant(timeElasped); |
|
178 } |
|
179 case DlRemainingTime: |
|
180 { |
|
181 if (priv->m_downloadState != DlInprogress) |
|
182 return QVariant(); |
|
183 QDateTime currentTime = QDateTime::currentDateTime(); |
|
184 uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t(); |
|
185 // total bytes recieved since last start/resume |
|
186 qint64 totalBytesRecieved = priv->m_currentDownloadedSize - priv->m_lastPausedSize; |
|
187 qint64 remainingSize = priv->m_totalSize - priv->m_currentDownloadedSize; |
|
188 if (totalBytesRecieved > 0) |
|
189 return QVariant((timeElasped*remainingSize)/totalBytesRecieved); |
|
190 else |
|
191 return QVariant(); |
|
192 } |
|
193 case DlSpeed: |
|
194 { |
|
195 if (priv->m_downloadState != DlInprogress) |
|
196 return QVariant(); |
|
197 QDateTime currentTime = QDateTime::currentDateTime(); |
|
198 uint timeElasped = currentTime.toTime_t() - priv->m_startTime.toTime_t(); |
|
199 qint64 totalBytesRecieved = priv->m_currentDownloadedSize - priv->m_lastPausedSize; |
|
200 if (timeElasped > 0) |
|
201 return QVariant(totalBytesRecieved/timeElasped); |
|
202 else |
|
203 return QVariant(); |
|
204 } |
|
205 case DlPercentage: |
|
206 { |
|
207 if (priv->m_totalSize > 0) |
|
208 return QVariant((priv->m_currentDownloadedSize*100)/priv->m_totalSize); |
|
209 else |
|
210 return QVariant(); |
|
211 } |
|
212 case DlLastError: |
|
213 { |
|
214 return QVariant(priv->m_downloadCore->lastError()); |
|
215 } |
|
216 case DlLastErrorString: |
|
217 { |
|
218 return QVariant(priv->m_downloadCore->lastErrorString()); |
|
219 } |
|
220 default: |
|
221 { |
|
222 break; |
|
223 } |
|
224 } |
|
225 return QVariant(); |
|
226 |
|
227 } |
|
228 |
|
229 int DownloadBackend::setAttribute(DownloadAttribute /*attr*/, const QVariant& /*value*/) |
|
230 { |
|
231 return -1; |
|
232 } |
|
233 |
|
234 void DownloadBackend::bytesRecieved(qint64 bytesRecieved, qint64 bytesTotal) |
|
235 { |
|
236 DM_PRIVATE(DownloadBackend); |
|
237 if((priv->m_downloadState == DlFailed) || (bytesRecieved == 0)) |
|
238 { |
|
239 return; |
|
240 } |
|
241 |
|
242 // in case of resumed downloads, we recieve total size remained to download |
|
243 setTotalSize(priv->m_lastPausedSize + bytesTotal); |
|
244 priv->m_currentDownloadedSize = priv->m_lastPausedSize + bytesRecieved; |
|
245 setDownloadState(DlInprogress); |
|
246 // store the recieved chunk |
|
247 store(priv->m_downloadCore->reply()->readAll(), false); |
|
248 postEvent(Progress, NULL); |
|
249 } |
|
250 |
|
251 void DownloadBackend::handleFinished() |
|
252 { |
|
253 DM_PRIVATE(DownloadBackend); |
|
254 |
|
255 DownloadState state = priv->m_downloadState; |
|
256 if( state == DlFailed ) |
|
257 { |
|
258 postEvent(Failed, NULL); |
|
259 return; |
|
260 } |
|
261 if( state == DlPaused ) |
|
262 { |
|
263 postEvent(Paused, NULL); |
|
264 return; |
|
265 } |
|
266 if( state == DlCancelled ) |
|
267 { |
|
268 postEvent(Cancelled, NULL); |
|
269 return; |
|
270 } |
|
271 if(priv->m_currentDownloadedSize < priv->m_totalSize) |
|
272 { |
|
273 // all packets are not recieved, so it is not last chunk |
|
274 // should be some network problem |
|
275 store(priv->m_downloadCore->reply()->readAll(), false); |
|
276 postEvent(NetworkLoss, NULL); |
|
277 } |
|
278 else |
|
279 { |
|
280 //finish is successful |
|
281 store(priv->m_downloadCore->reply()->readAll(), true); |
|
282 //finish is successful |
|
283 setDownloadState(DlCompleted); |
|
284 priv->m_endTime = QDateTime::currentDateTime(); |
|
285 postEvent(Completed, NULL); |
|
286 } |
|
287 } |
|
288 |
|
289 void DownloadBackend::error(QNetworkReply::NetworkError code) |
|
290 { |
|
291 DM_PRIVATE(DownloadBackend); |
|
292 if((code == QNetworkReply::OperationCanceledError) && (priv->m_downloadState == DlCancelled)) |
|
293 { |
|
294 return; |
|
295 } |
|
296 if(code == QNetworkReply::OperationCanceledError) |
|
297 { |
|
298 // this means user has paused the download |
|
299 setDownloadState(DlPaused); |
|
300 } |
|
301 else if(code != QNetworkReply::NoError) |
|
302 { |
|
303 priv->m_downloadCore->setLastError(code); |
|
304 if(priv->m_downloadCore->reply()) |
|
305 { |
|
306 priv->m_downloadCore->setLastErrorString(priv->m_downloadCore->reply()->errorString()); |
|
307 } |
|
308 setDownloadState(DlFailed); |
|
309 postEvent(Error, NULL); |
|
310 } |
|
311 } |
|
312 |
|
313 void DownloadBackend::postEvent(DEventType type, DlEventAttributeMap* attrMap) |
|
314 { |
|
315 DM_PRIVATE(DownloadBackend); |
|
316 // The client if it doesn't want progress events then it can set the DownloadMgrProgress mode as quiet |
|
317 // If it wants progress events at regular intervals then it has to specify the KiloBytes at which it requires the progress event. |
|
318 // By default, the DownloadMgrProgress Mode is non-quiet with progress events being sent at every 5KB downloaded. |
|
319 DownloadMgrProgressMode mode = (DownloadMgrProgressMode)(priv->m_download->downloadManager()->getAttribute(DlMgrProgressMode)).toInt(); |
|
320 if ((mode == Quiet) && (type == Progress)) |
|
321 return; |
|
322 |
|
323 qlonglong kBytes = priv->m_download->getAttribute(DlProgressInterval).toLongLong() * 1024; |
|
324 if (mode == NonQuiet && type == Progress) |
|
325 { |
|
326 if ((priv->m_currentDownloadedSize/(kBytes * priv->m_progressCounter)) > 0) |
|
327 { |
|
328 priv->m_progressCounter++; |
|
329 postDownloadEvent(type, attrMap); |
|
330 } |
|
331 } |
|
332 else |
|
333 postDownloadEvent(type, attrMap); |
|
334 } |
|
335 |
|
336 DownloadState DownloadBackend::downloadState(void) |
|
337 { |
|
338 DM_PRIVATE(DownloadBackend); |
|
339 return priv->m_downloadState; |
|
340 } |
|
341 |
|
342 void DownloadBackend::setDownloadState(DownloadState state) |
|
343 { |
|
344 DM_PRIVATE(DownloadBackend); |
|
345 priv->m_downloadState = state; |
|
346 // save the download state |
|
347 setValue(DownloadInfo::EDlState, priv->m_downloadState); |
|
348 if((state == DlFailed) || (state == DlCompleted) || (state == DlCancelled)) |
|
349 { |
|
350 // remove dl info |
|
351 deleteInfo(); |
|
352 } |
|
353 } |
|
354 |
|
355 void DownloadBackend::setDownloadedDataSize(qint64 size) |
|
356 { |
|
357 DM_PRIVATE(DownloadBackend); |
|
358 priv->m_currentDownloadedSize = size; |
|
359 return; |
|
360 } |
|
361 |
|
362 void DownloadBackend::setTotalSize(qint64 size) |
|
363 { |
|
364 DM_PRIVATE(DownloadBackend); |
|
365 priv->m_totalSize = size; |
|
366 setValue(DownloadInfo::ETotalSize, priv->m_totalSize); |
|
367 return; |
|
368 } |
|
369 |
|
370 void DownloadBackend::setStartTime() |
|
371 { |
|
372 DM_PRIVATE(DownloadBackend); |
|
373 priv->m_startTime = QDateTime::currentDateTime(); |
|
374 } |
|
375 |
|
376 ClientDownload* DownloadBackend::download(void) |
|
377 { |
|
378 DM_PRIVATE(DownloadBackend); |
|
379 return priv->m_download; |
|
380 } |
|
381 |
|
382 /* Helper functions to access download info */ |
|
383 |
|
384 int DownloadBackend::setValue(DownloadInfo::Key aKey, const QString& aStrValue) |
|
385 { |
|
386 DM_PRIVATE(DownloadBackend); |
|
387 if(priv->m_infoDeleted) |
|
388 return 0; |
|
389 return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aStrValue, priv->m_download->parentId()); |
|
390 } |
|
391 |
|
392 int DownloadBackend::setValueForChild(DownloadInfo::Key aKey, const QString& aStrValue, int aChildId) |
|
393 { |
|
394 DM_PRIVATE(DownloadBackend); |
|
395 if(priv->m_infoDeleted) |
|
396 return 0; |
|
397 return priv->m_dlInfo->setValueForChild(priv->m_download->id(), aKey, aStrValue, aChildId); |
|
398 } |
|
399 |
|
400 int DownloadBackend::setValue(DownloadInfo::Key aKey, long aIntValue) |
|
401 { |
|
402 DM_PRIVATE(DownloadBackend); |
|
403 if(priv->m_infoDeleted) |
|
404 return 0; |
|
405 return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aIntValue, priv->m_download->parentId()); |
|
406 } |
|
407 |
|
408 int DownloadBackend::setValueForChild(DownloadInfo::Key aKey, long aIntValue, int aChildId) |
|
409 { |
|
410 DM_PRIVATE(DownloadBackend); |
|
411 if(priv->m_infoDeleted) |
|
412 return 0; |
|
413 return priv->m_dlInfo->setValueForChild(priv->m_download->id(), aKey, aIntValue, aChildId); |
|
414 } |
|
415 |
|
416 int DownloadBackend::setValue(DownloadInfo::Key aKey, const QList<QVariant>& aChildIds) |
|
417 { |
|
418 DM_PRIVATE(DownloadBackend); |
|
419 if(priv->m_infoDeleted) |
|
420 return 0; |
|
421 return priv->m_dlInfo->setValue(priv->m_download->id(), aKey, aChildIds); |
|
422 } |
|
423 |
|
424 int DownloadBackend::getValue(DownloadInfo::Key aKey, QString& aStrValue) |
|
425 { |
|
426 DM_PRIVATE(DownloadBackend); |
|
427 if(priv->m_infoDeleted) |
|
428 return 0; |
|
429 return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aStrValue, priv->m_download->parentId()); |
|
430 } |
|
431 |
|
432 int DownloadBackend::getValueForChild(DownloadInfo::Key aKey, QString& aStrValue, int aChildId) |
|
433 { |
|
434 DM_PRIVATE(DownloadBackend); |
|
435 if(priv->m_infoDeleted) |
|
436 return 0; |
|
437 return priv->m_dlInfo->getValueForChild(priv->m_download->id(), aKey, aStrValue, aChildId); |
|
438 } |
|
439 |
|
440 int DownloadBackend::getValue(DownloadInfo::Key aKey, long& aIntValue) |
|
441 { |
|
442 DM_PRIVATE(DownloadBackend); |
|
443 if(priv->m_infoDeleted) |
|
444 return 0; |
|
445 return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aIntValue, priv->m_download->parentId()); |
|
446 } |
|
447 |
|
448 int DownloadBackend::getValueForChild(DownloadInfo::Key aKey, long& aIntValue, int aChildId) |
|
449 { |
|
450 DM_PRIVATE(DownloadBackend); |
|
451 if(priv->m_infoDeleted) |
|
452 return 0; |
|
453 return priv->m_dlInfo->getValueForChild(priv->m_download->id(), aKey, aIntValue, aChildId); |
|
454 |
|
455 } |
|
456 |
|
457 int DownloadBackend::getValue(DownloadInfo::Key aKey, QList<QVariant>& aChildIds) |
|
458 { |
|
459 DM_PRIVATE(DownloadBackend); |
|
460 if(priv->m_infoDeleted) |
|
461 return 0; |
|
462 return priv->m_dlInfo->getValue(priv->m_download->id(), aKey, aChildIds); |
|
463 } |
|
464 |
|
465 int DownloadBackend::deleteInfo() |
|
466 { |
|
467 DM_PRIVATE(DownloadBackend); |
|
468 if ((InActive == priv->m_download->downloadManager()->getAttribute(DlMgrPersistantMode)) |
|
469 && (DlCompleted == priv->m_downloadState)) |
|
470 return 0; |
|
471 priv->m_infoDeleted = true; |
|
472 return priv->m_dlInfo->remove(priv->m_download->id(), priv->m_download->parentId()); |
|
473 } |
|
474 void DownloadBackend::postDownloadEvent(DEventType type, DlEventAttributeMap* attrMap) |
|
475 { |
|
476 DM_PRIVATE(DownloadBackend); |
|
477 EventReceiverList list = priv->m_download->eventReceivers(); |
|
478 for(int i=0; i<list.size(); i++) |
|
479 { |
|
480 if(list[i]) |
|
481 { |
|
482 DownloadEvent *event = new DownloadEvent(type, attrMap, priv->m_download->id()); |
|
483 QCoreApplication::postEvent(list[i], event); |
|
484 } |
|
485 } |
|
486 } |