Lomiri Download Manager 0.1.1
A session-wide downloading service
 
Loading...
Searching...
No Matches
download_impl.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013-2015 Canonical Ltd.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of version 3 of the GNU Lesser General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301, USA.
17 */
18
19#include <QProcessEnvironment>
21#include "download_impl.h"
22
23namespace {
24 const QString CLICK_PACKAGE_PROPERTY = "ClickPackage";
25 const QString SHOW_INDICATOR_PROPERTY = "ShowInIndicator";
26 const QString TITLE_PROPERTY = "Title";
27}
28
29namespace Lomiri {
30
31namespace DownloadManager {
32
33using namespace Logging;
34
35DownloadImpl::DownloadImpl(const QDBusConnection& conn,
36 const QString& servicePath,
37 const QDBusObjectPath& objectPath,
38 QObject* parent)
39 : Download(parent),
40 _id(objectPath.path()),
41 _conn(conn),
42 _servicePath(servicePath) {
43
44 _dbusInterface = new DownloadInterface(servicePath,
45 _id, conn);
46
47 _propertiesInterface = new PropertiesInterface(servicePath,
48 _id, conn);
49
50 // fwd all the signals but the error one
51 auto connected = connect(_dbusInterface, &DownloadInterface::canceled,
52 this, &Download::canceled);
53
54 if (!connected) {
55 Logger::log(Logger::Critical,
56 "Could not connect to signal DownloadInterface::canceled");
57 }
58
59 connected = connect(_dbusInterface, &DownloadInterface::finished,
60 this, &Download::finished);
61 if (!connected) {
62 Logger::log(Logger::Critical,
63 "Could not connect to signal &DownloadInterface::finished");
64 }
65
66 connected = connect(_dbusInterface, &DownloadInterface::finished,
67 this, &DownloadImpl::onFinished);
68 if (!connected) {
69 Logger::log(Logger::Critical,
70 "Could not connect to signal &DownloadInterface::finished");
71 }
72
73 connected = connect(_dbusInterface, &DownloadInterface::paused,
74 this, &Download::paused);
75 if (!connected) {
76 Logger::log(Logger::Critical,
77 "Could not connect to signal DownloadInterface::paused");
78 }
79
80 connected = connect(_dbusInterface, &DownloadInterface::processing,
81 this, &Download::processing);
82 if (!connected) {
83 Logger::log(Logger::Critical,
84 "Could not connect to signal DownloadInterface::processing");
85 }
86
87 connected = connect(_dbusInterface, static_cast<void(DownloadInterface::*)
88 (qulonglong, qulonglong)>(&DownloadInterface::progress),
89 this, static_cast<void(Download::*)
90 (qulonglong, qulonglong)>(&Download::progress));
91 if (!connected) {
92 Logger::log(Logger::Critical,
93 "Could not connect to signal &DownloadInterface::progress");
94 }
95
96 connected = connect(_dbusInterface, &DownloadInterface::resumed,
97 this, &Download::resumed);
98 if (!connected) {
99 Logger::log(Logger::Critical,
100 "Could not connect to signal &DownloadInterface::resumed");
101 }
102
103 connected = connect(_dbusInterface, &DownloadInterface::started,
104 this, &Download::started);
105 if (!connected) {
106 Logger::log(Logger::Critical,
107 "Could not connect to signal &DownloadInterface::started");
108 }
109
110 // connect to the different type of errors that will later be converted to
111 // the error type to be used by the client.
112 connected = connect(_dbusInterface, &DownloadInterface::httpError,
113 this, &DownloadImpl::onHttpError);
114 if (!connected) {
115 Logger::log(Logger::Critical,
116 "Could not connect to signal &DownloadInterface::httpError");
117 }
118
119 connected = connect(_dbusInterface, &DownloadInterface::networkError,
120 this, &DownloadImpl::onNetworkError);
121 if (!connected) {
122 Logger::log(Logger::Critical,
123 "Could not connect to signal &DownloadInterface::networkError");
124 }
125
126 connected = connect(_dbusInterface, &DownloadInterface::processError,
127 this, &DownloadImpl::onProcessError);
128 if (!connected) {
129 Logger::log(Logger::Critical,
130 "Could not connect to signal &DownloadInterface::processError");
131 }
132
133 connected = connect(_dbusInterface, &DownloadInterface::authError,
134 this, &DownloadImpl::onAuthError);
135 if (!connected) {
136 Logger::log(Logger::Critical,
137 "Could not connect to signal &DownloadInterface::authError");
138 }
139
140 connected = connect(_dbusInterface, &DownloadInterface::hashError,
141 this, &DownloadImpl::onHashError);
142 if (!connected) {
143 Logger::log(Logger::Critical,
144 "Could not connect to signal &DownloadInterface::authError");
145 }
146
147 connected = connect(_propertiesInterface, &PropertiesInterface::PropertiesChanged,
148 this, &DownloadImpl::onPropertiesChanged);
149 if (!connected) {
150 Logger::log(Logger::Critical,
151 "Could not connect to signal &PropertiesInterface::PropertiesChanged");
152 }
153}
154
155DownloadImpl::DownloadImpl(const QDBusConnection& conn, Error* err, QObject* parent)
156 : Download(parent),
157 _isError(true),
158 _lastError(err),
159 _conn(conn) {
160}
161
162DownloadImpl::~DownloadImpl() {
163 delete _lastError;
164 delete _dbusInterface;
165 delete _propertiesInterface;
166}
167
168void
169DownloadImpl::setLastError(Error* err) {
170 Logger::log(Logger::Debug,
171 QString("Download{%1} setLastError(%2)").arg(_id).arg(
172 err->errorString()));
173 if (_lastError != nullptr) {
174 delete _lastError;
175 }
176 _lastError = err;
177 _isError = true;
178 emit Download::error(err);
179}
180
181void
182DownloadImpl::setLastError(const QDBusError& err) {
183 setLastError(new DBusError(err, this));
184}
185
186void
187DownloadImpl::start() {
188 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
189 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
190 return;
191 }
192 Logger::log(Logger::Debug, QString("Download{%1} start())").arg(_id));
193 QDBusPendingCall call =
194 _dbusInterface->start();
195 auto watcher = new DownloadPCW(_conn, _servicePath,
196 call, this);
197 Q_UNUSED(watcher);
198}
199
200void
201DownloadImpl::pause() {
202 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
203 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
204 return;
205 }
206 Logger::log(Logger::Debug, QString("Download{%1} pause())").arg(_id));
207 QDBusPendingCall call =
208 _dbusInterface->pause();
209 auto watcher = new DownloadPCW(_conn, _servicePath,
210 call, this);
211 Q_UNUSED(watcher);
212}
213
214void
215DownloadImpl::resume() {
216 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
217 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
218 return;
219 }
220 Logger::log(Logger::Debug, QString("Download{%1} resume())").arg(_id));
221 QDBusPendingCall call =
222 _dbusInterface->resume();
223 auto watcher = new DownloadPCW(_conn, _servicePath,
224 call, this);
225 Q_UNUSED(watcher);
226}
227
228void
229DownloadImpl::cancel() {
230 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
231 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
232 return;
233 }
234 Logger::log(Logger::Debug, QString("Download{%1} cancel())").arg(_id));
235 QDBusPendingCall call =
236 _dbusInterface->cancel();
237 auto watcher = new DownloadPCW(_conn, _servicePath,
238 call, this);
239 Q_UNUSED(watcher);
240}
241
242void
243DownloadImpl::collected() {
244 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
245 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
246 return;
247 }
248 Logger::log(Logger::Debug, QString("Download{%1} collected()").arg(_id));
249 QDBusPendingReply<> reply =
250 _dbusInterface->collected();
251 // block, the call should be fast enough
252 reply.waitForFinished();
253 if (reply.isError()) {
254 Logger::log(Logger::Error, "Error when setting download collected");
255 setLastError(reply.error());
256 }
257}
258
259void
260DownloadImpl::allowMobileDownload(bool allowed) {
261 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
262 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
263 return;
264 }
265 Logger::log(Logger::Debug,
266 QString("Download{%1} allowMobileDownload%2())").arg(_id).arg(allowed));
267 QDBusPendingReply<> reply =
268 _dbusInterface->allowGSMDownload(allowed);
269 // block, the call should be fast enough
270 reply.waitForFinished();
271 if (reply.isError()) {
272 Logger::log(Logger::Error, "Error when setting mobile data usage");
273 setLastError(reply.error());
274 }
275}
276
277bool
278DownloadImpl::isMobileDownloadAllowed() {
279 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
280 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
281 return false;
282 }
283 Logger::log(Logger::Debug,
284 QString("Download{%1} isMobileDownloadAllowed").arg(_id));
285 QDBusPendingReply<bool> reply =
286 _dbusInterface->isGSMDownloadAllowed();
287 // block, the call should be fast enough
288 reply.waitForFinished();
289 if (reply.isError()) {
290 Logger::log(Logger::Error, "Error when querying mobile data usage");
291 setLastError(reply.error());
292 return false;
293 } else {
294 auto result = reply.value();
295 return result;
296 }
297}
298
299void
300DownloadImpl::setDestinationDir(const QString& path) {
301 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
302 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
303 return;
304 }
305 Logger::log(Logger::Debug, QString("Dowmload{%1} setDestinationDir(%2)")
306 .arg(_id).arg(path));
307 QDBusPendingReply<> reply =
308 _dbusInterface->setDestinationDir(path);
309 // block, the call should be fast enough
310 reply.waitForFinished();
311 if (reply.isError()) {
312 Logger::log(Logger::Error, "Error setting the download directory");
313 setLastError(reply.error());
314 }
315}
316
317void
318DownloadImpl::setHeaders(QMap<QString, QString> headers) {
319 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
320 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
321 return;
322 }
323 Logger::log(Logger::Debug,
324 QString("Download {%1} setHeaders(%2)").arg(_id), headers);
325
326 QDBusPendingReply<> reply =
327 _dbusInterface->setHeaders(headers);
328 // block, the call should be fast enough
329 reply.waitForFinished();
330 if (reply.isError()) {
331 Logger::log(Logger::Error, "Error setting the download headers");
332 setLastError(reply.error());
333 }
334}
335
336QVariantMap
337DownloadImpl::metadata() {
338 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
339 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
340 QVariantMap emptyResult;
341 return emptyResult;
342 }
343 Logger::log(Logger::Debug, QString("Download{%1} metadata()").arg(_id));
344 QDBusPendingReply<QVariantMap> reply =
345 _dbusInterface->metadata();
346 // block the call is fast enough
347 reply.waitForFinished();
348 if (reply.isError()) {
349 Logger::log(Logger::Error, "Error querying the download metadata");
350 QVariantMap emptyResult;
351 setLastError(reply.error());
352 return emptyResult;
353 } else {
354 auto result = reply.value();
355 return result;
356 }
357}
358
359void
360DownloadImpl::setMetadata(QVariantMap map) {
361 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
362 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
363 return;
364 }
365 Logger::log(Logger::Debug,
366 QString("Download {%1} setMetadata(%2)").arg(_id), map);
367
368 QDBusPendingReply<> reply =
369 _dbusInterface->setMetadata(map);
370 // block, the call should be fast enough
371 reply.waitForFinished();
372 if (reply.isError()) {
373 Logger::log(Logger::Error, "Error setting the download metadata");
374 setLastError(reply.error());
375 }
376}
377
378QMap<QString, QString>
379DownloadImpl::headers() {
380 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
381 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
382 QMap<QString, QString> empty;
383 return empty;
384 }
385 Logger::log(Logger::Debug, QString("Download{%1} headers()").arg(_id));
386 QDBusPendingReply<QMap<QString, QString> > reply =
387 _dbusInterface->headers();
388 // block, the call should be fast enough
389 reply.waitForFinished();
390 if (reply.isError()) {
391 Logger::log(Logger::Error, "Error querying the download headers");
392 setLastError(reply.error());
393 QMap<QString, QString> empty;
394 return empty;
395 } else {
396 auto result = reply.value();
397 return result;
398 }
399}
400
401
402void
403DownloadImpl::setThrottle(qulonglong speed) {
404 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
405 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
406 return;
407 }
408 Logger::log(Logger::Debug,
409 QString("Download{%1} setThrottle(%2)").arg(_id).arg(speed));
410 QDBusPendingReply<> reply =
411 _dbusInterface->setThrottle(speed);
412 // block, the call should be fast enough
413 reply.waitForFinished();
414 if (reply.isError()) {
415 Logger::log(Logger::Error, "Error setting the download throttle");
416 setLastError(reply.error());
417 }
418}
419
420qulonglong
421DownloadImpl::throttle() {
422 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
423 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
424 return 0;
425 }
426 Logger::log(Logger::Debug, QString("Download{%1} throttle()").arg(_id));
427 QDBusPendingReply<qulonglong> reply =
428 _dbusInterface->throttle();
429 // block, the call is fast enough
430 reply.waitForFinished();
431 if (reply.isError()) {
432 Logger::log(Logger::Error, "Error querying the download throttle");
433 setLastError(reply.error());
434 return 0;
435 } else {
436 auto result = reply.value();
437 return result;
438 }
439}
440
441QString
442DownloadImpl::filePath() {
443 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
444 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
445 return "";
446 }
447 Logger::log(Logger::Debug, QString("Download{%1} filePath()").arg(_id));
448 QDBusPendingReply<QString> reply =
449 _dbusInterface->filePath();
450 // block, the call is fast enough
451 reply.waitForFinished();
452 if (reply.isError()) {
453 Logger::log(Logger::Error, "Error querying the download file path");
454 setLastError(reply.error());
455 return "";
456 } else {
457 auto result = reply.value();
458 return result;
459 }
460}
461
462Download::State
463DownloadImpl::state() {
464 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
465 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
466 return Download::ERROR;
467 }
468 Logger::log(Logger::Debug, QString("Download{%1} state()").arg(_id));
469 QDBusPendingReply<int> reply =
470 _dbusInterface->state();
471 // block, the call is fast enough
472 reply.waitForFinished();
473 if (reply.isError()) {
474 Logger::log(Logger::Error, "Error querying the download state");
475 setLastError(reply.error());
476 return Download::ERROR;
477 } else {
478 auto result = static_cast<Download::State>(reply.value());
479 return result;
480 }
481}
482
483QString
484DownloadImpl::id() const {
485 return _id;
486}
487
488qulonglong
489DownloadImpl::progress() {
490 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
491 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
492 return 0;
493 }
494 Logger::log(Logger::Debug, QString("Download{%1} progress()").arg(_id));
495 QDBusPendingReply<qulonglong> reply =
496 _dbusInterface->progress();
497 // block call should be fast enough
498 reply.waitForFinished();
499 if (reply.isError()) {
500 Logger::log(Logger::Error, "Error querying the download progress");
501 setLastError(reply.error());
502 return 0;
503 } else {
504 auto result = reply.value();
505 return result;
506 }
507}
508
509qulonglong
510DownloadImpl::totalSize() {
511 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
512 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
513 return 0;
514 }
515 Logger::log(Logger::Debug, QString("Download{%1} totalSize()").arg(_id));
516 QDBusPendingReply<qulonglong> reply =
517 _dbusInterface->totalSize();
518 // block call should be fast enough
519 reply.waitForFinished();
520 if (reply.isError()) {
521 Logger::log(Logger::Error, "Error querying the download size");
522 setLastError(reply.error());
523 return 0;
524 } else {
525 auto result = reply.value();
526 return result;
527 }
528}
529
530bool
531DownloadImpl::isError() const {
532 return _isError;
533}
534
535Error*
536DownloadImpl::error() const {
537 return _lastError;
538}
539
540QString
541DownloadImpl::clickPackage() const {
542 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
543 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
544 return "";
545 }
546 return _dbusInterface->clickPackage();
547}
548
549bool
550DownloadImpl::showInIndicator() const {
551 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
552 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
553 return false;
554 }
555 return _dbusInterface->showInIndicator();
556}
557
558QString
559DownloadImpl::title() const {
560 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
561 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
562 return "";
563 }
564 return _dbusInterface->title();
565}
566
567QString
568DownloadImpl::destinationApp() const {
569 if (_dbusInterface == nullptr || !_dbusInterface->isValid()) {
570 Logger::log(Logger::Error, QString("Invalid dbus interface: %1").arg(_lastError->errorString()));
571 return "";
572 }
573 return _dbusInterface->destinationApp();
574}
575
576void
577DownloadImpl::onHttpError(HttpErrorStruct errStruct) {
578 auto err = new HttpError(errStruct, this);
579 setLastError(err);
580}
581
582void
583DownloadImpl::onNetworkError(NetworkErrorStruct errStruct) {
584 auto err = new NetworkError(errStruct, this);
585 setLastError(err);
586}
587
588void
589DownloadImpl::onProcessError(ProcessErrorStruct errStruct) {
590 auto err = new ProcessError(errStruct, this);
591 setLastError(err);
592}
593
594void
595DownloadImpl::onAuthError(AuthErrorStruct errStruct) {
596 auto err = new AuthError(errStruct, this);
597 setLastError(err);
598}
599
600void
601DownloadImpl::onHashError(HashErrorStruct errStruct) {
602 auto err = new HashError(errStruct, this);
603 setLastError(err);
604}
605
606void
607DownloadImpl::onPropertiesChanged(const QString& interfaceName,
608 const QVariantMap& changedProperties,
609 const QStringList& invalidatedProperties) {
610 Q_UNUSED(invalidatedProperties);
611 // just take care of the property changes from the download interface
612 if (interfaceName == DownloadInterface::staticInterfaceName()) {
613 if (changedProperties.contains(CLICK_PACKAGE_PROPERTY)) {
614 emit clickPackagedChanged();
615 }
616
617 if (changedProperties.contains(SHOW_INDICATOR_PROPERTY)) {
618 emit showInIndicatorChanged();
619 }
620
621 if (changedProperties.contains(TITLE_PROPERTY)) {
622 emit titleChanged();
623 }
624 }
625}
626
627void DownloadImpl::onFinished(const QString &path) {
628 Q_UNUSED(path);
629
630 // Only acknowledge collection automatically if we aren't sending
631 // this download to another app via content-hub
632 auto environment = QProcessEnvironment::systemEnvironment();
633 QString appId;
634 if (environment.contains("APP_ID")) {
635 appId = environment.value("APP_ID");
636 } else {
637 appId = QCoreApplication::applicationFilePath();
638 }
639
640 if (appId == metadata().value("app-id", appId)) {
641 // Inform LDM that we've received the finished signal, so the download
642 // can be considered completely finished.
643 collected();
644 }
645}
646
647} // DownloadManager
648
649} // Lomiri
void PropertiesChanged(const QString &interface_name, const QVariantMap &changed_properties, const QStringList &invalidated_properties)