Ubuntu Download Manager  1.2.0
A session-wide downloading service
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 
23 namespace {
24  const QString CLICK_PACKAGE_PROPERTY = "ClickPackage";
25  const QString SHOW_INDICATOR_PROPERTY = "ShowInIndicator";
26  const QString TITLE_PROPERTY = "Title";
27 }
28 
29 namespace Ubuntu {
30 
31 namespace DownloadManager {
32 
33 using namespace Logging;
34 
35 DownloadImpl::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 
155 DownloadImpl::DownloadImpl(const QDBusConnection& conn, Error* err, QObject* parent)
156  : Download(parent),
157  _isError(true),
158  _lastError(err),
159  _conn(conn) {
160 }
161 
162 DownloadImpl::~DownloadImpl() {
163  delete _lastError;
164  delete _dbusInterface;
165  delete _propertiesInterface;
166 }
167 
168 void
169 DownloadImpl::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 
181 void
182 DownloadImpl::setLastError(const QDBusError& err) {
183  setLastError(new DBusError(err, this));
184 }
185 
186 void
187 DownloadImpl::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 
200 void
201 DownloadImpl::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 
214 void
215 DownloadImpl::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 
228 void
229 DownloadImpl::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 
242 void
243 DownloadImpl::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 
259 void
260 DownloadImpl::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 
277 bool
278 DownloadImpl::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 
299 void
300 DownloadImpl::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 
317 void
318 DownloadImpl::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 
336 QVariantMap
337 DownloadImpl::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 
359 void
360 DownloadImpl::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 
378 QMap<QString, QString>
379 DownloadImpl::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 
402 void
403 DownloadImpl::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 
420 qulonglong
421 DownloadImpl::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 
441 QString
442 DownloadImpl::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 
463 DownloadImpl::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 
483 QString
484 DownloadImpl::id() const {
485  return _id;
486 }
487 
488 qulonglong
489 DownloadImpl::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 
509 qulonglong
510 DownloadImpl::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 
530 bool
531 DownloadImpl::isError() const {
532  return _isError;
533 }
534 
535 Error*
536 DownloadImpl::error() const {
537  return _lastError;
538 }
539 
540 QString
541 DownloadImpl::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 
549 bool
550 DownloadImpl::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 
558 QString
559 DownloadImpl::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 
567 QString
568 DownloadImpl::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 
576 void
577 DownloadImpl::onHttpError(HttpErrorStruct errStruct) {
578  auto err = new HttpError(errStruct, this);
579  setLastError(err);
580 }
581 
582 void
583 DownloadImpl::onNetworkError(NetworkErrorStruct errStruct) {
584  auto err = new NetworkError(errStruct, this);
585  setLastError(err);
586 }
587 
588 void
589 DownloadImpl::onProcessError(ProcessErrorStruct errStruct) {
590  auto err = new ProcessError(errStruct, this);
591  setLastError(err);
592 }
593 
594 void
595 DownloadImpl::onAuthError(AuthErrorStruct errStruct) {
596  auto err = new AuthError(errStruct, this);
597  setLastError(err);
598 }
599 
600 void
601 DownloadImpl::onHashError(HashErrorStruct errStruct) {
602  auto err = new HashError(errStruct, this);
603  setLastError(err);
604 }
605 
606 void
607 DownloadImpl::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 
627 void 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 UDM 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 } // Ubuntu
void finished(const QString &path)
virtual QMap< QString, QString > headers()=0
Download(QObject *parent=0)
Definition: download.h:57
virtual QVariantMap metadata()=0
void PropertiesChanged(const QString &interface_name, const QVariantMap &changed_properties, const QStringList &invalidated_properties)
void processing(const QString &path)
virtual Error * error() const =0
virtual qulonglong progress()=0