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  Logger::log(Logger::Debug, QString("Download{%1} start())").arg(_id));
189  QDBusPendingCall call =
190  _dbusInterface->start();
191  auto watcher = new DownloadPCW(_conn, _servicePath,
192  call, this);
193  Q_UNUSED(watcher);
194 }
195 
196 void
197 DownloadImpl::pause() {
198  Logger::log(Logger::Debug, QString("Download{%1} pause())").arg(_id));
199  QDBusPendingCall call =
200  _dbusInterface->pause();
201  auto watcher = new DownloadPCW(_conn, _servicePath,
202  call, this);
203  Q_UNUSED(watcher);
204 }
205 
206 void
207 DownloadImpl::resume() {
208  Logger::log(Logger::Debug, QString("Download{%1} resume())").arg(_id));
209  QDBusPendingCall call =
210  _dbusInterface->resume();
211  auto watcher = new DownloadPCW(_conn, _servicePath,
212  call, this);
213  Q_UNUSED(watcher);
214 }
215 
216 void
217 DownloadImpl::cancel() {
218  Logger::log(Logger::Debug, QString("Download{%1} cancel())").arg(_id));
219  QDBusPendingCall call =
220  _dbusInterface->cancel();
221  auto watcher = new DownloadPCW(_conn, _servicePath,
222  call, this);
223  Q_UNUSED(watcher);
224 }
225 
226 void
227 DownloadImpl::collected() {
228  Logger::log(Logger::Debug, QString("Download{%1} collected()").arg(_id));
229  QDBusPendingReply<> reply =
230  _dbusInterface->collected();
231  // block, the call should be fast enough
232  reply.waitForFinished();
233  if (reply.isError()) {
234  Logger::log(Logger::Error, "Error when setting download collected");
235  setLastError(reply.error());
236  }
237 }
238 
239 void
240 DownloadImpl::allowMobileDownload(bool allowed) {
241  Logger::log(Logger::Debug,
242  QString("Download{%1} allowMobileDownload%2())").arg(_id).arg(allowed));
243  QDBusPendingReply<> reply =
244  _dbusInterface->allowGSMDownload(allowed);
245  // block, the call should be fast enough
246  reply.waitForFinished();
247  if (reply.isError()) {
248  Logger::log(Logger::Error, "Error when setting mobile data usage");
249  setLastError(reply.error());
250  }
251 }
252 
253 bool
254 DownloadImpl::isMobileDownloadAllowed() {
255  Logger::log(Logger::Debug,
256  QString("Download{%1} isMobileDownloadAllowed").arg(_id));
257  QDBusPendingReply<bool> reply =
258  _dbusInterface->isGSMDownloadAllowed();
259  // block, the call should be fast enough
260  reply.waitForFinished();
261  if (reply.isError()) {
262  Logger::log(Logger::Error, "Error when querying mobile data usage");
263  setLastError(reply.error());
264  return false;
265  } else {
266  auto result = reply.value();
267  return result;
268  }
269 }
270 
271 void
272 DownloadImpl::setDestinationDir(const QString& path) {
273  Logger::log(Logger::Debug, QString("Dowmload{%1} setDestinationDir(%2)")
274  .arg(_id).arg(path));
275  QDBusPendingReply<> reply =
276  _dbusInterface->setDestinationDir(path);
277  // block, the call should be fast enough
278  reply.waitForFinished();
279  if (reply.isError()) {
280  Logger::log(Logger::Error, "Error setting the download directory");
281  setLastError(reply.error());
282  }
283 }
284 
285 void
286 DownloadImpl::setHeaders(QMap<QString, QString> headers) {
287  Logger::log(Logger::Debug,
288  QString("Download {%1} setHeaders(%2)").arg(_id), headers);
289 
290  QDBusPendingReply<> reply =
291  _dbusInterface->setHeaders(headers);
292  // block, the call should be fast enough
293  reply.waitForFinished();
294  if (reply.isError()) {
295  Logger::log(Logger::Error, "Error setting the download headers");
296  setLastError(reply.error());
297  }
298 }
299 
300 QVariantMap
301 DownloadImpl::metadata() {
302  Logger::log(Logger::Debug, QString("Download{%1} metadata()").arg(_id));
303  QDBusPendingReply<QVariantMap> reply =
304  _dbusInterface->metadata();
305  // block the call is fast enough
306  reply.waitForFinished();
307  if (reply.isError()) {
308  Logger::log(Logger::Error, "Error querying the download metadata");
309  QVariantMap emptyResult;
310  setLastError(reply.error());
311  return emptyResult;
312  } else {
313  auto result = reply.value();
314  return result;
315  }
316 }
317 
318 void
319 DownloadImpl::setMetadata(QVariantMap map) {
320  Logger::log(Logger::Debug,
321  QString("Download {%1} setMetadata(%2)").arg(_id), map);
322 
323  QDBusPendingReply<> reply =
324  _dbusInterface->setMetadata(map);
325  // block, the call should be fast enough
326  reply.waitForFinished();
327  if (reply.isError()) {
328  Logger::log(Logger::Error, "Error setting the download metadata");
329  setLastError(reply.error());
330  }
331 }
332 
333 QMap<QString, QString>
334 DownloadImpl::headers() {
335  Logger::log(Logger::Debug, QString("Download{%1} headers()").arg(_id));
336  QDBusPendingReply<QMap<QString, QString> > reply =
337  _dbusInterface->headers();
338  // block, the call should be fast enough
339  reply.waitForFinished();
340  if (reply.isError()) {
341  Logger::log(Logger::Error, "Error querying the download headers");
342  setLastError(reply.error());
343  QMap<QString, QString> empty;
344  return empty;
345  } else {
346  auto result = reply.value();
347  return result;
348  }
349 }
350 
351 
352 void
353 DownloadImpl::setThrottle(qulonglong speed) {
354  Logger::log(Logger::Debug,
355  QString("Download{%1} setThrottle(%2)").arg(_id).arg(speed));
356  QDBusPendingReply<> reply =
357  _dbusInterface->setThrottle(speed);
358  // block, the call should be fast enough
359  reply.waitForFinished();
360  if (reply.isError()) {
361  Logger::log(Logger::Error, "Error setting the download throttle");
362  setLastError(reply.error());
363  }
364 }
365 
366 qulonglong
367 DownloadImpl::throttle() {
368  Logger::log(Logger::Debug, QString("Download{%1} throttle()").arg(_id));
369  QDBusPendingReply<qulonglong> reply =
370  _dbusInterface->throttle();
371  // block, the call is fast enough
372  reply.waitForFinished();
373  if (reply.isError()) {
374  Logger::log(Logger::Error, "Error querying the download throttle");
375  setLastError(reply.error());
376  return 0;
377  } else {
378  auto result = reply.value();
379  return result;
380  }
381 }
382 
383 QString
384 DownloadImpl::filePath() {
385  Logger::log(Logger::Debug, QString("Download{%1} filePath()").arg(_id));
386  QDBusPendingReply<QString> reply =
387  _dbusInterface->filePath();
388  // block, the call is fast enough
389  reply.waitForFinished();
390  if (reply.isError()) {
391  Logger::log(Logger::Error, "Error querying the download file path");
392  setLastError(reply.error());
393  return "";
394  } else {
395  auto result = reply.value();
396  return result;
397  }
398 }
399 
401 DownloadImpl::state() {
402  Logger::log(Logger::Debug, QString("Download{%1} state()").arg(_id));
403  QDBusPendingReply<int> reply =
404  _dbusInterface->state();
405  // block, the call is fast enough
406  reply.waitForFinished();
407  if (reply.isError()) {
408  Logger::log(Logger::Error, "Error querying the download state");
409  setLastError(reply.error());
410  return Download::ERROR;
411  } else {
412  auto result = static_cast<Download::State>(reply.value());
413  return result;
414  }
415 }
416 
417 QString
418 DownloadImpl::id() const {
419  return _id;
420 }
421 
422 qulonglong
423 DownloadImpl::progress() {
424  Logger::log(Logger::Debug, QString("Download{%1} progress()").arg(_id));
425  QDBusPendingReply<qulonglong> reply =
426  _dbusInterface->progress();
427  // block call should be fast enough
428  reply.waitForFinished();
429  if (reply.isError()) {
430  Logger::log(Logger::Error, "Error querying the download progress");
431  setLastError(reply.error());
432  return 0;
433  } else {
434  auto result = reply.value();
435  return result;
436  }
437 }
438 
439 qulonglong
440 DownloadImpl::totalSize() {
441  Logger::log(Logger::Debug, QString("Download{%1} totalSize()").arg(_id));
442  QDBusPendingReply<qulonglong> reply =
443  _dbusInterface->totalSize();
444  // block call should be fast enough
445  reply.waitForFinished();
446  if (reply.isError()) {
447  Logger::log(Logger::Error, "Error querying the download size");
448  setLastError(reply.error());
449  return 0;
450  } else {
451  auto result = reply.value();
452  return result;
453  }
454 }
455 
456 bool
457 DownloadImpl::isError() const {
458  return _isError;
459 }
460 
461 Error*
462 DownloadImpl::error() const {
463  return _lastError;
464 }
465 
466 QString
467 DownloadImpl::clickPackage() const {
468  return _dbusInterface->clickPackage();
469 }
470 
471 bool
472 DownloadImpl::showInIndicator() const {
473  return _dbusInterface->showInIndicator();
474 }
475 
476 QString
477 DownloadImpl::title() const {
478  return _dbusInterface->title();
479 }
480 
481 QString
482 DownloadImpl::destinationApp() const {
483  return _dbusInterface->destinationApp();
484 }
485 
486 void
487 DownloadImpl::onHttpError(HttpErrorStruct errStruct) {
488  auto err = new HttpError(errStruct, this);
489  setLastError(err);
490 }
491 
492 void
493 DownloadImpl::onNetworkError(NetworkErrorStruct errStruct) {
494  auto err = new NetworkError(errStruct, this);
495  setLastError(err);
496 }
497 
498 void
499 DownloadImpl::onProcessError(ProcessErrorStruct errStruct) {
500  auto err = new ProcessError(errStruct, this);
501  setLastError(err);
502 }
503 
504 void
505 DownloadImpl::onAuthError(AuthErrorStruct errStruct) {
506  auto err = new AuthError(errStruct, this);
507  setLastError(err);
508 }
509 
510 void
511 DownloadImpl::onHashError(HashErrorStruct errStruct) {
512  auto err = new HashError(errStruct, this);
513  setLastError(err);
514 }
515 
516 void
517 DownloadImpl::onPropertiesChanged(const QString& interfaceName,
518  const QVariantMap& changedProperties,
519  const QStringList& invalidatedProperties) {
520  Q_UNUSED(invalidatedProperties);
521  // just take care of the property changes from the download interface
522  if (interfaceName == DownloadInterface::staticInterfaceName()) {
523  if (changedProperties.contains(CLICK_PACKAGE_PROPERTY)) {
524  emit clickPackagedChanged();
525  }
526 
527  if (changedProperties.contains(SHOW_INDICATOR_PROPERTY)) {
528  emit showInIndicatorChanged();
529  }
530 
531  if (changedProperties.contains(TITLE_PROPERTY)) {
532  emit titleChanged();
533  }
534  }
535 }
536 
537 void DownloadImpl::onFinished(const QString &path) {
538  Q_UNUSED(path);
539 
540  // Only acknowledge collection automatically if we aren't sending
541  // this download to another app via content-hub
542  auto environment = QProcessEnvironment::systemEnvironment();
543  QString appId;
544  if (environment.contains("APP_ID")) {
545  appId = environment.value("APP_ID");
546  } else {
547  appId = QCoreApplication::applicationFilePath();
548  }
549 
550  if (appId == metadata().value("app-id", appId)) {
551  // Inform UDM that we've received the finished signal, so the download
552  // can be considered completely finished.
553  collected();
554  }
555 }
556 
557 } // DownloadManager
558 
559 } // Ubuntu
void finished(const QString &path)
Download(QObject *parent=0)
Definition: download.h:57
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