Merge lp:keeper/devel into lp:keeper

Proposed by dobey
Status: Merged
Approved by: Charles Kerr
Approved revision: 129
Merged at revision: 94
Proposed branch: lp:keeper/devel
Merge into: lp:keeper
Diff against target: 11619 lines (+7871/-1027)
124 files modified
CMakeLists.txt (+1/-1)
data/CMakeLists.txt (+6/-0)
data/helper-registry.json.in (+6/-1)
debian/changelog (+14/-0)
debian/control (+5/-1)
debian/keeper.install (+3/-1)
include/client/client.h (+18/-4)
include/client/keeper-errors.h (+57/-0)
include/client/keeper-items.h (+102/-0)
include/helper/backup-helper.h (+1/-0)
include/helper/data-dir-registry.h (+2/-0)
include/helper/helper.h (+3/-1)
include/helper/metadata.h (+6/-27)
include/helper/registry.h (+1/-0)
include/helper/restore-helper.h (+62/-0)
src/cli/CMakeLists.txt (+4/-0)
src/cli/command-line-client-view.cpp (+194/-0)
src/cli/command-line-client-view.h (+60/-0)
src/cli/command-line-client.cpp (+250/-0)
src/cli/command-line-client.h (+58/-0)
src/cli/command-line.cpp (+234/-0)
src/cli/command-line.h (+55/-0)
src/cli/main.cpp (+40/-46)
src/client/CMakeLists.txt (+22/-0)
src/client/client.cpp (+223/-60)
src/client/items.cpp (+196/-0)
src/client/keeper-errors.cpp (+74/-0)
src/client/qml-plugin/CMakeLists.txt (+1/-1)
src/helper/CMakeLists.txt (+18/-1)
src/helper/backup-helper.cpp (+30/-8)
src/helper/data-dir-registry.cpp (+54/-22)
src/helper/folder-backup.sh.in (+1/-1)
src/helper/folder-restore.sh.in (+23/-0)
src/helper/helper.cpp (+6/-8)
src/helper/metadata.cpp (+45/-50)
src/helper/restore-helper.cpp (+377/-0)
src/qdbus-stubs/CMakeLists.txt (+19/-1)
src/qdbus-stubs/com.canonical.keeper.User.xml (+47/-3)
src/qdbus-stubs/dbus-types.h (+6/-2)
src/qdbus-stubs/org.freedesktop.DBus.Properties.xml (+27/-0)
src/service/CMakeLists.txt (+4/-0)
src/service/backup-choices.cpp (+20/-12)
src/service/backup-choices.h (+2/-1)
src/service/keeper-helper.cpp (+5/-2)
src/service/keeper-task-backup.cpp (+40/-11)
src/service/keeper-task-backup.h (+4/-2)
src/service/keeper-task-restore.cpp (+130/-0)
src/service/keeper-task-restore.h (+46/-0)
src/service/keeper-task.cpp (+96/-23)
src/service/keeper-task.h (+10/-2)
src/service/keeper-user.cpp (+37/-45)
src/service/keeper-user.h (+8/-6)
src/service/keeper.cpp (+365/-62)
src/service/keeper.h (+19/-5)
src/service/main.cpp (+2/-1)
src/service/manifest.cpp (+248/-0)
src/service/manifest.h (+51/-0)
src/service/metadata-provider.h (+10/-2)
src/service/private/keeper-task_p.h (+10/-2)
src/service/restore-choices.cpp (+55/-93)
src/service/restore-choices.h (+10/-5)
src/service/task-manager.cpp (+170/-25)
src/service/task-manager.h (+12/-6)
src/storage-framework/CMakeLists.txt (+3/-0)
src/storage-framework/downloader.h (+46/-0)
src/storage-framework/sf-downloader.cpp (+54/-0)
src/storage-framework/sf-downloader.h (+48/-0)
src/storage-framework/sf-uploader.cpp (+12/-2)
src/storage-framework/sf-uploader.h (+3/-0)
src/storage-framework/storage_framework_client.cpp (+444/-36)
src/storage-framework/storage_framework_client.h (+25/-5)
src/storage-framework/uploader.h (+1/-0)
src/tar/CMakeLists.txt (+72/-27)
src/tar/tar-creator.cpp (+31/-29)
src/tar/untar-main.cpp (+169/-0)
src/tar/untar.cpp (+144/-0)
src/tar/untar.h (+38/-0)
src/util/connection-helper.h (+9/-4)
tests/CMakeLists.txt (+9/-1)
tests/com_canonical_keeper.py (+80/-45)
tests/dbusmock/keeper-template-test.cpp (+113/-102)
tests/fakes/CMakeLists.txt (+14/-0)
tests/fakes/fake-restore-helper.cpp (+136/-0)
tests/fakes/fake-restore-helper.h (+27/-0)
tests/fakes/folder-restore.sh.in (+41/-0)
tests/fakes/helper-test.sh.in (+16/-0)
tests/fakes/upstart/upstart-job-mock.cpp (+4/-1)
tests/integration/helpers/CMakeLists.txt (+94/-1)
tests/integration/helpers/helpers-test-failure.cpp (+20/-8)
tests/integration/helpers/helpers-test.cc (+289/-9)
tests/integration/helpers/restore-test.cpp (+126/-0)
tests/integration/helpers/state-change-test-manager.h (+55/-0)
tests/integration/helpers/state-change-test.cpp (+56/-0)
tests/integration/helpers/state-test-helper.h (+55/-0)
tests/integration/helpers/test-helpers-base.cpp (+363/-135)
tests/integration/helpers/test-helpers-base.h (+22/-13)
tests/unit/CMakeLists.txt (+3/-0)
tests/unit/helper/CMakeLists.txt (+1/-5)
tests/unit/helper/speed-test.cpp (+3/-3)
tests/unit/manifest/CMakeLists.txt (+45/-0)
tests/unit/manifest/manifest-test.cpp (+170/-0)
tests/unit/metadata-providers/CMakeLists.txt (+3/-0)
tests/unit/metadata-providers/user-dirs-test.cpp (+19/-12)
tests/unit/metadata/CMakeLists.txt (+44/-0)
tests/unit/metadata/metadata-json-test.cpp (+100/-0)
tests/unit/storage-framework/CMakeLists.txt (+73/-0)
tests/unit/storage-framework/create-uploader-test.cpp (+147/-0)
tests/unit/storage-framework/folders-test.cpp (+109/-0)
tests/unit/tar/CMakeLists.txt (+104/-29)
tests/unit/tar/keeper-tar-test.cpp (+5/-5)
tests/unit/tar/keeper-untar-test.cpp (+232/-0)
tests/unit/tar/ku-invoke-nobus.sh.in (+1/-0)
tests/unit/tar/ku-invoke.sh.in (+1/-0)
tests/unit/tar/tar-creator-libarchive-failure-test.cpp (+5/-1)
tests/unit/tar/tar-creator-test.cpp (+1/-1)
tests/unit/tar/untar-test.cpp (+120/-0)
tests/utils/CMakeLists.txt (+2/-0)
tests/utils/file-utils.cpp (+88/-6)
tests/utils/file-utils.h (+5/-1)
tests/utils/keeper-dbusmock-fixture.h (+9/-0)
tests/utils/main.cpp (+1/-1)
tests/utils/storage-framework-local.cpp (+207/-0)
tests/utils/storage-framework-local.h (+48/-0)
tests/utils/xdg-user-dirs-sandbox.cpp (+1/-1)
To merge this branch: bzr merge lp:keeper/devel
Reviewer Review Type Date Requested Status
Charles Kerr (community) Approve
Review via email: mp+318388@code.launchpad.net

Description of the change

This is just to merge what's in devel (which has apparently already mostly been released to zesty/xenial+overlay), into trunk. Only missing piece from release is for the UAL API/ABI change.

To post a comment you must log in.
lp:keeper/devel updated
130. By dobey

Update the changelog for Ken's change, and to keep the already released version when releasing to trunk.
Fix comment starter removed in a previous change.

Approved by unity-api-1-bot, Charles Kerr.

Revision history for this message
Charles Kerr (charlesk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-08-26 09:30:11 +0000
+++ CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -272,7 +272,7 @@
272include(CTest)272include(CTest)
273enable_testing()273enable_testing()
274274
275include(EnableCoverageReport)275find_package(CoverageReport)
276276
277add_subdirectory(data)277add_subdirectory(data)
278add_subdirectory(src)278add_subdirectory(src)
279279
=== modified file 'data/CMakeLists.txt'
--- data/CMakeLists.txt 2016-08-10 07:43:36 +0000
+++ data/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -6,6 +6,12 @@
6 FOLDER_BACKUP_EXEC6 FOLDER_BACKUP_EXEC
7 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-backup.sh7 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-backup.sh
8)8)
9
10set(
11 FOLDER_RESTORE_EXEC
12 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-restore.sh
13)
14
9configure_file(15configure_file(
10 ${HELPER_REGISTRY_FILENAME}.in16 ${HELPER_REGISTRY_FILENAME}.in
11 ${HELPER_REGISTRY_FILENAME}17 ${HELPER_REGISTRY_FILENAME}
1218
=== modified file 'data/helper-registry.json.in'
--- data/helper-registry.json.in 2016-08-09 04:20:33 +0000
+++ data/helper-registry.json.in 2017-02-27 19:05:17 +0000
@@ -4,5 +4,10 @@
4 "@FOLDER_BACKUP_EXEC@",4 "@FOLDER_BACKUP_EXEC@",
5 "${subtype}"5 "${subtype}"
6 ]6 ]
7 }7 ,
8 "restore-urls": [
9 "@FOLDER_RESTORE_EXEC@",
10 "${subtype}"
11 ]
12 }
8}13}
914
=== modified file 'debian/changelog'
--- debian/changelog 2016-09-15 19:20:14 +0000
+++ debian/changelog 2017-02-27 19:05:17 +0000
@@ -1,3 +1,17 @@
1keeper (0.1.1-0ubuntu1) UNRELEASED; urgency=medium
2
3 [ Ken Vandine ]
4 * Update to handle the API/ABI break in ubuntu-app-launch.
5
6 -- Rodney Dawes <rodney.dawes@canonical.com> Mon, 27 Feb 2017 13:46:45 -0500
7
8keeper (0.1.0+17.04.20170213.1-0ubuntu1) zesty; urgency=medium
9
10 [ Charles Kerr, Xavi Garcia, Xavi Garcia Mena ]
11 * Adds integration tests for restore and restore cancellation.
12
13 -- Xavi Garcia <xavi.garcia.mena@canonical.com> Mon, 13 Feb 2017 08:57:47 +0000
14
1keeper (0.1.0+16.10.20160915.3-0ubuntu1) yakkety; urgency=medium15keeper (0.1.0+16.10.20160915.3-0ubuntu1) yakkety; urgency=medium
216
3 * Initial release. 17 * Initial release.
418
=== modified file 'debian/control'
--- debian/control 2016-08-26 08:48:05 +0000
+++ debian/control 2017-02-27 19:05:17 +0000
@@ -9,7 +9,7 @@
9# for building the code:9# for building the code:
10 libarchive-dev (>= 3.1.2),10 libarchive-dev (>= 3.1.2),
11 libproperties-cpp-dev,11 libproperties-cpp-dev,
12 libubuntu-app-launch2-dev (>= 0.9),12 libubuntu-app-launch3-dev,
13 storage-framework-client-dev,13 storage-framework-client-dev,
14 libclick-0.4-dev,14 libclick-0.4-dev,
15 uuid-dev,15 uuid-dev,
@@ -45,6 +45,8 @@
45Depends: ${shlibs:Depends}, 45Depends: ${shlibs:Depends},
46 ${misc:Depends},46 ${misc:Depends},
47 systemd | systemd-shim,47 systemd | systemd-shim,
48 tar,
49 xz-utils
48Description: Backup Tool50Description: Backup Tool
49 A backup/restore utility for Ubuntu51 A backup/restore utility for Ubuntu
5052
@@ -53,6 +55,8 @@
53Depends: ${shlibs:Depends},55Depends: ${shlibs:Depends},
54 ${misc:Depends},56 ${misc:Depends},
55 systemd | systemd-shim,57 systemd | systemd-shim,
58 tar,
59 xz-utils
56Description: Backup Tool60Description: Backup Tool
57 A backup/restore utility for Ubuntu (client application)61 A backup/restore utility for Ubuntu (client application)
5862
5963
=== modified file 'debian/keeper.install'
--- debian/keeper.install 2016-08-10 07:43:36 +0000
+++ debian/keeper.install 2017-02-27 19:05:17 +0000
@@ -1,6 +1,8 @@
1/usr/lib/*/keeper/folder-backup.sh1/usr/lib/*/keeper/folder-backup.sh
2/usr/lib/*/keeper/folder-restore.sh
2/usr/lib/*/keeper/keeper-service3/usr/lib/*/keeper/keeper-service
3/usr/lib/*/keeper/keeper-tar-create4/usr/lib/*/keeper/keeper-tar
5/usr/lib/*/keeper/keeper-untar
4/usr/lib/*/ubuntu-app-launch/backup-helper/exec-tool6/usr/lib/*/ubuntu-app-launch/backup-helper/exec-tool
5/usr/share/keeper/helper-registry.json7/usr/share/keeper/helper-registry.json
6/usr/share/dbus-1/services/com.canonical.keeper.service8/usr/share/dbus-1/services/com.canonical.keeper.service
79
=== modified file 'include/client/client.h'
--- include/client/client.h 2016-09-06 18:28:45 +0000
+++ include/client/client.h 2017-02-27 19:05:17 +0000
@@ -19,10 +19,13 @@
1919
20#pragma once20#pragma once
2121
22#include "keeper-errors.h"
23
22#include <QObject>24#include <QObject>
23#include <QScopedPointer>25#include <QScopedPointer>
24#include <QStringList>26#include <QStringList>
25#include <QVariant>27#include <QVariant>
28#include "keeper-items.h"
2629
27struct KeeperClientPrivate;30struct KeeperClientPrivate;
2831
@@ -53,14 +56,22 @@
5356
54 Q_INVOKABLE QString getBackupName(QString uuid);57 Q_INVOKABLE QString getBackupName(QString uuid);
55 Q_INVOKABLE void enableBackup(QString uuid, bool enabled);58 Q_INVOKABLE void enableBackup(QString uuid, bool enabled);
56 Q_INVOKABLE void startBackup();59 Q_INVOKABLE void startBackup(QString const & storage);
60
61 Q_INVOKABLE void enableRestore(QString uuid, bool enabled);
62 Q_INVOKABLE void startRestore(QString const & storage);
63
64 Q_INVOKABLE void cancel();
5765
58// C++66// C++
59public:67public:
60 QMap<QString, QVariantMap> getBackupChoices() const;68 keeper::Items getBackupChoices(keeper::Error & error) const;
61 void startBackup(QStringList const& uuids) const;69 keeper::Items getRestoreChoices(QString const & storage, keeper::Error & error) const;
70 void startBackup(QStringList const& uuids, QString const & storage) const;
71 void startRestore(QStringList const& uuids, QString const & storage) const;
6272
63 QMap<QString, QVariantMap> getState() const;73 keeper::Items getState() const;
74 QStringList getStorageAccounts() const;
6475
65Q_SIGNALS:76Q_SIGNALS:
66 void statusChanged();77 void statusChanged();
@@ -68,6 +79,9 @@
68 void readyToBackupChanged();79 void readyToBackupChanged();
69 void backupBusyChanged();80 void backupBusyChanged();
7081
82 void taskStatusChanged(QString const & displayName, QString const & status, double percentage, keeper::Error error);
83 void finished();
84
71private Q_SLOTS:85private Q_SLOTS:
72 void stateUpdated();86 void stateUpdated();
7387
7488
=== added file 'include/client/keeper-errors.h'
--- include/client/keeper-errors.h 1970-01-01 00:00:00 +0000
+++ include/client/keeper-errors.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
18 */
19
20#pragma once
21
22#include <QDBusArgument>
23#include <QMetaType>
24
25namespace keeper
26{
27
28enum class Error
29{
30 OK,
31 UNKNOWN,
32 HELPER_READ,
33 HELPER_WRITE,
34 HELPER_INACTIVITY_DETECTED,
35 HELPER_SOCKET,
36 HELPER_START_TIMEOUT,
37 NO_HELPER_INFORMATION_IN_REGISTRY,
38 HELPER_BAD_URL,
39 MANIFEST_STORAGE,
40 COMMITTING_DATA,
41
42 CREATING_REMOTE_DIR,
43 CREATING_REMOTE_FILE,
44 READING_REMOTE_FILE,
45 REMOTE_DIR_NOT_EXISTS,
46 NO_REMOTE_ACCOUNTS,
47 NO_REMOTE_ROOTS,
48 ACCOUNT_NOT_FOUND
49};
50
51Error convert_from_dbus_variant(const QVariant & value, bool *conversion_ok = nullptr);
52} // namespace keeper
53
54QDBusArgument &operator<<(QDBusArgument &argument, keeper::Error value);
55const QDBusArgument &operator>>(const QDBusArgument &argument, keeper::Error &val);
56
57Q_DECLARE_METATYPE(keeper::Error)
058
=== added file 'include/client/keeper-items.h'
--- include/client/keeper-items.h 1970-01-01 00:00:00 +0000
+++ include/client/keeper-items.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
18 */
19
20#pragma once
21
22#include "client/keeper-errors.h"
23
24#include <QJsonObject>
25
26typedef QMap<QString, QVariantMap> QVariantDictMap;
27
28namespace keeper
29{
30
31class Item : public QVariantMap
32{
33public:
34 Item();
35 ~Item();
36 explicit Item(QVariantMap const & values);
37
38 // keys
39 static QString const UUID_KEY;
40 static QString const TYPE_KEY;
41 static QString const SUBTYPE_KEY;
42 static QString const NAME_KEY;
43 static QString const PACKAGE_KEY;
44 static QString const TITLE_KEY;
45 static QString const VERSION_KEY;
46 static QString const FILE_NAME_KEY;
47 static QString const DIR_NAME_KEY;
48 static QString const DISPLAY_NAME_KEY;
49 static QString const STATUS_KEY;
50 static QString const ERROR_KEY;
51 static QString const PERCENT_DONE_KEY;
52 static QString const SPEED_KEY;
53
54 // values
55 static QString const FOLDER_VALUE;
56 static QString const SYSTEM_DATA_VALUE;
57 static QString const APPLICATION_VALUE;
58
59
60 // methods created for convenience
61 bool has_property(QString const & property) const;
62 template<typename T> T get_property(QString const & property, bool * valid) const;
63 QVariant get_property_value(QString const & property) const;
64 void set_property_value(QString const& property, QVariant const& value);
65
66 // checks that the item is valid
67 bool is_valid() const;
68
69 // predefined properties
70 QString get_uuid(bool *valid = nullptr) const;
71 QString get_type(bool *valid = nullptr) const;
72 QString get_display_name(bool *valid = nullptr) const;
73 QString get_dir_name(bool *valid = nullptr) const;
74 QString get_status(bool *valid = nullptr) const;
75 double get_percent_done(bool *valid = nullptr) const;
76 keeper::Error get_error(bool *valid = nullptr) const;
77 QString get_file_name(bool *valid = nullptr) const;
78
79 // d-bus
80 static void registerMetaType();
81};
82
83class Items : public QMap<QString, Item>
84{
85public:
86 Items();
87 ~Items();
88 explicit Items(Error error);
89
90 QStringList get_uuids() const;
91
92 // d-bus
93 static void registerMetaType();
94
95private:
96 Error error_ = Error::OK;
97};
98
99} // namespace keeper
100
101Q_DECLARE_METATYPE(keeper::Item)
102Q_DECLARE_METATYPE(keeper::Items)
0103
=== modified file 'include/helper/backup-helper.h'
--- include/helper/backup-helper.h 2016-09-15 16:02:54 +0000
+++ include/helper/backup-helper.h 2017-02-27 19:05:17 +0000
@@ -53,6 +53,7 @@
53 int get_helper_socket() const;53 int get_helper_socket() const;
54 QString to_string(Helper::State state) const override;54 QString to_string(Helper::State state) const override;
55 void set_state(State) override;55 void set_state(State) override;
56 QString get_uploader_committed_file_name() const;
56protected:57protected:
57 void on_helper_finished() override;58 void on_helper_finished() override;
5859
5960
=== modified file 'include/helper/data-dir-registry.h'
--- include/helper/data-dir-registry.h 2016-08-09 05:44:25 +0000
+++ include/helper/data-dir-registry.h 2017-02-27 19:05:17 +0000
@@ -39,6 +39,8 @@
3939
40 QStringList get_backup_helper_urls(Metadata const& metadata) override;40 QStringList get_backup_helper_urls(Metadata const& metadata) override;
4141
42 QStringList get_restore_helper_urls(Metadata const& metadata) override;
43
42private:44private:
43 class Impl;45 class Impl;
44 friend class Impl;46 friend class Impl;
4547
=== modified file 'include/helper/helper.h'
--- include/helper/helper.h 2016-09-15 16:02:54 +0000
+++ include/helper/helper.h 2017-02-27 19:05:17 +0000
@@ -19,6 +19,7 @@
1919
20#pragma once20#pragma once
2121
22#include <client/keeper-errors.h>
22#include <util/attributes.h>23#include <util/attributes.h>
2324
24#include <QObject>25#include <QObject>
@@ -64,11 +65,12 @@
64 virtual void start(QStringList const& urls);65 virtual void start(QStringList const& urls);
65 virtual void stop();66 virtual void stop();
6667
67 static constexpr int MAX_UAL_WAIT_TIME = 5000;68 static constexpr int MAX_UAL_WAIT_TIME = 10000;
6869
69Q_SIGNALS:70Q_SIGNALS:
70 void state_changed(Helper::State);71 void state_changed(Helper::State);
71 void percent_done_changed(float);72 void percent_done_changed(float);
73 void error(keeper::Error error);
7274
73protected:75protected:
74 Helper(QString const & appid, const clock_func& clock=default_clock, QObject *parent=nullptr);76 Helper(QString const & appid, const clock_func& clock=default_clock, QObject *parent=nullptr);
7577
=== modified file 'include/helper/metadata.h'
--- include/helper/metadata.h 2016-09-06 18:51:30 +0000
+++ include/helper/metadata.h 2017-02-27 19:05:17 +0000
@@ -19,42 +19,21 @@
1919
20#pragma once20#pragma once
2121
22#include "client/keeper-items.h"
23#include <QJsonObject>
22#include <QMap>24#include <QMap>
23#include <QString>25#include <QString>
2426
25/**27/**
26 * Information about a backup28 * Information about a backup or restore item
27 */29 */
28class Metadata30class Metadata : public keeper::Item
29{31{
30public:32public:
3133
32 Metadata();34 Metadata();
35 explicit Metadata(QJsonObject const & json_object);
33 Metadata(QString const& uuid, QString const& display_name);36 Metadata(QString const& uuid, QString const& display_name);
3437
35 // metadata keys38 QJsonObject json() const;
36 static QString const TYPE_KEY;
37 static QString const SUBTYPE_KEY;
38 static QString const NAME_KEY;
39 static QString const PACKAGE_KEY;
40 static QString const TITLE_KEY;
41 static QString const VERSION_KEY;
42
43 // metadata values
44 static QString const FOLDER_VALUE;
45 static QString const SYSTEM_DATA_VALUE;
46 static QString const APPLICATION_VALUE;
47
48 QString uuid() const { return uuid_; }
49 QString display_name() const { return display_name_; }
50 bool get_property(QString const& property_name, QString& setme_value) const;
51 void set_property(QString const& property_name, QString const& value);
52
53 QMap<QString,QString> get_public_properties() const;
54
55private:
56
57 QString uuid_;
58 QString display_name_;
59 QMap<QString,QString> properties_{};
60};39};
6140
=== modified file 'include/helper/registry.h'
--- include/helper/registry.h 2016-08-08 04:56:35 +0000
+++ include/helper/registry.h 2017-02-27 19:05:17 +0000
@@ -30,6 +30,7 @@
30 Q_DISABLE_COPY(HelperRegistry)30 Q_DISABLE_COPY(HelperRegistry)
3131
32 virtual QStringList get_backup_helper_urls(Metadata const& task) =0;32 virtual QStringList get_backup_helper_urls(Metadata const& task) =0;
33 virtual QStringList get_restore_helper_urls(Metadata const& task) =0;
3334
34protected:35protected:
35 HelperRegistry() =default;36 HelperRegistry() =default;
3637
=== added file 'include/helper/restore-helper.h'
--- include/helper/restore-helper.h 1970-01-01 00:00:00 +0000
+++ include/helper/restore-helper.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 * Charles Kerr <charles.kerr@canonical.com>
19 */
20
21#pragma once
22
23#include "storage-framework/downloader.h"
24#include "helper/helper.h" // parent class
25#include "helper/registry.h"
26
27#include <QObject>
28#include <QScopedPointer>
29#include <QString>
30
31#include <memory>
32
33class RestoreHelperPrivate;
34class RestoreHelper final: public Helper
35{
36 Q_OBJECT
37 Q_DECLARE_PRIVATE(RestoreHelper)
38
39public:
40 RestoreHelper(
41 QString const & appid,
42 clock_func const & clock=Helper::default_clock,
43 QObject * parent=nullptr
44 );
45 virtual ~RestoreHelper();
46 Q_DISABLE_COPY(RestoreHelper)
47
48 static constexpr int MAX_INACTIVITY_TIME = 15000;
49
50 void set_downloader(std::shared_ptr<Downloader> const& downloader);
51
52 void start(QStringList const& urls) override;
53 void stop() override;
54 int get_helper_socket() const;
55 QString to_string(Helper::State state) const override;
56 void set_state(State) override;
57protected:
58 void on_helper_finished() override;
59
60private:
61 QScopedPointer<RestoreHelperPrivate> const d_ptr;
62};
063
=== modified file 'src/cli/CMakeLists.txt'
--- src/cli/CMakeLists.txt 2016-09-06 01:31:59 +0000
+++ src/cli/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -5,6 +5,9 @@
55
6set(CLI_SOURCES6set(CLI_SOURCES
7 main.cpp7 main.cpp
8 command-line.cpp
9 command-line-client.cpp
10 command-line-client-view.cpp
8)11)
912
10add_executable(13add_executable(
@@ -19,6 +22,7 @@
19 util22 util
20 qdbus-stubs23 qdbus-stubs
21 ${SERVICE_DEVEL_SF_DEPS_LIBRARIES}24 ${SERVICE_DEVEL_SF_DEPS_LIBRARIES}
25 ${KEEPER_CLIENT_LIB}
22 Qt5::Core26 Qt5::Core
23 Qt5::DBus27 Qt5::DBus
24)28)
2529
=== added file 'src/cli/command-line-client-view.cpp'
--- src/cli/command-line-client-view.cpp 1970-01-01 00:00:00 +0000
+++ src/cli/command-line-client-view.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,194 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#include "command-line-client-view.h"
20
21#include <client/client.h>
22
23#include <iostream>
24#include <iomanip>
25
26CommandLineClientView::CommandLineClientView(QObject * parent)
27 : QObject(parent)
28{
29 connect(&timer_status_, &QTimer::timeout, this, &CommandLineClientView::show_info);
30
31 // TODO see if we can do this in a better way
32 // This line is for the global progress status and percentage
33 std::cout << std::endl;
34}
35
36void CommandLineClientView::progress_changed(double percentage)
37{
38 percentage_ = percentage * 100;
39}
40
41void CommandLineClientView::status_changed(QString const & status)
42{
43 if (status_ != status)
44 {
45 status_ = status;
46 }
47}
48
49void CommandLineClientView::add_task(QString const & display_name, QString const & initial_status, double initial_percentage)
50{
51 tasks_strings_[display_name] = get_task_string(display_name, initial_status, initial_percentage, keeper::Error::OK);
52 // TODO see if we can do this in a better way
53 // We add a line per each backup task
54 std::cout << std::endl;
55}
56
57void CommandLineClientView::clear_all_tasks()
58{
59 tasks_strings_.clear();
60}
61
62void CommandLineClientView::start_printing_tasks()
63{
64 timer_status_.start(300);
65}
66
67void CommandLineClientView::clear_all()
68{
69 timer_status_.stop();
70 std::cout << std::endl;
71}
72
73void CommandLineClientView::print_sections(QStringList const & sections)
74{
75 for (auto const & section : sections)
76 {
77 std::cout << section.toStdString() << std::endl;
78 }
79}
80
81void CommandLineClientView::print_error_message(QString const & error_message)
82{
83 std::cerr << error_message.toStdString() << std::endl;
84}
85
86void CommandLineClientView::show_info()
87{
88 // TODO Revisit this code to see if we can do this in a different way
89 // Maybe using ncurses?
90
91 // Rewind to the beginning
92 std::cout << '\r' << std::flush;
93 // For every backup task we go up 1 line
94 for (auto i = 0; i < tasks_strings_.size(); ++i)
95 {
96 std::cout << "\e[A";
97 }
98 // print the tasks
99 for (auto iter = tasks_strings_.begin(); iter != tasks_strings_.end(); ++iter)
100 {
101 std::cout << (*iter).toStdString() << std::setfill(' ') << std::endl;
102 }
103 std::cout << '\r' << std::fixed << std::setw(30) << status_.toStdString() << std::setprecision(3)
104 << std::setfill(' ') << " " << percentage_ << " % " << get_next_spin_char() << " " << std::flush;
105}
106
107char CommandLineClientView::get_next_spin_char()
108{
109 char cursor[4]={'/','-','\\','|'};
110 auto ret = cursor[spin_value_];
111 spin_value_ = (spin_value_ + 1) % 4;
112 return ret;
113}
114
115QString CommandLineClientView::get_task_string(QString const & displayName, QString const & status, double percentage, keeper::Error error)
116{
117
118 if (error == keeper::Error::OK)
119 return QStringLiteral("%1 %2 % %3").arg(displayName, 15).arg((percentage * 100), 10, 'f', 2, ' ').arg(status, -15);
120 else
121 return QStringLiteral("%1 %2 % %3 %4").arg(displayName, 15).arg((percentage * 100), 10, 'f', 2, ' ').arg(status, -15).arg(get_error_string(error));
122}
123
124QString CommandLineClientView::get_error_string(keeper::Error error)
125{
126 QString ret;
127 switch(error)
128 {
129 case keeper::Error::UNKNOWN:
130 ret = QStringLiteral("Unknown error");
131 break;
132 case keeper::Error::HELPER_BAD_URL:
133 ret = QStringLiteral("Bad URL for keeper helper");
134 break;
135 case keeper::Error::HELPER_INACTIVITY_DETECTED:
136 ret = QStringLiteral("Inactivity detected in task");
137 break;
138 case keeper::Error::HELPER_START_TIMEOUT:
139 ret = QStringLiteral("Task failed to start");
140 break;
141 case keeper::Error::HELPER_READ:
142 ret = QStringLiteral("Read error");
143 break;
144 case keeper::Error::HELPER_SOCKET:
145 ret = QStringLiteral("Error creating internal socket");
146 break;
147 case keeper::Error::HELPER_WRITE:
148 ret = QStringLiteral("Write error");
149 break;
150 case keeper::Error::MANIFEST_STORAGE:
151 ret = QStringLiteral("Error storing manifest file");
152 break;
153 case keeper::Error::NO_HELPER_INFORMATION_IN_REGISTRY:
154 ret = QStringLiteral("No helper information in registry");
155 break;
156 case keeper::Error::OK:
157 ret = QStringLiteral("Success");
158 break;
159 case keeper::Error::COMMITTING_DATA:
160 ret = QStringLiteral("Error uploading data");
161 break;
162 case keeper::Error::CREATING_REMOTE_DIR:
163 ret = QStringLiteral("Error creating remote directory");
164 break;
165 case keeper::Error::CREATING_REMOTE_FILE:
166 ret = QStringLiteral("Error creating remote file");
167 break;
168 case keeper::Error::READING_REMOTE_FILE:
169 ret = QStringLiteral("Error reading remote file");
170 break;
171 case keeper::Error::REMOTE_DIR_NOT_EXISTS:
172 ret = QStringLiteral("Remote directory does not exist");
173 break;
174 case keeper::Error::NO_REMOTE_ACCOUNTS:
175 ret = QStringLiteral("No remote accounts were found");
176 break;
177 case keeper::Error::NO_REMOTE_ROOTS:
178 ret = QStringLiteral("No remote root accounts were found");
179 break;
180 case keeper::Error::ACCOUNT_NOT_FOUND:
181 ret = QStringLiteral("The storage account was not found");
182 break;
183 }
184 return ret;
185}
186
187void CommandLineClientView::on_task_state_changed(QString const & displayName, QString const & status, double percentage, keeper::Error error)
188{
189 auto iter = tasks_strings_.find(displayName);
190 if (iter != tasks_strings_.end())
191 {
192 tasks_strings_[displayName] = get_task_string(displayName, status, percentage, error);
193 }
194}
0195
=== added file 'src/cli/command-line-client-view.h'
--- src/cli/command-line-client-view.h 1970-01-01 00:00:00 +0000
+++ src/cli/command-line-client-view.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,60 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#pragma once
20
21#include <client/keeper-errors.h>
22
23#include <QMap>
24#include <QObject>
25#include <QTimer>
26
27class CommandLineClientView : public QObject
28{
29 Q_OBJECT
30public:
31 explicit CommandLineClientView(QObject * parent = nullptr);
32 ~CommandLineClientView() = default;
33
34 Q_DISABLE_COPY(CommandLineClientView)
35
36 void progress_changed(double percentage);
37 void status_changed(QString const & status);
38
39 void add_task(QString const & display_name, QString const & initial_status, double initial_percentage);
40 void clear_all_tasks();
41 void start_printing_tasks();
42 void clear_all();
43 void print_sections(QStringList const & sections);
44 void print_error_message(QString const & error_message);
45 QString get_error_string(keeper::Error error);
46
47public Q_SLOTS:
48 void show_info();
49 void on_task_state_changed(QString const & displayName, QString const & status, double percentage, keeper::Error error);
50
51private:
52 char get_next_spin_char();
53 QString get_task_string(QString const & displayName, QString const & status, double percentage, keeper::Error error);
54
55 QString status_;
56 QTimer timer_status_;
57 double percentage_ = 0.0;
58 int spin_value_ = 0;
59 QMap<QString, QString> tasks_strings_;
60};
061
=== added file 'src/cli/command-line-client.cpp'
--- src/cli/command-line-client.cpp 1970-01-01 00:00:00 +0000
+++ src/cli/command-line-client.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,250 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#include "command-line-client.h"
20#include "command-line-client-view.h"
21
22#include <client/client.h>
23
24#include <QCoreApplication>
25#include <QDebug>
26
27#include <iostream>
28#include <iomanip>
29
30CommandLineClient::CommandLineClient(QObject * parent)
31 : QObject(parent)
32 , keeper_client_(new KeeperClient(this))
33 , view_(new CommandLineClientView(this))
34{
35 connect(keeper_client_.data(), &KeeperClient::statusChanged, this, &CommandLineClient::on_status_changed);
36 connect(keeper_client_.data(), &KeeperClient::progressChanged, this, &CommandLineClient::on_progress_changed);
37 connect(keeper_client_.data(), &KeeperClient::finished, this, &CommandLineClient::on_keeper_client_finished);
38 connect(keeper_client_.data(), &KeeperClient::taskStatusChanged, view_.data(), &CommandLineClientView::on_task_state_changed);
39}
40
41CommandLineClient::~CommandLineClient() = default;
42
43void CommandLineClient::run_list_sections(bool remote, QString const & storage)
44{
45 keeper::Items choices_values;
46 keeper::Error error;
47 if(!remote)
48 {
49 choices_values = keeper_client_->getBackupChoices(error);
50 check_for_choices_error(error);
51 list_backup_sections(choices_values);
52 }
53 else
54 {
55 choices_values = keeper_client_->getRestoreChoices(storage, error);
56 check_for_choices_error(error);
57 list_restore_sections(choices_values);
58 }
59}
60
61void CommandLineClient::run_list_storage_accounts()
62{
63 list_storage_accounts(keeper_client_->getStorageAccounts());
64}
65
66void CommandLineClient::run_backup(QStringList & sections, QString const & storage)
67{
68 auto unhandled_sections = sections;
69 keeper::Error error;
70 auto choices_values = keeper_client_->getBackupChoices(error);
71 check_for_choices_error(error);
72 QStringList uuids;
73
74 auto uuids_choices = choices_values.get_uuids();
75 for(auto iter = uuids_choices.begin(); iter != uuids_choices.end() && unhandled_sections.size(); ++iter)
76 {
77 const auto& values = choices_values[(*iter)];
78
79 if (values.is_valid() && values.get_type() == keeper::Item::FOLDER_VALUE)
80 {
81
82 auto display_name = values.get_display_name();
83 auto index = unhandled_sections.indexOf(display_name);
84 if (index != -1)
85 {
86 // we have to backup this section
87 uuids << (*iter);
88 unhandled_sections.removeAt(index);
89 view_->add_task(display_name, "waiting", 0.0);
90 }
91 }
92 }
93
94 if (!unhandled_sections.isEmpty())
95 {
96 QString error_message("The following sections were not found: \n");
97 for (auto const & section : unhandled_sections)
98 {
99 error_message += QStringLiteral("\t %1 \n").arg(section);
100 }
101 view_->print_error_message(error_message);
102 exit(1);
103 }
104
105 for (auto const & uuid: uuids)
106 {
107 keeper_client_->enableBackup(uuid, true);
108 }
109 keeper_client_->startBackup(storage);
110 view_->start_printing_tasks();
111}
112
113void CommandLineClient::run_restore(QStringList & sections, QString const & storage)
114{
115 auto unhandled_sections = sections;
116 keeper::Error error;
117
118 auto choices_values = keeper_client_->getRestoreChoices(storage, error);
119 check_for_choices_error(error);
120 QStringList uuids;
121
122 auto uuids_choices = choices_values.get_uuids();
123 for(auto iter = uuids_choices.begin(); iter != uuids_choices.end(); ++iter)
124 {
125 const auto& values = choices_values[(*iter)];
126
127 if (values.is_valid() && values.get_type() == keeper::Item::FOLDER_VALUE)
128 {
129 auto display_name = values.get_display_name();
130 auto dir_name = values.get_dir_name();
131
132 auto section_name = QStringLiteral("%1:%2").arg(display_name).arg(dir_name);
133 auto index = unhandled_sections.indexOf(section_name);
134 if (index != -1)
135 {
136 // we have to restore this section
137 uuids << (*iter);
138 unhandled_sections.removeAt(index);
139 view_->add_task(display_name, "waiting", 0.0);
140 }
141 }
142 }
143 if (!unhandled_sections.isEmpty())
144 {
145 QString error_message("The following sections were not found: \n");
146 for (auto const & section : unhandled_sections)
147 {
148 error_message += QStringLiteral("\t %1 \n").arg(section);
149 }
150 view_->print_error_message(error_message);
151 exit(1);
152 }
153
154 for (auto const & uuid: uuids)
155 {
156 keeper_client_->enableRestore(uuid, true);
157 }
158 keeper_client_->startRestore(storage);
159 view_->start_printing_tasks();
160}
161
162void CommandLineClient::run_cancel() const
163{
164 keeper_client_->cancel();
165}
166
167void CommandLineClient::list_backup_sections(keeper::Items const & choices_values)
168{
169 QStringList sections;
170 for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter)
171 {
172 if ((*iter).is_valid() && (*iter).get_type() == keeper::Item::FOLDER_VALUE)
173 {
174 sections << (*iter).get_display_name();
175 }
176 }
177 view_->print_sections(sections);
178}
179
180void CommandLineClient::list_restore_sections(keeper::Items const & choices_values)
181{
182 QMap<QString, QList<keeper::Item>> values_per_dir;
183
184 for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter)
185 {
186 if ((*iter).is_valid() && (*iter).get_type() == keeper::Item::FOLDER_VALUE)
187 {
188 auto dir_name = (*iter).get_dir_name();
189 if (!dir_name.isEmpty())
190 {
191 values_per_dir[dir_name].push_back((*iter));
192 }
193 }
194 }
195
196 QStringList sections;
197 for(auto iter = values_per_dir.begin(); iter != values_per_dir.end(); ++iter)
198 {
199 for(auto iter_items = (*iter).begin(); iter_items != (*iter).end(); ++iter_items)
200 {
201 const auto& values = (*iter_items);
202 sections << QStringLiteral("%1:%2").arg(values.get_display_name()).arg(iter.key());
203 }
204 sections << "";
205 }
206 view_->print_sections(sections);
207}
208
209void CommandLineClient::list_storage_accounts(QStringList const & accounts)
210{
211 view_->print_sections(accounts);
212}
213
214void CommandLineClient::on_progress_changed()
215{
216 view_->progress_changed(keeper_client_->progress());
217}
218
219void CommandLineClient::on_status_changed()
220{
221 view_->status_changed(keeper_client_->status());
222}
223
224void CommandLineClient::on_keeper_client_finished()
225{
226 QCoreApplication::processEvents();
227 view_->show_info();
228 view_->clear_all();
229 QCoreApplication::exit(0);
230}
231
232bool CommandLineClient::find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value)
233{
234 auto iter = choice.find(id);
235 if (iter == choice.end())
236 return false;
237 value = (*iter);
238 return true;
239}
240
241void CommandLineClient::check_for_choices_error(keeper::Error error)
242{
243 if (error != keeper::Error::OK)
244 {
245 // an error occurred
246 auto error_message = QStringLiteral("Error obtaining keeper choices: %1").arg(view_->get_error_string(error));
247 view_->print_error_message(error_message);
248 return;
249 }
250}
0251
=== added file 'src/cli/command-line-client.h'
--- src/cli/command-line-client.h 1970-01-01 00:00:00 +0000
+++ src/cli/command-line-client.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#pragma once
20
21#include <QMap>
22#include <QObject>
23#include <QScopedPointer>
24#include <QTimer>
25#include "../../include/client/keeper-items.h"
26
27class KeeperClient;
28class CommandLineClientView;
29
30class CommandLineClient : public QObject
31{
32 Q_OBJECT
33public:
34 explicit CommandLineClient(QObject * parent = nullptr);
35 ~CommandLineClient();
36
37 Q_DISABLE_COPY(CommandLineClient)
38
39 void run_list_sections(bool remote, QString const & storage = "");
40 void run_list_storage_accounts();
41 void run_backup(QStringList & sections, QString const & storage);
42 void run_restore(QStringList & sections, QString const & storage);
43 void run_cancel() const;
44
45private Q_SLOTS:
46 void on_progress_changed();
47 void on_status_changed();
48 void on_keeper_client_finished();
49
50private:
51 bool find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value);
52 void list_backup_sections(keeper::Items const & choices);
53 void list_restore_sections(keeper::Items const & choices);
54 void list_storage_accounts(QStringList const & accounts);
55 void check_for_choices_error(keeper::Error error);
56 QScopedPointer<KeeperClient> keeper_client_;
57 QScopedPointer<CommandLineClientView> view_;
58};
059
=== added file 'src/cli/command-line.cpp'
--- src/cli/command-line.cpp 1970-01-01 00:00:00 +0000
+++ src/cli/command-line.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,234 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#include "command-line.h"
20
21#include <QCommandLineParser>
22#include <QDebug>
23
24#include <iostream>
25
26namespace
27{
28 // arguments
29 constexpr const char ARGUMENT_LIST_SECTIONS[] = "list-sections";
30 constexpr const char ARGUMENT_LIST_STORAGE_ACCOUNTS[] = "list-storage-configs";
31 constexpr const char ARGUMENT_BACKUP[] = "backup";
32 constexpr const char ARGUMENT_RESTORE[] = "restore";
33
34 // argument descriptions
35 constexpr const char ARGUMENT_LIST_SECTIONS_DESCRIPTION[] = "List the sections available to backup";
36 constexpr const char ARGUMENT_LIST_STORAGE_ACCOUNTS_DESCRIPTION[] = "List the available storage accounts";
37 constexpr const char ARGUMENT_BACKUP_DESCRIPTION[] = "Starts a backup";
38 constexpr const char ARGUMENT_RESTORE_DESCRIPTION[] = "Starts a restore";
39
40 // options
41 constexpr const char OPTION_STORAGE[] = "storage";
42 constexpr const char OPTION_SECTIONS[] = "sections";
43
44 // option descriptions
45 constexpr const char OPTION_STORAGE_DESCRIPTION[] = "Defines the available storage to use. Pass 'default' to use the default one";
46 constexpr const char OPTION_SECTIONS_DESCRIPTION[] = "Lists the sections to backup or restore";
47}
48
49CommandLineParser::CommandLineParser()
50 : parser_(new QCommandLineParser)
51{
52 parser_->setApplicationDescription("Keeper command line client");
53 parser_->addHelpOption();
54 parser_->addVersionOption();
55 parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION));
56 parser_->addPositionalArgument(ARGUMENT_LIST_STORAGE_ACCOUNTS, QCoreApplication::translate("main", ARGUMENT_LIST_STORAGE_ACCOUNTS_DESCRIPTION));
57 parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION));
58 parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION));
59}
60
61bool CommandLineParser::parse(QStringList const & arguments, QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args)
62{
63 parser_->parse(arguments);
64 const QStringList args = parser_->positionalArguments();
65 if (!check_number_of_args(args))
66 {
67 return false;
68 }
69
70 if (args.size() == 1)
71 {
72 // if something fails at the process call the process exists
73 if (args.at(0) == ARGUMENT_LIST_SECTIONS)
74 {
75 return handle_list_sections(app, cmd_args);
76 }
77 else if (args.at(0) == ARGUMENT_LIST_STORAGE_ACCOUNTS)
78 {
79 return handle_list_storage_accounts(app, cmd_args);
80 }
81 else if (args.at(0) == ARGUMENT_BACKUP)
82 {
83 return handle_backup(app, cmd_args);
84 }
85 else if (args.at(0) == ARGUMENT_RESTORE)
86 {
87 return handle_restore(app, cmd_args);
88 }
89 else
90 {
91 std::cerr << "Bad argument." << std::endl;
92 std::cerr << parser_->errorText().toStdString() << std::endl;
93 exit(1);
94 }
95 }
96 else
97 {
98 qDebug() << "More or none arguments";
99 // maybe we have the version or help options
100 parser_->process(app);
101 }
102
103 return false;
104}
105
106bool CommandLineParser::handle_list_sections(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args)
107{
108 parser_->clearPositionalArguments();
109 parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION));
110
111 parser_->addOptions({
112 {{"r", OPTION_STORAGE},
113 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION),
114 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION)
115 },
116 });
117 parser_->process(app);
118
119 // it didn't exit... we're good
120 cmd_args.sections.clear();
121 cmd_args.storage.clear();
122 if (parser_->isSet(OPTION_STORAGE))
123 {
124 cmd_args.cmd = CommandLineParser::Command::LIST_REMOTE_SECTIONS;
125 cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE));
126 }
127 else
128 {
129 cmd_args.cmd = CommandLineParser::Command::LIST_LOCAL_SECTIONS;
130 }
131
132 return true;
133}
134
135bool CommandLineParser::handle_list_storage_accounts(QCoreApplication const & app, CommandArgs & cmd_args)
136{
137 parser_->process(app);
138 // it didn't exit... we're good
139 cmd_args.sections.clear();
140 cmd_args.storage.clear();
141 cmd_args.cmd = CommandLineParser::Command::LIST_STORAGE_ACCOUNTS;
142
143 return true;
144}
145
146bool CommandLineParser::handle_backup(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args)
147{
148 parser_->clearPositionalArguments();
149 parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION));
150
151 parser_->addOptions({
152 {{"s", OPTION_SECTIONS},
153 QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION),
154 QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION)
155 },
156 {{"r", OPTION_STORAGE},
157 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION),
158 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION)
159 },
160 });
161 parser_->process(app);
162
163 // it didn't exit... we're good
164 cmd_args.sections.clear();
165 cmd_args.storage.clear();
166 cmd_args.cmd = CommandLineParser::Command::BACKUP;
167 if (!parser_->isSet(OPTION_SECTIONS))
168 {
169 std::cerr << "You need to specify some sections to run a backup." << std::endl;
170 return false;
171 }
172 if (parser_->isSet(OPTION_STORAGE))
173 {
174 cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE));
175 }
176 cmd_args.sections = parser_->value(OPTION_SECTIONS).split(',');
177
178 return true;
179}
180
181bool CommandLineParser::handle_restore(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args)
182{
183 parser_->clearPositionalArguments();
184 parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION));
185
186 parser_->addOptions({
187 {{"s", OPTION_SECTIONS},
188 QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION),
189 QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION)
190 },
191 {{"r", OPTION_STORAGE},
192 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION),
193 QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION)
194 },
195 });
196 parser_->process(app);
197
198 // it didn't exit... we're good
199 cmd_args.sections.clear();
200 cmd_args.storage.clear();
201 cmd_args.cmd = CommandLineParser::Command::RESTORE;
202 if (!parser_->isSet(OPTION_SECTIONS))
203 {
204 std::cerr << "You need to specify some sections to run a restore." << std::endl;
205 return false;
206 }
207 if (parser_->isSet(OPTION_STORAGE))
208 {
209 cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE));
210 }
211 cmd_args.sections = parser_->value(OPTION_SECTIONS).split(',');
212
213 return true;
214}
215
216bool CommandLineParser::check_number_of_args(QStringList const & args)
217{
218 if (args.size() > 1)
219 {
220 std::cerr << "Please, pass only one argument." << std::endl;
221 std::cerr << parser_->helpText().toStdString() << std::endl;
222 return false;
223 }
224 return true;
225}
226
227QString CommandLineParser::get_storage_string(QString const & value)
228{
229 if (value == "default")
230 {
231 return QString();
232 }
233 return value;
234}
0235
=== added file 'src/cli/command-line.h'
--- src/cli/command-line.h 1970-01-01 00:00:00 +0000
+++ src/cli/command-line.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19#pragma once
20
21#include <QCoreApplication>
22#include <QSharedPointer>
23
24class QCommandLineParser;
25
26class CommandLineParser
27{
28public:
29 Q_ENUMS(Command)
30 enum class Command {LIST_LOCAL_SECTIONS, LIST_REMOTE_SECTIONS, LIST_STORAGE_ACCOUNTS, BACKUP, RESTORE};
31 struct CommandArgs
32 {
33 Command cmd;
34 QStringList sections;
35 QString storage;
36 };
37
38 CommandLineParser();
39 ~CommandLineParser() = default;
40 Q_DISABLE_COPY(CommandLineParser)
41
42 bool parse(QStringList const & arguments, QCoreApplication const & app, CommandArgs & cmd_args);
43
44private:
45 bool handle_list_sections(QCoreApplication const & app, CommandArgs & cmd_args);
46 bool handle_list_storage_accounts(QCoreApplication const & app, CommandArgs & cmd_args);
47 bool handle_backup(QCoreApplication const & app, CommandArgs & cmd_args);
48 bool handle_restore(QCoreApplication const & app, CommandArgs & cmd_args);
49
50 bool check_number_of_args(QStringList const & args);
51
52 QString get_storage_string(QString const & value);
53
54 QSharedPointer<QCommandLineParser> parser_;
55};
056
=== modified file 'src/cli/main.cpp'
--- src/cli/main.cpp 2016-08-30 14:16:19 +0000
+++ src/cli/main.cpp 2017-02-27 19:05:17 +0000
@@ -17,9 +17,12 @@
17 * Charles Kerr <charles.kerr@canonical.com>17 * Charles Kerr <charles.kerr@canonical.com>
18 * Xavi Garcia <xavi.garcia.mena@canonical.com>18 * Xavi Garcia <xavi.garcia.mena@canonical.com>
19 */19 */
20#include "command-line.h"
21#include "command-line-client.h"
2022
21#include <dbus-types.h>23#include <dbus-types.h>
22#include <util/logging.h>24#include <util/logging.h>
25#include "util/unix-signal-handler.h"
2326
24#include <keeper_user_interface.h>27#include <keeper_user_interface.h>
2528
@@ -29,6 +32,8 @@
29#include <libintl.h>32#include <libintl.h>
30#include <cstdlib>33#include <cstdlib>
31#include <ctime>34#include <ctime>
35#include <iostream>
36
3237
33int38int
34main(int argc, char **argv)39main(int argc, char **argv)
@@ -37,60 +42,49 @@
3742
38 QCoreApplication app(argc, argv);43 QCoreApplication app(argc, argv);
39 DBusTypes::registerMetaTypes();44 DBusTypes::registerMetaTypes();
40// Variant::registerMetaTypes();
41 std::srand(unsigned(std::time(nullptr)));45 std::srand(unsigned(std::time(nullptr)));
4246
47 util::UnixSignalHandler handler([]{
48 CommandLineClient client;
49 client.run_cancel();
50 });
51 handler.setupUnixSignalHandlers();
52
43 // boilerplate locale53 // boilerplate locale
44 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");54 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
45 setlocale(LC_ALL, "");55 setlocale(LC_ALL, "");
46 bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);56 bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
47 textdomain(GETTEXT_PACKAGE);57 textdomain(GETTEXT_PACKAGE);
4858
49 if (argc == 2 && QString("--print-address") == argv[1])59 QCoreApplication::setApplicationName("keeper");
50 {60 QCoreApplication::setApplicationVersion("1.0");
51 qDebug() << QDBusConnection::sessionBus().baseService();61
52 }62 CommandLineParser parser;
5363 CommandLineClient client;
54 qDebug() << "Argc =" << argc;64 CommandLineParser::CommandArgs cmd_args;
55 if (argc == 2 && QString("--use-uuids") == argv[1])65 if (parser.parse(QCoreApplication::arguments(), app, cmd_args))
56 {66 {
57 QScopedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(67 switch(cmd_args.cmd)
58 DBusTypes::KEEPER_SERVICE,68 {
59 DBusTypes::KEEPER_USER_PATH,69 case CommandLineParser::Command::LIST_LOCAL_SECTIONS:
60 QDBusConnection::sessionBus()70 client.run_list_sections(false);
61 ) );71 exit(0);
62 QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices");72 break;
63 if (!choices.isValid())73 case CommandLineParser::Command::LIST_STORAGE_ACCOUNTS:
64 {74 client.run_list_storage_accounts();
65 qWarning() << "Error getting backup choices:" << choices.error().message();75 exit(0);
66 }76 break;
6777 case CommandLineParser::Command::LIST_REMOTE_SECTIONS:
68 QStringList uuids;78 client.run_list_sections(true, cmd_args.storage);
69 auto choices_values = choices.value();79 exit(0);
70 for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter)80 break;
71 {81 case CommandLineParser::Command::BACKUP:
72 const auto& values = iter.value();82 client.run_backup(cmd_args.sections, cmd_args.storage);
73 auto iter_values = values.find("type");83 break;
74 if (iter_values != values.end())84 case CommandLineParser::Command::RESTORE:
75 {85 client.run_restore(cmd_args.sections, cmd_args.storage);
76 if (iter_values.value().toString() == "folder")86 break;
77 {87 };
78 qDebug() << "Adding uuid" << iter.key() << "with type:" << "folder";
79 uuids << iter.key();
80 }
81 }
82 }
83
84 QDBusReply<void> backup_reply = user_iface->call("StartBackup", uuids);
85
86 if (!backup_reply.isValid())
87 {
88 qWarning() << "Error starting backup:" << backup_reply.error().message();
89 }
90 }
91 else
92 {
93 qWarning() << "FIXME";
94 }88 }
9589
9690
9791
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2016-08-26 09:30:11 +0000
+++ src/client/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -1,8 +1,24 @@
1add_subdirectory(qml-plugin)1add_subdirectory(qml-plugin)
22
3set(3set(
4 KEEPER_ERRORS_LIB
5 keeper-errors-lib
6)
7
8add_library(
9 ${KEEPER_ERRORS_LIB}
10 STATIC
11 keeper-errors.cpp
12 ${CMAKE_SOURCE_DIR}/include/client/keeper-errors.h
13 ${CMAKE_SOURCE_DIR}/include/client/keeper-items.h
14 items.cpp
15)
16
17set(
4 CLIENT_HEADERS18 CLIENT_HEADERS
5 ${CMAKE_SOURCE_DIR}/include/client/client.h19 ${CMAKE_SOURCE_DIR}/include/client/client.h
20 ${CMAKE_SOURCE_DIR}/include/client/keeper-errors.h
21 ${CMAKE_SOURCE_DIR}/include/client/keeper-items.h
6)22)
723
8add_library(24add_library(
@@ -11,8 +27,14 @@
11 ${CLIENT_HEADERS}27 ${CLIENT_HEADERS}
12)28)
1329
30set_target_properties(${KEEPER_CLIENT_LIB} PROPERTIES
31 AUTOMOC TRUE
32 LINK_FLAGS "-Wl,--no-undefined"
33)
34
14target_link_libraries(35target_link_libraries(
15 ${KEEPER_CLIENT_LIB}36 ${KEEPER_CLIENT_LIB}
37 ${KEEPER_ERRORS_LIB}
16 qdbus-stubs38 qdbus-stubs
17 Qt5::Core39 Qt5::Core
18 Qt5::DBus40 Qt5::DBus
1941
=== modified file 'src/client/client.cpp'
--- src/client/client.cpp 2016-08-26 08:48:05 +0000
+++ src/client/client.cpp 2017-02-27 19:05:17 +0000
@@ -22,34 +22,100 @@
22#include <client/client.h>22#include <client/client.h>
2323
24#include <qdbus-stubs/keeper_user_interface.h>24#include <qdbus-stubs/keeper_user_interface.h>
25#include <qdbus-stubs/DBusPropertiesInterface.h>
26#include <qdbus-stubs/dbus-types.h>
2527
26struct KeeperClientPrivate final28struct KeeperClientPrivate final
27{29{
28 Q_DISABLE_COPY(KeeperClientPrivate)30 Q_DISABLE_COPY(KeeperClientPrivate)
2931
30 KeeperClientPrivate(QObject* parent)32 enum class TasksMode { IDLE_MODE, BACKUP_MODE, RESTORE_MODE };
33
34 explicit KeeperClientPrivate(QObject* /* parent */)
31 : userIface(new DBusInterfaceKeeperUser(35 : userIface(new DBusInterfaceKeeperUser(
32 DBusTypes::KEEPER_SERVICE,36 DBusTypes::KEEPER_SERVICE,
33 DBusTypes::KEEPER_USER_PATH,37 DBusTypes::KEEPER_USER_PATH,
34 QDBusConnection::sessionBus()38 QDBusConnection::sessionBus()
35 )),39 ))
36 status(""),40 , propertiesIface(new DBusPropertiesInterface(
37 progress(0),41 DBusTypes::KEEPER_SERVICE,
38 readyToBackup(false),42 DBusTypes::KEEPER_USER_PATH,
39 backupBusy(false),43 QDBusConnection::sessionBus()
40 stateTimer(parent)44 ))
41 {45 {
42 }46 }
4347
44 ~KeeperClientPrivate() = default;48 ~KeeperClientPrivate() = default;
4549
50 struct TaskStatus
51 {
52 QString status;
53 double percentage;
54 };
55
56 static bool stateIsFinal(QString const & stateString)
57 {
58 return (stateString == "complete" || stateString == "cancelled" || stateString == "failed");
59 }
60
61 bool checkAllTasksFinished(keeper::Items const & state) const
62 {
63 bool ret = true;
64 for (auto iter = state.begin(); ret && (iter != state.end()); ++iter)
65 {
66 auto statusString = (*iter).get_status();
67 ret = stateIsFinal(statusString);
68 }
69 return ret;
70 }
71
72 static keeper::Items getValue(QDBusMessage const & message, keeper::Error & error)
73 {
74 if (message.errorMessage().isEmpty())
75 {
76 if (message.arguments().count() != 1)
77 {
78 error = keeper::Error::UNKNOWN;
79 return keeper::Items();
80 }
81
82 auto value = message.arguments().at(0);
83 if (value.typeName() != QStringLiteral("QDBusArgument"))
84 {
85 error = keeper::Error::UNKNOWN;
86 return keeper::Items();
87 }
88 auto dbus_arg = value.value<QDBusArgument>();
89 error = keeper::Error::OK;
90 keeper::Items ret;
91 dbus_arg >> ret;
92 return ret;
93 }
94 if (message.arguments().count() != 2)
95 {
96 error = keeper::Error::UNKNOWN;
97 return keeper::Items();
98 }
99
100 // pick up the error
101 bool valid;
102 error = keeper::convert_from_dbus_variant(message.arguments().at(1), &valid);
103 if (!valid)
104 {
105 error = keeper::Error::UNKNOWN;
106 }
107 return keeper::Items();
108 }
109
46 QScopedPointer<DBusInterfaceKeeperUser> userIface;110 QScopedPointer<DBusInterfaceKeeperUser> userIface;
111 QScopedPointer<DBusPropertiesInterface> propertiesIface;
47 QString status;112 QString status;
48 QMap<QString, QVariantMap> backups;113 keeper::Items backups;
49 double progress;114 double progress = 0;
50 bool readyToBackup;115 bool readyToBackup = false;
51 bool backupBusy;116 bool backupBusy = false;
52 QTimer stateTimer;117 QMap<QString, TaskStatus> taskStatus;
118 TasksMode mode = TasksMode::IDLE_MODE;
53};119};
54120
55KeeperClient::KeeperClient(QObject* parent) :121KeeperClient::KeeperClient(QObject* parent) :
@@ -60,13 +126,15 @@
60126
61 // Store backups list locally with an additional "enabled" pair to keep track enabled states127 // Store backups list locally with an additional "enabled" pair to keep track enabled states
62 // TODO: We should be listening to a backupChoicesChanged signal to keep this list updated128 // TODO: We should be listening to a backupChoicesChanged signal to keep this list updated
63 d->backups = getBackupChoices();129 keeper::Error error;
130 d->backups = getBackupChoices(error);
131
64 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)132 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)
65 {133 {
66 iter.value()["enabled"] = false;134 iter.value()["enabled"] = false;
67 }135 }
68136
69 connect(&d->stateTimer, &QTimer::timeout, this, &KeeperClient::stateUpdated);137 connect(d->propertiesIface.data(), &DBusPropertiesInterface::PropertiesChanged, this, &KeeperClient::stateUpdated);
70}138}
71139
72KeeperClient::~KeeperClient() = default;140KeeperClient::~KeeperClient() = default;
@@ -77,7 +145,7 @@
77 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)145 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)
78 {146 {
79 // TODO: We currently only support "folder" type backups147 // TODO: We currently only support "folder" type backups
80 if (iter.value().value("type").toString() == "folder")148 if (iter.value().get_type() == keeper::Item::FOLDER_VALUE)
81 {149 {
82 returnList.append(iter.key());150 returnList.append(iter.key());
83 }151 }
@@ -120,17 +188,19 @@
120 }188 }
121 }189 }
122190
191 d->taskStatus[uuid] = KeeperClientPrivate::TaskStatus{"", 0.0};
192
123 Q_EMIT readyToBackupChanged();193 Q_EMIT readyToBackupChanged();
124}194}
125195
126void KeeperClient::startBackup()196void KeeperClient::enableRestore(QString uuid, bool enabled)
127{197{
128 // TODO: Instead of polling for state, we should be listening to a stateChanged signal198 // Until we re-design the client we treat restores as backups
129 if (!d->stateTimer.isActive())199 enableBackup(uuid, enabled);
130 {200}
131 d->stateTimer.start(200);
132 }
133201
202void KeeperClient::startBackup(QString const & storage)
203{
134 // Determine which backups are enabled, and start only those204 // Determine which backups are enabled, and start only those
135 QStringList backupList;205 QStringList backupList;
136 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)206 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)
@@ -143,8 +213,9 @@
143213
144 if (!backupList.empty())214 if (!backupList.empty())
145 {215 {
146 startBackup(backupList);216 startBackup(backupList, storage);
147217
218 d->mode = KeeperClientPrivate::TasksMode::BACKUP_MODE;
148 d->status = "Preparing Backup...";219 d->status = "Preparing Backup...";
149 Q_EMIT statusChanged();220 Q_EMIT statusChanged();
150 d->backupBusy = true;221 d->backupBusy = true;
@@ -152,27 +223,60 @@
152 }223 }
153}224}
154225
226void KeeperClient::startRestore(QString const & storage)
227{
228 // Determine which restores are enabled, and start only those
229 QStringList restoreList;
230 for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter)
231 {
232 if (iter.value().value("enabled").toBool())
233 {
234 restoreList.append(iter.key());
235 }
236 }
237
238 if (!restoreList.empty())
239 {
240 startRestore(restoreList, storage);
241
242 d->mode = KeeperClientPrivate::TasksMode::RESTORE_MODE;
243 d->status = "Preparing Restore...";
244 Q_EMIT statusChanged();
245 d->backupBusy = true;
246 Q_EMIT backupBusyChanged();
247 }
248}
249
250void KeeperClient::cancel()
251{
252 QDBusReply<void> cancelReply = d->userIface->call("Cancel");
253
254 if (!cancelReply.isValid())
255 {
256 qWarning() << "Error canceling" << cancelReply.error().message();
257 }
258}
259
155QString KeeperClient::getBackupName(QString uuid)260QString KeeperClient::getBackupName(QString uuid)
156{261{
157 return d->backups.value(uuid).value("display-name").toString();262 return d->backups.value(uuid).get_display_name();
158}263}
159264
160QMap<QString, QVariantMap> KeeperClient::getBackupChoices() const265keeper::Items KeeperClient::getBackupChoices(keeper::Error & error) const
161{266{
162 QDBusReply<QMap<QString, QVariantMap>> choices = d->userIface->call("GetBackupChoices");267 QDBusMessage choices = d->userIface->call("GetBackupChoices");
163268 return KeeperClientPrivate::getValue(choices, error);
164 if (!choices.isValid())269}
165 {270
166 qWarning() << "Error getting backup choices:" << choices.error().message();271keeper::Items KeeperClient::getRestoreChoices(QString const & storage, keeper::Error & error) const
167 return QMap<QString, QVariantMap>();272{
168 }273 QDBusMessage choices = d->userIface->call("GetRestoreChoices", storage);
169274 return KeeperClientPrivate::getValue(choices, error);
170 return choices.value();275}
171}276
172277void KeeperClient::startBackup(const QStringList& uuids, QString const & storage) const
173void KeeperClient::startBackup(const QStringList& uuids) const278{
174{279 QDBusReply<void> backupReply = d->userIface->call("StartBackup", uuids, storage);
175 QDBusReply<void> backupReply = d->userIface->call("StartBackup", uuids);
176280
177 if (!backupReply.isValid())281 if (!backupReply.isValid())
178 {282 {
@@ -180,51 +284,110 @@
180 }284 }
181}285}
182286
183QMap<QString, QVariantMap> KeeperClient::getState() const287void KeeperClient::startRestore(const QStringList& uuids, QString const & storage) const
288{
289 QDBusReply<void> backupReply = d->userIface->call("StartRestore", uuids, storage);
290
291 if (!backupReply.isValid())
292 {
293 qWarning() << "Error starting restore:" << backupReply.error().message();
294 }
295}
296
297keeper::Items KeeperClient::getState() const
184{298{
185 return d->userIface->state();299 return d->userIface->state();
186}300}
187301
302QStringList KeeperClient::getStorageAccounts() const
303{
304 QDBusPendingReply<QStringList> accountsReply = d->userIface->call("GetStorageAccounts");
305
306 accountsReply.waitForFinished();
307 if (!accountsReply.isValid())
308 {
309 qWarning() << "Error retrieving storage accounts:" << accountsReply.error().message();
310 }
311
312 return accountsReply.value();
313}
314
188void KeeperClient::stateUpdated()315void KeeperClient::stateUpdated()
189{316{
190 auto states = getState();317 auto states = getState();
191318
192 if (!states.empty())319 if (!states.empty())
193 {320 {
194 // Calculate current total progress321 for (auto const & uuid : d->taskStatus.keys())
195 // TODO: May be better to monitor each backup's progress separately instead of total322 {
196 // to avoid irregular jumps in progress between larger and smaller backups323 auto iter_state = states.find(uuid);
324 if (iter_state == states.end())
325 {
326 qWarning() << "State for uuid: " << uuid << " was not found";
327 }
328 keeper::Item keeper_item((*iter_state));
329 auto progress = keeper_item.get_percent_done();
330 auto status = keeper_item.get_status();
331 auto keeper_error = keeper_item.get_error();
332
333 auto current_state = d->taskStatus[uuid];
334 if (current_state.status != status || current_state.percentage < progress)
335 {
336 d->taskStatus[uuid].status = status;
337 d->taskStatus[uuid].percentage = progress;
338 Q_EMIT(taskStatusChanged(keeper_item.get_display_name(), status, progress, keeper_error));
339 }
340 }
341
197 double totalProgress = 0;342 double totalProgress = 0;
198 for (auto const& state : states)343 for (auto const& state : states)
199 {344 {
200 totalProgress += state.value("percent-done").toDouble();345 keeper::Item keeper_item(state);
346 totalProgress += keeper_item.get_percent_done();
201 }347 }
202348
203 d->progress = totalProgress / states.count();349 d->progress = totalProgress / states.count();
204 Q_EMIT progressChanged();350 Q_EMIT progressChanged();
205351
352 auto allTasksFinished = d->checkAllTasksFinished(states);
206 // Update backup status353 // Update backup status
354 QString statusString;
355 if (d->mode == KeeperClientPrivate::TasksMode::BACKUP_MODE)
356 {
357 statusString = QStringLiteral("Backup");
358 }
359 else if (d->mode == KeeperClientPrivate::TasksMode::RESTORE_MODE)
360 {
361 statusString = QStringLiteral("Restore");
362 }
207 if (d->progress > 0 && d->progress < 1)363 if (d->progress > 0 && d->progress < 1)
208 {364 {
209 d->status = "Backup In Progress...";365 d->status = statusString + QStringLiteral(" In Progress...");
210 Q_EMIT statusChanged();366 Q_EMIT statusChanged();
211367
212 d->backupBusy = true;368 d->backupBusy = true;
213 Q_EMIT backupBusyChanged();369 Q_EMIT backupBusyChanged();
214 }370 }
215 else if (d->progress >= 1)371 else if (d->progress >= 1 && !allTasksFinished)
216 {372 {
217 d->status = "Backup Complete";373 d->status = statusString + QStringLiteral(" Finishing...");
374 Q_EMIT statusChanged();
375
376 d->backupBusy = true;
377 Q_EMIT backupBusyChanged();
378 }
379 else if (allTasksFinished)
380 {
381 d->status = statusString + QStringLiteral(" Complete");
218 Q_EMIT statusChanged();382 Q_EMIT statusChanged();
219383
220 d->backupBusy = false;384 d->backupBusy = false;
221 Q_EMIT backupBusyChanged();385 Q_EMIT backupBusyChanged();
386 }
222387
223 // Stop state timer388 if (d->checkAllTasksFinished(states))
224 if (d->stateTimer.isActive())389 {
225 {390 Q_EMIT(finished());
226 d->stateTimer.stop();
227 }
228 }391 }
229 }392 }
230}393}
231394
=== added file 'src/client/items.cpp'
--- src/client/items.cpp 1970-01-01 00:00:00 +0000
+++ src/client/items.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,196 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
18 */
19
20#include "client/keeper-items.h"
21
22#include <QtDBus>
23#include <QVariantMap>
24
25namespace keeper
26{
27// json keys
28constexpr const char PROPERTIES_KEY[] = "properties";
29
30// keys
31const QString Item::UUID_KEY = QStringLiteral("uuid");
32const QString Item::TYPE_KEY = QStringLiteral("type");
33const QString Item::SUBTYPE_KEY = QStringLiteral("subtype");
34const QString Item::NAME_KEY = QStringLiteral("name");
35const QString Item::PACKAGE_KEY = QStringLiteral("package");
36const QString Item::TITLE_KEY = QStringLiteral("title");
37const QString Item::VERSION_KEY = QStringLiteral("version");
38const QString Item::FILE_NAME_KEY = QStringLiteral("file-name");
39const QString Item::DIR_NAME_KEY = QStringLiteral("dir-name");
40const QString Item::DISPLAY_NAME_KEY = QStringLiteral("display-name");
41const QString Item::STATUS_KEY = QStringLiteral("action");
42const QString Item::ERROR_KEY = QStringLiteral("error");
43const QString Item::PERCENT_DONE_KEY = QStringLiteral("percent-done");
44const QString Item::SPEED_KEY = QStringLiteral("speed");
45
46
47// values
48const QString Item::FOLDER_VALUE = QStringLiteral("folder");
49const QString Item::SYSTEM_DATA_VALUE = QStringLiteral("system-data");
50const QString Item::APPLICATION_VALUE = QStringLiteral("application");
51
52Item::Item() = default;
53
54Item::Item(QVariantMap const & values)
55 : QVariantMap(values)
56{
57}
58
59Item::~Item() = default;
60
61QVariant Item::get_property_value(QString const & property) const
62{
63 auto iter = this->find(property);
64 if (iter != this->end())
65 {
66 return (*iter);
67 }
68 else
69 {
70 return QVariant();
71 }
72}
73
74void Item::set_property_value(QString const& property, QVariant const& value)
75{
76 this->insert(property, value);
77}
78
79template<typename T> T Item::get_property(QString const & property, bool * valid) const
80{
81 auto it = this->find(property);
82
83 if (it == this->end())
84 {
85 if (valid != nullptr)
86 *valid = false;
87
88 return T{};
89 }
90
91 if (valid != nullptr)
92 *valid = true;
93
94 return it->value<T>();
95}
96
97bool Item::is_valid()const
98{
99 // check for required properties
100 for (auto& property : {TYPE_KEY, DISPLAY_NAME_KEY})
101 if (!this->has_property(property))
102 return false;
103
104 return true;
105}
106
107bool Item::has_property(QString const & property) const
108{
109 return this->contains(property);
110}
111
112QString Item::get_uuid(bool *valid) const
113{
114 return get_property<QString>(UUID_KEY, valid);
115}
116
117QString Item::get_type(bool *valid) const
118{
119 return get_property<QString>(TYPE_KEY, valid);
120}
121
122QString Item::get_display_name(bool *valid) const
123{
124 return get_property<QString>(DISPLAY_NAME_KEY, valid);
125}
126
127QString Item::get_dir_name(bool *valid) const
128{
129 return get_property<QString>(DIR_NAME_KEY, valid);
130}
131
132QString Item::get_status(bool *valid) const
133{
134 return get_property<QString>(STATUS_KEY, valid);
135}
136
137double Item::get_percent_done(bool *valid) const
138{
139 return get_property<double>(PERCENT_DONE_KEY, valid);
140}
141
142keeper::Error Item::get_error(bool *valid) const
143{
144 auto it = this->find(ERROR_KEY);
145
146 // if no error was sent, things must be OK
147 if (it == this->end())
148 {
149 return keeper::Error::OK;
150 }
151
152 return keeper::convert_from_dbus_variant(*it, valid);
153}
154
155QString Item::get_file_name(bool *valid) const
156{
157 return get_property<QString>(FILE_NAME_KEY, valid);
158}
159
160void Item::registerMetaType()
161{
162 qRegisterMetaType<Item>("Item");
163
164 qDBusRegisterMetaType<Item>();
165}
166
167/////
168// Items
169/////
170
171
172Items::Items() =default;
173
174Items::~Items() =default;
175
176
177Items::Items(Error error)
178 : error_{error}
179{
180}
181
182QStringList Items::get_uuids() const
183{
184 return this->keys();
185}
186
187void Items::registerMetaType()
188{
189 qRegisterMetaType<Items>("Items");
190
191 qDBusRegisterMetaType<Items>();
192
193 Item::registerMetaType();
194}
195
196} // namespace keeper
0197
=== added file 'src/client/keeper-errors.cpp'
--- src/client/keeper-errors.cpp 1970-01-01 00:00:00 +0000
+++ src/client/keeper-errors.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,74 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 */
19
20#include <client/keeper-errors.h>
21
22#include <QDebug>
23
24QDBusArgument &operator<<(QDBusArgument &argument, keeper::Error value)
25{
26 argument.beginStructure();
27 argument << static_cast<int>(value);
28 argument.endStructure();
29 return argument;
30}
31
32const QDBusArgument &operator>>(const QDBusArgument &argument, keeper::Error &val)
33{
34 int int_val;
35 argument.beginStructure();
36 argument >> int_val;
37 val = static_cast<keeper::Error>(int_val);
38 argument.endStructure();
39 return argument;
40}
41
42namespace keeper
43{
44Error convert_from_dbus_variant(const QVariant & value, bool *conversion_ok)
45{
46 if (value.typeName() != QStringLiteral("QDBusArgument"))
47 {
48 qWarning() << Q_FUNC_INFO
49 << " Error converting dbus QVariant to Error, expected type is [ QDBusArgument ] and current type is: ["
50 << value.typeName() << "]";
51 if (conversion_ok)
52 *conversion_ok = false;
53 return Error(keeper::Error::UNKNOWN);
54 }
55 auto dbus_arg = value.value<QDBusArgument>();
56
57 if (dbus_arg.currentSignature() != "(i)")
58 {
59 qWarning() << Q_FUNC_INFO
60 << " Error converting dbus QVariant to Error, expected signature is \"(i)\" and current signature is: \""
61 << dbus_arg.currentSignature() << "\"";
62 if (conversion_ok)
63 *conversion_ok = false;
64 return Error(keeper::Error::UNKNOWN);
65 }
66 Error ret;
67 dbus_arg >> ret;
68
69 if (conversion_ok)
70 *conversion_ok = true;
71
72 return ret;
73}
74}
075
=== modified file 'src/client/qml-plugin/CMakeLists.txt'
--- src/client/qml-plugin/CMakeLists.txt 2016-08-26 09:30:11 +0000
+++ src/client/qml-plugin/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -6,7 +6,7 @@
6add_definitions(-DKEEPER_MAJOR=${KEEPER_MAJOR})6add_definitions(-DKEEPER_MAJOR=${KEEPER_MAJOR})
7add_definitions(-DKEEPER_MINOR=${KEEPER_MINOR})7add_definitions(-DKEEPER_MINOR=${KEEPER_MINOR})
88
9include(QmlPlugins)9find_package(QmlPlugins)
1010
11find_package(Qt5Quick REQUIRED)11find_package(Qt5Quick REQUIRED)
1212
1313
=== modified file 'src/helper/CMakeLists.txt'
--- src/helper/CMakeLists.txt 2016-09-06 01:31:59 +0000
+++ src/helper/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -18,6 +18,21 @@
18 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}18 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}
19)19)
2020
21set(
22 FOLDER_RESTORE
23 folder-restore.sh
24)
25configure_file(
26 ${CMAKE_CURRENT_SOURCE_DIR}/${FOLDER_RESTORE}.in
27 ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE}
28)
29
30install(
31 PROGRAMS
32 ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE}
33 DESTINATION
34 ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}
35)
2136
22#37#
23# the library38# the library
@@ -30,7 +45,7 @@
3045
31include(FindPkgConfig)46include(FindPkgConfig)
32pkg_check_modules(BACKUP_HELPER_DEPENDENCIES REQUIRED47pkg_check_modules(BACKUP_HELPER_DEPENDENCIES REQUIRED
33 ubuntu-app-launch-248 ubuntu-app-launch-3
34 properties-cpp49 properties-cpp
35)50)
3651
@@ -48,10 +63,12 @@
48 ${HELPER_LIB}63 ${HELPER_LIB}
49 STATIC64 STATIC
50 backup-helper.cpp65 backup-helper.cpp
66 restore-helper.cpp
51 data-dir-registry.cpp67 data-dir-registry.cpp
52 helper.cpp68 helper.cpp
53 metadata.cpp69 metadata.cpp
54 ${CMAKE_SOURCE_DIR}/include/helper/backup-helper.h70 ${CMAKE_SOURCE_DIR}/include/helper/backup-helper.h
71 ${CMAKE_SOURCE_DIR}/include/helper/restore-helper.h
55 ${CMAKE_SOURCE_DIR}/include/helper/data-dir-registry.h72 ${CMAKE_SOURCE_DIR}/include/helper/data-dir-registry.h
56 ${CMAKE_SOURCE_DIR}/include/helper/helper.h73 ${CMAKE_SOURCE_DIR}/include/helper/helper.h
57 ${CMAKE_SOURCE_DIR}/include/helper/registry.h74 ${CMAKE_SOURCE_DIR}/include/helper/registry.h
5875
=== modified file 'src/helper/backup-helper.cpp'
--- src/helper/backup-helper.cpp 2016-09-12 15:13:33 +0000
+++ src/helper/backup-helper.cpp 2017-02-27 19:05:17 +0000
@@ -62,8 +62,8 @@
62 int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);62 int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
63 if (rc == -1)63 if (rc == -1)
64 {64 {
65 // TODO throw exception.65 qWarning() << QStringLiteral("Error creating socket to communicate with helper");;
66 qWarning() << "BackupHelperPrivate: error creating socket pair to communicate with helper ";66 Q_EMIT(q_ptr->error(keeper::Error::HELPER_SOCKET));
67 return;67 return;
68 }68 }
6969
@@ -139,9 +139,14 @@
139 &Uploader::commit_finished,139 &Uploader::commit_finished,
140 std::function<void(bool)>{[this](bool success){140 std::function<void(bool)>{[this](bool success){
141 qDebug() << "Commit finished";141 qDebug() << "Commit finished";
142 uploader_.reset();
143 if (!success)142 if (!success)
143 {
144 write_error_ = true;144 write_error_ = true;
145 Q_EMIT(q_ptr->error(keeper::Error::COMMITTING_DATA));
146 }
147 else
148 uploader_committed_file_name_ = uploader_->file_name();
149 uploader_.reset();
145 check_for_done();150 check_for_done();
146 }}151 }}
147 );152 );
@@ -162,12 +167,18 @@
162 check_for_done();167 check_for_done();
163 }168 }
164169
170 QString get_uploader_committed_file_name() const
171 {
172 return uploader_committed_file_name_;
173 }
174
165private:175private:
166176
167 void on_inactivity_detected()177 void on_inactivity_detected()
168 {178 {
169 stop_inactivity_timer();179 stop_inactivity_timer();
170 qWarning() << "Inactivity detected in the helper...stopping it";180 qWarning() << "Inactivity detected in the helper...stopping it";
181 Q_EMIT(q_ptr->error(keeper::Error::HELPER_INACTIVITY_DETECTED));
171 stop();182 stop();
172 }183 }
173184
@@ -180,7 +191,6 @@
180 {191 {
181 n_uploaded_ += n;192 n_uploaded_ += n;
182 q_ptr->record_data_transferred(n);193 q_ptr->record_data_transferred(n);
183 qDebug("n_read %zu n_uploaded %zu (newly uploaded %zu)", size_t(n_read_), size_t(n_uploaded_), size_t(n));
184 process_more();194 process_more();
185 check_for_done();195 check_for_done();
186 }196 }
@@ -201,10 +211,10 @@
201 if (n > 0) {211 if (n > 0) {
202 n_read_ += n;212 n_read_ += n;
203 upload_buffer_.append(readbuf, int(n));213 upload_buffer_.append(readbuf, int(n));
204 qDebug("upload_buffer_.size() is %zu after reading %zu from helper", size_t(upload_buffer_.size()), size_t(n));
205 }214 }
206 else if (n < 0) {215 else if (n < 0) {
207 read_error_ = true;216 read_error_ = true;
217 Q_EMIT(q_ptr->error(keeper::Error::HELPER_READ));
208 stop();218 stop();
209 return;219 return;
210 }220 }
@@ -214,13 +224,13 @@
214 const auto n = socket->write(upload_buffer_);224 const auto n = socket->write(upload_buffer_);
215 if (n > 0) {225 if (n > 0) {
216 upload_buffer_.remove(0, int(n));226 upload_buffer_.remove(0, int(n));
217 qDebug("upload_buffer_.size() is %zu after writing %zu to cloud", size_t(upload_buffer_.size()), size_t(n));
218 continue;227 continue;
219 }228 }
220 else {229 else {
221 if (n < 0) {230 if (n < 0) {
222 write_error_ = true;231 write_error_ = true;
223 qWarning() << "Write error:" << socket->errorString();232 qWarning() << "Write error:" << socket->errorString();
233 Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE));
224 stop();234 stop();
225 }235 }
226 break;236 break;
@@ -251,6 +261,10 @@
251 {261 {
252 if (!q_ptr->is_helper_running())262 if (!q_ptr->is_helper_running())
253 {263 {
264 if (n_uploaded_ > q_ptr->expected_size())
265 {
266 Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE));
267 }
254 q_ptr->set_state(Helper::State::FAILED);268 q_ptr->set_state(Helper::State::FAILED);
255 }269 }
256 }270 }
@@ -289,6 +303,7 @@
289 bool write_error_ = false;303 bool write_error_ = false;
290 bool cancelled_ = false;304 bool cancelled_ = false;
291 ConnectionHelper connections_;305 ConnectionHelper connections_;
306 QString uploader_committed_file_name_;
292};307};
293308
294/***309/***
@@ -352,14 +367,21 @@
352{367{
353 Q_D(BackupHelper);368 Q_D(BackupHelper);
354369
355 qDebug() << Q_FUNC_INFO;370 Helper::set_state(state);
356 d->on_state_changed(state);371 d->on_state_changed(state);
357 Helper::set_state(state);
358}372}
359373
360void BackupHelper::on_helper_finished()374void BackupHelper::on_helper_finished()
361{375{
362 Q_D(BackupHelper);376 Q_D(BackupHelper);
377
363 Helper::on_helper_finished();378 Helper::on_helper_finished();
364 d->on_helper_finished();379 d->on_helper_finished();
365}380}
381
382QString BackupHelper::get_uploader_committed_file_name() const
383{
384 Q_D(const BackupHelper);
385
386 return d->get_uploader_committed_file_name();
387}
366388
=== modified file 'src/helper/data-dir-registry.cpp'
--- src/helper/data-dir-registry.cpp 2016-08-10 02:29:17 +0000
+++ src/helper/data-dir-registry.cpp 2017-02-27 19:05:17 +0000
@@ -49,15 +49,27 @@
4949
50 QStringList get_backup_helper_urls(Metadata const& task)50 QStringList get_backup_helper_urls(Metadata const& task)
51 {51 {
52 return get_helper_urls(task, "backup");
53 }
54
55 QStringList get_restore_helper_urls(Metadata const& task)
56 {
57 return get_helper_urls(task, "restore");
58 }
59
60private:
61
62 QStringList get_helper_urls(Metadata const& task, QString const & prop)
63 {
52 QStringList ret;64 QStringList ret;
5365
54 QString type;66 auto type = task.get_type();
55 if (task.get_property(Metadata::TYPE_KEY, type))67 if (!type.isEmpty())
56 {68 {
57 auto it = registry_.find(std::make_pair(type,QStringLiteral("backup")));69 auto it = registry_.find(std::make_pair(type,prop));
58 if (it == registry_.end())70 if (it == registry_.end())
59 {71 {
60 qCritical() << "can't get backup helper urls for unhandled type" << type;72 qCritical() << "can't get " << prop << " helper urls for unhandled type" << type;
61 }73 }
62 else74 else
63 {75 {
@@ -73,30 +85,28 @@
73 return ret;85 return ret;
74 }86 }
7587
76private:
77
78 // replace "${key}" with task.get_property("key")88 // replace "${key}" with task.get_property("key")
79 QStringList perform_url_substitution(Metadata const& task, QStringList const& urls_in)89 QStringList perform_url_substitution(Metadata const& task, QStringList const& urls_in)
80 {90 {
81 std::array<QString,6> keys = {91 std::array<QString,6> keys = {
82 Metadata::TYPE_KEY,92 keeper::Item::TYPE_KEY,
83 Metadata::SUBTYPE_KEY,93 keeper::Item::SUBTYPE_KEY,
84 Metadata::NAME_KEY,94 keeper::Item::NAME_KEY,
85 Metadata::PACKAGE_KEY,95 keeper::Item::PACKAGE_KEY,
86 Metadata::TITLE_KEY,96 keeper::Item::TITLE_KEY,
87 Metadata::VERSION_KEY97 keeper::Item::VERSION_KEY
88 };98 };
8999
90 QStringList urls {urls_in};100 QStringList urls {urls_in};
91101
92 for (auto const& key : keys)102 for (auto const& key : keys)
93 {103 {
94 QString after;104 QVariant after = task.get_property_value(key);
95 if (task.get_property(key, after))105 if (after.isValid())
96 {106 {
97 QString before = QStringLiteral("${%1}").arg(key);107 QString before = QStringLiteral("${%1}").arg(key);
98 for (auto& url : urls)108 for (auto& url : urls)
99 url.replace(before, after);109 url.replace(before, after.toString());
100 }110 }
101 }111 }
102112
@@ -139,6 +149,10 @@
139 * "backup-urls": [149 * "backup-urls": [
140 * "/path/to/helper.sh",150 * "/path/to/helper.sh",
141 * "${subtype}"151 * "${subtype}"
152 * ],
153 * "restore-urls": [
154 * "/path/to/helper.sh",
155 * "${subtype}"
142 * ]156 * ]
143 * }157 * }
144 * }158 * }
@@ -156,25 +170,37 @@
156 if (error.error != QJsonParseError::NoError)170 if (error.error != QJsonParseError::NoError)
157 qCritical() << path << "parse error at offset" << error.offset << error.errorString();171 qCritical() << path << "parse error at offset" << error.offset << error.errorString();
158172
159 auto obj = doc.object();173 const auto obj = doc.object();
160 for (auto tit=obj.begin(), tend=obj.end(); tit!=tend; ++tit)174 for (auto tit=obj.begin(), tend=obj.end(); tit!=tend; ++tit)
161 {175 {
162 auto const type = tit.key();176 auto const type = tit.key();
163 auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))];
164
165 auto const props = tit.value().toObject();177 auto const props = tit.value().toObject();
166 auto const urls_jsonval = props["backup-urls"];178
179 auto const &urls_jsonval = props["backup-urls"];
167 if (urls_jsonval.isArray())180 if (urls_jsonval.isArray())
168 {181 {
182 auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))];
169 for (auto url_jsonval : urls_jsonval.toArray())183 for (auto url_jsonval : urls_jsonval.toArray())
170 {184 {
171 info.urls.push_back(url_jsonval.toString());185 info.urls.push_back(url_jsonval.toString());
172 }186 }
187 qDebug() << "loaded" << type << "backup urls from" << path;
188 for(auto const& url : info.urls)
189 qDebug() << "\turl:" << url;
173 }190 }
174191
175 qDebug() << "loaded" << type << "backup urls from" << path;192 auto const &urls_jsonval_restore = props["restore-urls"];
176 for(auto const& url : info.urls)193 if (urls_jsonval_restore.isArray())
177 qDebug() << "\turl:" << url;194 {
195 auto& info = registry_[std::make_pair(type,QStringLiteral("restore"))];
196 for (auto url_jsonval : urls_jsonval_restore.toArray())
197 {
198 info.urls.push_back(url_jsonval.toString());
199 }
200 qDebug() << "loaded" << type << "restore urls from" << path;
201 for(auto const& url : info.urls)
202 qDebug() << "\turl:" << url;
203 }
178 }204 }
179 }205 }
180 }206 }
@@ -198,3 +224,9 @@
198{224{
199 return impl_->get_backup_helper_urls(task);225 return impl_->get_backup_helper_urls(task);
200}226}
227
228QStringList
229DataDirRegistry::get_restore_helper_urls(Metadata const& task)
230{
231 return impl_->get_restore_helper_urls(task);
232}
201233
=== modified file 'src/helper/folder-backup.sh.in'
--- src/helper/folder-backup.sh.in 2016-08-10 05:01:08 +0000
+++ src/helper/folder-backup.sh.in 2017-02-27 19:05:17 +0000
@@ -20,4 +20,4 @@
20#20#
2121
22echo $PWD22echo $PWD
23find ./ -type f -print0 | @CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-tar-create -a /com/canonical/keeper/helper23find ./ -type f -print0 | @CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-tar -a /com/canonical/keeper/helper
2424
=== added file 'src/helper/folder-restore.sh.in'
--- src/helper/folder-restore.sh.in 1970-01-01 00:00:00 +0000
+++ src/helper/folder-restore.sh.in 2017-02-27 19:05:17 +0000
@@ -0,0 +1,23 @@
1#!/bin/bash
2#
3# Copyright (C) 2016 Canonical, Ltd.
4#
5# This program is free software: you can redistribute it and/or modify it
6# under the terms of the GNU General Public License version 3, as published
7# by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranties of
11# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12# PURPOSE. See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program. If not, see <http://www.gnu.org/licenses/>.
16#
17# Authors:
18# Xavi Garcia <xavi.garcia.mena@canonical.com>
19# Charles Kerr <charles.kerr@canonical.com>
20#
21
22echo $PWD
23@CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-untar -a /com/canonical/keeper/helper
024
=== modified file 'src/helper/helper.cpp'
--- src/helper/helper.cpp 2016-09-12 15:13:33 +0000
+++ src/helper/helper.cpp 2017-02-27 19:05:17 +0000
@@ -75,7 +75,6 @@
75 uint32_t75 uint32_t
76 speed_bytes_per_second(uint64_t now, unsigned int interval_msec=HISTORY_MSEC) const76 speed_bytes_per_second(uint64_t now, unsigned int interval_msec=HISTORY_MSEC) const
77 {77 {
78qDebug() << "now" << now << "cache_time" << cache_time << "interval_msec" << interval_msec;
79 if (cache_time != now)78 if (cache_time != now)
80 {79 {
81 auto i = newest;80 auto i = newest;
@@ -88,22 +87,18 @@
88 break;87 break;
8988
90 bytes += transfers[i].size;89 bytes += transfers[i].size;
91qDebug() << "i" << i << "transfers[i] .date" << transfers[i].date << ".size" << transfers[i].size << "sum" << bytes;
9290
93 if (--i == -1) {91 if (--i == -1) {
94 i = HISTORY_SIZE - 1; // circular history92 i = HISTORY_SIZE - 1; // circular history
95qDebug() << "circular history";
96 }93 }
9794
98 if (i == newest) {95 if (i == newest) {
99qDebug() << "i" << i << "transfers[i] .date" << transfers[i].date << ".size" << transfers[i].size << "sum" << bytes;
100 break; // we've come all the way around96 break; // we've come all the way around
101 }97 }
102 }98 }
10399
104 cache_val = uint32_t((bytes * 1000u) / interval_msec);100 cache_val = uint32_t((bytes * 1000u) / interval_msec);
105 cache_time = now;101 cache_time = now;
106qDebug() << "cache_val" << cache_val << "cache_time" << cache_time;
107 }102 }
108103
109 return cache_val;104 return cache_val;
@@ -170,7 +165,10 @@
170 {165 {
171 qDebug() << "changing state of helper" << static_cast<void*>(this) << "from" << q_ptr->to_string(state_) << "to" << q_ptr->to_string(state);166 qDebug() << "changing state of helper" << static_cast<void*>(this) << "from" << q_ptr->to_string(state_) << "to" << q_ptr->to_string(state);
172 state_ = state;167 state_ = state;
173 q_ptr->state_changed(state);168 QMetaObject::invokeMethod(q_ptr,
169 "state_changed",
170 Qt::QueuedConnection,
171 Q_ARG(Helper::State, state));
174 }172 }
175 }173 }
176174
@@ -337,7 +335,6 @@
337335
338 if (is_noteworthy)336 if (is_noteworthy)
339 {337 {
340 qDebug() << "emitting percent-done-changed" << percent_done_;
341 Q_EMIT(q_ptr->percent_done_changed(percent_done_));338 Q_EMIT(q_ptr->percent_done_changed(percent_done_));
342 last_notified_percent_done_ = percent_done_;339 last_notified_percent_done_ = percent_done_;
343 }340 }
@@ -356,7 +353,8 @@
356353
357 void on_max_time_waiting_for_ual_started()354 void on_max_time_waiting_for_ual_started()
358 {355 {
359 qDebug() << "Max time reached waiting for UAL to start";356 qWarning() << "Maximum time reached waiting for the helper to start.";
357 Q_EMIT(q_ptr->error(keeper::Error::HELPER_START_TIMEOUT));
360 q_ptr->set_state(Helper::State::FAILED);358 q_ptr->set_state(Helper::State::FAILED);
361 stop_wait_for_ual_timer();359 stop_wait_for_ual_timer();
362 }360 }
363361
=== modified file 'src/helper/metadata.cpp'
--- src/helper/metadata.cpp 2016-09-06 18:51:30 +0000
+++ src/helper/metadata.cpp 2017-02-27 19:05:17 +0000
@@ -19,63 +19,58 @@
1919
20#include "helper/metadata.h"20#include "helper/metadata.h"
2121
22///22#include <QDebug>
23///23#include <QJsonArray>
2424#include <QJsonDocument>
25// Metadata keys25
26const QString Metadata::TYPE_KEY = QStringLiteral("type");26///
27const QString Metadata::SUBTYPE_KEY = QStringLiteral("subtype");27///
28const QString Metadata::NAME_KEY = QStringLiteral("name");28
29const QString Metadata::PACKAGE_KEY = QStringLiteral("package");29// JSON Keys
30const QString Metadata::TITLE_KEY = QStringLiteral("title");30namespace
31const QString Metadata::VERSION_KEY = QStringLiteral("version");31{
3232 constexpr const char PROPERTIES_KEY[] = "properties";
33// Metadata values33}
34const QString Metadata::FOLDER_VALUE = QStringLiteral("folder");
35const QString Metadata::SYSTEM_DATA_VALUE = QStringLiteral("system-data");
36const QString Metadata::APPLICATION_VALUE = QStringLiteral("application");
3734
38///35///
39///36///
4037
41Metadata::Metadata()38Metadata::Metadata()
42 : uuid_()39 : keeper::Item()
43 , display_name_()40{
44 , properties_()41}
45{42
43Metadata::Metadata(QJsonObject const & json)
44 : keeper::Item()
45{
46 auto properties = json[PROPERTIES_KEY].toObject();
47 for (auto const & key : properties.keys())
48 {
49 this->insert(key, properties[key].toString());
50 }
46}51}
4752
48Metadata::Metadata(QString const& uuid, QString const& display_name)53Metadata::Metadata(QString const& uuid, QString const& display_name)
49 : uuid_(uuid)54 : keeper::Item()
50 , display_name_(display_name)55{
51 , properties_()56 this->insert(keeper::Item::UUID_KEY, uuid);
52{57 this->insert(keeper::Item::DISPLAY_NAME_KEY, display_name);
53}58}
5459
55bool60QJsonObject
56Metadata::get_property(QString const& property_name, QString& setme) const61Metadata::json() const
57{62{
58 auto it = properties_.constFind(property_name);63 QJsonArray json_properties;
59 const bool found = it != properties_.end();64 QJsonObject properties_obj;
6065 for (auto iter = this->begin(); iter != this->end(); ++iter)
61 if (found)66 {
62 setme = it.value();67 properties_obj[iter.key()] = (*iter).toString();
6368 }
64 return found;69
65}70 QJsonObject ret
6671 {
67void72 { PROPERTIES_KEY, properties_obj }
68Metadata::set_property(QString const& property_name, QString const& value)73 };
69{74
70 properties_.insert(property_name, value);
71}
72
73QMap<QString,QString>
74Metadata::get_public_properties() const
75{
76 // they're all public so far...
77 auto ret = properties_;
78 ret.insert(QStringLiteral("uuid"), uuid_);
79 ret.insert(QStringLiteral("display-name"), display_name_);
80 return ret;75 return ret;
81}76}
8277
=== added file 'src/helper/restore-helper.cpp'
--- src/helper/restore-helper.cpp 1970-01-01 00:00:00 +0000
+++ src/helper/restore-helper.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,377 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 * Charles Kerr <charles.kerr@canonical.com>
19 */
20
21#include "util/connection-helper.h"
22#include "helper/restore-helper.h"
23#include "service/app-const.h" // HELPER_TYPE
24
25#include <QByteArray>
26#include <QDebug>
27#include <QLocalSocket>
28#include <QMap>
29#include <QObject>
30#include <QString>
31#include <QTimer>
32#include <QVector>
33
34#include <fcntl.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37
38#include <functional> // std::bind()
39
40
41class RestoreHelperPrivate
42{
43public:
44
45 explicit RestoreHelperPrivate(
46 RestoreHelper* backup_helper
47 )
48 : q_ptr(backup_helper)
49 {
50 // listen for inactivity from storage framework
51 QObject::connect(&timer_, &QTimer::timeout,
52 std::bind(&RestoreHelperPrivate::on_inactivity_detected, this)
53 );
54
55 // fire up the sockets
56 int fds[2];
57 int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
58 if (rc == -1)
59 {
60 qWarning() << QStringLiteral("Error creating socket to communicate with helper");;
61 Q_EMIT(q_ptr->error(keeper::Error::HELPER_SOCKET));
62 return;
63 }
64
65 // helper socket is for the client.
66 // We don't use a QLocalSocket here as it buffers data and it makes the helper miss packets.
67 helper_socket_ = fds[1];
68
69 write_socket_.setSocketDescriptor(fds[0], QLocalSocket::ConnectedState, QIODevice::WriteOnly);
70 }
71
72 ~RestoreHelperPrivate() = default;
73
74 Q_DISABLE_COPY(RestoreHelperPrivate)
75
76 void start(QStringList const& urls)
77 {
78 q_ptr->Helper::start(urls);
79 reset_inactivity_timer();
80 }
81
82 void set_downloader(std::shared_ptr<Downloader> const& downloader)
83 {
84 n_read_ = 0;
85 n_uploaded_ = 0;
86 read_error_ = false;
87 write_error_ = false;
88 cancelled_ = false;
89
90 q_ptr->set_expected_size(downloader->file_size());
91 downloader_ = downloader;
92
93 connections_.remember(QObject::connect(
94 &write_socket_, &QLocalSocket::bytesWritten,
95 std::bind(&RestoreHelperPrivate::on_data_uploaded, this, std::placeholders::_1)
96 ));
97
98 // listen for data ready to read
99 QObject::connect(downloader_->socket().get(), &QLocalSocket::readyRead,
100 std::bind(&RestoreHelperPrivate::on_ready_read, this)
101 );
102
103 // TODO investigate why UAL takes so long to call the helper started callback
104 // At this point we are sure that the helper started, as it is the helper
105 // the ones that asks for a downloader socket.
106 q_ptr->Helper::on_helper_started();
107
108 // maybe there's data already to be read
109 process_more();
110
111 reset_inactivity_timer();
112 }
113
114 void stop()
115 {
116 write_socket_.disconnectFromServer();
117 cancelled_ = true;
118 q_ptr->Helper::stop();
119 }
120
121 int get_helper_socket() const
122 {
123 return helper_socket_;
124 }
125
126 QString to_string(Helper::State state) const
127 {
128 return state == Helper::State::STARTED
129 ? QStringLiteral("restoring")
130 : q_ptr->Helper::to_string(state);
131 }
132
133 void on_state_changed(Helper::State state)
134 {
135 switch (state)
136 {
137 case Helper::State::CANCELLED:
138 case Helper::State::FAILED:
139 qDebug() << "cancelled/failed, calling downloader_.reset()";
140 downloader_.reset();
141 break;
142
143 case Helper::State::DATA_COMPLETE: {
144 qDebug() << "Restore helper finished, calling downloader_.finish()";
145 write_socket_.disconnectFromServer();
146 downloader_->finish();
147 downloader_.reset();
148 break;
149 }
150
151 //case Helper::State::NOT_STARTED:
152 //case Helper::State::STARTED:
153 default:
154 break;
155 }
156 }
157
158 void on_helper_finished()
159 {
160 stop_inactivity_timer();
161 check_for_done();
162 }
163
164private:
165
166 void on_inactivity_detected()
167 {
168 stop_inactivity_timer();
169 qWarning() << "Inactivity detected in the helper...stopping it";
170 Q_EMIT(q_ptr->error(keeper::Error::HELPER_INACTIVITY_DETECTED));
171 stop();
172 }
173
174 void on_ready_read()
175 {
176 process_more();
177 }
178
179 void on_data_uploaded(qint64 n)
180 {
181 n_uploaded_ += n;
182 q_ptr->record_data_transferred(n);
183 process_more();
184 check_for_done();
185 }
186
187 void process_more()
188 {
189 if (!downloader_)
190 return;
191
192 char readbuf[UPLOAD_BUFFER_MAX_];
193 auto socket = downloader_->socket();
194 while(socket->bytesAvailable() || upload_buffer_.size())
195 {
196 if (socket->bytesAvailable())
197 {
198 // try to fill the upload buf
199 int max_bytes = UPLOAD_BUFFER_MAX_ - upload_buffer_.size();
200 if (max_bytes > 0) {
201 const auto n = socket->read(readbuf, max_bytes);
202 if (n > 0) {
203 n_read_ += n;
204 upload_buffer_.append(readbuf, int(n));
205 }
206 else if (n < 0) {
207 read_error_ = true;
208 qDebug() << "Read error in restore helper: " << socket->errorString();
209 Q_EMIT(q_ptr->error(keeper::Error::HELPER_READ));
210 stop();
211 check_for_done();
212 return;
213 }
214 }
215 }
216
217 if (upload_buffer_.size())
218 {
219 // try to empty the upload buf
220 const auto n = write_socket_.write(upload_buffer_);
221 if (n > 0) {
222 upload_buffer_.remove(0, int(n));
223 continue;
224 }
225 else {
226 if (n < 0) {
227 write_error_ = true;
228 qWarning() << "Write error:" << write_socket_.errorString();
229 Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE));
230 stop();
231 check_for_done();
232 }
233 break;
234 }
235 }
236 }
237
238 reset_inactivity_timer();
239 }
240
241 void reset_inactivity_timer()
242 {
243 static constexpr int MAX_TIME_WAITING_FOR_DATA {RestoreHelper::MAX_INACTIVITY_TIME};
244 timer_.start(MAX_TIME_WAITING_FOR_DATA);
245 }
246
247 void stop_inactivity_timer()
248 {
249 timer_.stop();
250 }
251
252 void check_for_done()
253 {
254 if (cancelled_)
255 {
256 q_ptr->set_state(Helper::State::CANCELLED);
257 }
258 else if (read_error_ || write_error_ || n_uploaded_ > q_ptr->expected_size())
259 {
260 if (!q_ptr->is_helper_running())
261 {
262 if (n_uploaded_ > q_ptr->expected_size())
263 {
264 Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE));
265 }
266 q_ptr->set_state(Helper::State::FAILED);
267 }
268 }
269 else if (n_uploaded_ == q_ptr->expected_size())
270 {
271 if (downloader_)
272 {
273 if (q_ptr->is_helper_running())
274 {
275 // only in the case that the helper process finished we move to the next state
276 // this is to prevent to start the next task too early
277 q_ptr->set_state(Helper::State::DATA_COMPLETE);
278 stop_inactivity_timer();
279 }
280 }
281 else
282 q_ptr->set_state(Helper::State::COMPLETE);
283 }
284 }
285
286 /***
287 ****
288 ***/
289
290 static constexpr int UPLOAD_BUFFER_MAX_ {1024*16};
291
292 RestoreHelper * const q_ptr;
293 QTimer timer_;
294 std::shared_ptr<Downloader> downloader_;
295 int helper_socket_ = -1;
296 QLocalSocket write_socket_;
297 QByteArray upload_buffer_;
298 qint64 n_read_ = 0;
299 qint64 n_uploaded_ = 0;
300 bool read_error_ = false;
301 bool write_error_ = false;
302 bool cancelled_ = false;
303 ConnectionHelper connections_;
304};
305
306/***
307****
308***/
309
310RestoreHelper::RestoreHelper(
311 QString const & appid,
312 clock_func const & clock,
313 QObject * parent
314)
315 : Helper(appid, clock, parent)
316 , d_ptr(new RestoreHelperPrivate(this))
317{
318}
319
320RestoreHelper::~RestoreHelper() =default;
321
322void
323RestoreHelper::start(QStringList const& url)
324{
325 Q_D(RestoreHelper);
326
327 d->start(url);
328}
329
330void
331RestoreHelper::stop()
332{
333 Q_D(RestoreHelper);
334
335 d->stop();
336}
337
338void
339RestoreHelper::set_downloader(std::shared_ptr<Downloader> const& downloader)
340{
341 Q_D(RestoreHelper);
342
343 d->set_downloader(downloader);
344}
345
346int
347RestoreHelper::get_helper_socket() const
348{
349 Q_D(const RestoreHelper);
350
351 return d->get_helper_socket();
352}
353
354QString
355RestoreHelper::to_string(Helper::State state) const
356{
357 Q_D(const RestoreHelper);
358
359 return d->to_string(state);
360}
361
362void
363RestoreHelper::set_state(Helper::State state)
364{
365 Q_D(RestoreHelper);
366
367 Helper::set_state(state);
368 d->on_state_changed(state);
369}
370
371void RestoreHelper::on_helper_finished()
372{
373 Q_D(RestoreHelper);
374
375 Helper::on_helper_finished();
376 d->on_helper_finished();
377}
0378
=== modified file 'src/qdbus-stubs/CMakeLists.txt'
--- src/qdbus-stubs/CMakeLists.txt 2016-08-10 05:41:26 +0000
+++ src/qdbus-stubs/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -67,6 +67,7 @@
67 ${user_xml}67 ${user_xml}
68 PROPERTIES68 PROPERTIES
69 CLASSNAME DBusInterfaceKeeperUser69 CLASSNAME DBusInterfaceKeeperUser
70 INCLUDE "client/keeper-items.h"
70)71)
7172
72qt5_add_dbus_interface(73qt5_add_dbus_interface(
@@ -84,6 +85,23 @@
84 KeeperUserAdaptor85 KeeperUserAdaptor
85)86)
8687
88set(
89 properties_xml
90 "org.freedesktop.DBus.Properties.xml"
91)
92
93set_source_files_properties(
94 "${properties_xml}"
95 PROPERTIES
96 NO_NAMESPACE YES
97 CLASSNAME DBusPropertiesInterface
98)
99
100qt5_add_dbus_interface(
101 interface_files
102 ${properties_xml}
103 DBusPropertiesInterface
104)
87#105#
88#106#
89107
@@ -101,5 +119,5 @@
101119
102target_link_libraries(120target_link_libraries(
103 ${STUBS_LIB}121 ${STUBS_LIB}
104 backup-helper122 keeper-errors-lib
105)123)
106124
=== modified file 'src/qdbus-stubs/com.canonical.keeper.User.xml'
--- src/qdbus-stubs/com.canonical.keeper.User.xml 2016-07-28 19:44:52 +0000
+++ src/qdbus-stubs/com.canonical.keeper.User.xml 2017-02-27 19:05:17 +0000
@@ -5,7 +5,7 @@
5 <interface name="com.canonical.keeper.User">5 <interface name="com.canonical.keeper.User">
66
7 <method name="GetBackupChoices">7 <method name="GetBackupChoices">
8 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantDictMap"/>8 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="keeper::Items"/>
9 <arg direction="out" name="backups" type="a{sa{sv}}">9 <arg direction="out" name="backups" type="a{sa{sv}}">
10 <doc:doc>10 <doc:doc>
11 <doc:summary>A list of backup possibilities for the user to choose from</doc:summary>11 <doc:summary>A list of backup possibilities for the user to choose from</doc:summary>
@@ -32,10 +32,32 @@
32 </doc:description>32 </doc:description>
33 </doc:doc>33 </doc:doc>
34 </arg>34 </arg>
35 <arg direction="in" name="storage" type="s">
36 <doc:doc>
37 <doc:summary>The storage identifier</doc:summary>
38 <doc:description>
39 <doc:para>Because keeper supports multiple storage providers the user can define
40 which is the storage provider to use.
41 If the passed storage id is an empty string the default storage provider
42 will be used.</doc:para>
43 </doc:description>
44 </doc:doc>
45 </arg>
35 </method>46 </method>
3647
37 <method name="GetRestoreChoices">48 <method name="GetRestoreChoices">
38 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantDictMap"/>49 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="keeper::Items"/>
50 <arg direction="in" name="storage" type="s">
51 <doc:doc>
52 <doc:summary>The storage identifier</doc:summary>
53 <doc:description>
54 <doc:para>Because keeper supports multiple storage providers the user can define
55 which is the storage provider to use.
56 If the passed storage id is an empty string the default storage provider
57 will be used.</doc:para>
58 </doc:description>
59 </doc:doc>
60 </arg>
39 <arg direction="out" name="backups" type="a{sa{sv}}">61 <arg direction="out" name="backups" type="a{sa{sv}}">
40 <doc:doc>62 <doc:doc>
41 <doc:summary>The backups which already exist and can be restored</doc:summary>63 <doc:summary>The backups which already exist and can be restored</doc:summary>
@@ -62,10 +84,21 @@
62 </doc:description>84 </doc:description>
63 </doc:doc>85 </doc:doc>
64 </arg>86 </arg>
87 <arg direction="in" name="storage" type="s">
88 <doc:doc>
89 <doc:summary>The storage identifier</doc:summary>
90 <doc:description>
91 <doc:para>Because keeper supports multiple storage providers the user can define
92 which is the storage provider to use.
93 If the passed storage id is an empty string the default storage provider
94 will be used.</doc:para>
95 </doc:description>
96 </doc:doc>
97 </arg>
65 </method>98 </method>
6699
67 <property name="State" type="a{sa{sv}}" access="read">100 <property name="State" type="a{sa{sv}}" access="read">
68 <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantDictMap"/>101 <annotation name="org.qtproject.QtDBus.QtTypeName" value="keeper::Items"/>
69 <doc:doc>102 <doc:doc>
70 <doc:description>103 <doc:description>
71 <doc:para>Provides state information so the user interface can show104 <doc:para>Provides state information so the user interface can show
@@ -86,6 +119,17 @@
86 </doc:doc>119 </doc:doc>
87 </property>120 </property>
88121
122 <method name="GetStorageAccounts">
123 <arg direction="out" name="accounts" type="as">
124 <doc:doc>
125 <doc:summary>The list of available storage accounts.</doc:summary>
126 <doc:description>
127 <doc:para>An array of the available accounts to choose from to backup/restore</doc:para>
128 </doc:description>
129 </doc:doc>
130 </arg>
131 </method>
132
89 <method name="Cancel">133 <method name="Cancel">
90 <doc:doc>134 <doc:doc>
91 <doc:summary>Cancels the current backup or restore actions.</doc:summary>135 <doc:summary>Cancels the current backup or restore actions.</doc:summary>
92136
=== modified file 'src/qdbus-stubs/dbus-types.h'
--- src/qdbus-stubs/dbus-types.h 2016-07-14 15:31:11 +0000
+++ src/qdbus-stubs/dbus-types.h 2017-02-27 19:05:17 +0000
@@ -22,7 +22,8 @@
22#include <QtCore>22#include <QtCore>
23#include <QString>23#include <QString>
24#include <QVariantMap>24#include <QVariantMap>
25#include <helper/helper.h>25#include <client/keeper-errors.h>
26#include "client/keeper-items.h"
2627
27typedef QMap<QString, QVariantMap> QVariantDictMap;28typedef QMap<QString, QVariantMap> QVariantDictMap;
28Q_DECLARE_METATYPE(QVariantDictMap)29Q_DECLARE_METATYPE(QVariantDictMap)
@@ -36,10 +37,13 @@
36 {37 {
37 qRegisterMetaType<QVariantDictMap>("QVariantDictMap");38 qRegisterMetaType<QVariantDictMap>("QVariantDictMap");
38 qRegisterMetaType<QStringMap>("QStringMap");39 qRegisterMetaType<QStringMap>("QStringMap");
40 qRegisterMetaType<keeper::Error>("keeper::Error");
3941
40 qDBusRegisterMetaType<QVariantDictMap>();42 qDBusRegisterMetaType<QVariantDictMap>();
41 qDBusRegisterMetaType<QStringMap>();43 qDBusRegisterMetaType<QStringMap>();
42 Helper::registerMetaTypes();44 qDBusRegisterMetaType<keeper::Error>();
45
46 keeper::Items::registerMetaType();
43 }47 }
4448
45 constexpr const char KEEPER_SERVICE[] = "com.canonical.keeper";49 constexpr const char KEEPER_SERVICE[] = "com.canonical.keeper";
4650
=== added file 'src/qdbus-stubs/org.freedesktop.DBus.Properties.xml'
--- src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000
+++ src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 2017-02-27 19:05:17 +0000
@@ -0,0 +1,27 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
2 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
3<node>
4 <interface name="org.freedesktop.DBus.Properties">
5 <method name="Get">
6 <arg type="s" name="interface_name" direction="in"/>
7 <arg type="s" name="property_name" direction="in"/>
8 <arg type="v" name="value" direction="out"/>
9 </method>
10 <method name="GetAll">
11 <arg type="s" name="interface_name" direction="in"/>
12 <arg type="a{sv}" name="properties" direction="out"/>
13 <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
14 </method>
15 <method name="Set">
16 <arg type="s" name="interface_name" direction="in"/>
17 <arg type="s" name="property_name" direction="in"/>
18 <arg type="v" name="value" direction="in"/>
19 </method>
20 <signal name="PropertiesChanged">
21 <arg type="s" name="interface_name"/>
22 <arg type="a{sv}" name="changed_properties"/>
23 <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/>
24 <arg type="as" name="invalidated_properties"/>
25 </signal>
26 </interface>
27</node>
028
=== modified file 'src/service/CMakeLists.txt'
--- src/service/CMakeLists.txt 2016-09-06 01:31:59 +0000
+++ src/service/CMakeLists.txt 2017-02-27 19:05:17 +0000
@@ -15,6 +15,9 @@
15 task-manager.cpp15 task-manager.cpp
16 keeper-task.cpp16 keeper-task.cpp
17 keeper-task-backup.cpp17 keeper-task-backup.cpp
18 keeper-task-restore.cpp
19 manifest.cpp
20 metadata-provider.h
18)21)
19add_library(22add_library(
20 ${SERVICE_LIB}23 ${SERVICE_LIB}
@@ -46,6 +49,7 @@
46 storage-framework49 storage-framework
47 util50 util
48 qdbus-stubs51 qdbus-stubs
52 keeper-errors-lib
49)53)
5054
51target_link_libraries(55target_link_libraries(
5256
=== modified file 'src/service/backup-choices.cpp'
--- src/service/backup-choices.cpp 2016-09-05 18:38:36 +0000
+++ src/service/backup-choices.cpp 2017-02-27 19:05:17 +0000
@@ -45,22 +45,30 @@
45 }45 }
46}46}
4747
48BackupChoices::BackupChoices() =default;48BackupChoices::BackupChoices(QObject *parent)
49 : MetadataProvider(parent)
50{
51}
4952
50BackupChoices::~BackupChoices() =default;53BackupChoices::~BackupChoices() =default;
5154
52QVector<Metadata>55QVector<Metadata>
53BackupChoices::get_backups() const56BackupChoices::get_backups() const
54{57{
55 QVector<Metadata> ret;58 return backups_;
59}
5660
61void
62BackupChoices::get_backups_async(QString const & /*storage*/)
63{
64 backups_.clear();
57 //65 //
58 // System Data66 // System Data
59 //67 //
60 {68 {
61 Metadata m(generate_new_uuid(), "System Data"); // FIXME: how to i18n in a Qt DBus service?69 Metadata m(generate_new_uuid(), "System Data"); // FIXME: how to i18n in a Qt DBus service?
62 m.set_property(Metadata::TYPE_KEY, Metadata::SYSTEM_DATA_VALUE);70 m.set_property_value(Metadata::TYPE_KEY, Metadata::SYSTEM_DATA_VALUE);
63 ret.push_back(m);71 backups_.push_back(m);
64 }72 }
6573
66 //74 //
@@ -112,13 +120,13 @@
112 display_name = QStringLiteral("%1 (%2)").arg(display_name).arg(version.toString());120 display_name = QStringLiteral("%1 (%2)").arg(display_name).arg(version.toString());
113121
114 Metadata m(generate_new_uuid(), display_name);122 Metadata m(generate_new_uuid(), display_name);
115 m.set_property(Metadata::PACKAGE_KEY, name.toString());123 m.set_property_value(Metadata::PACKAGE_KEY, name.toString());
116 m.set_property(Metadata::TYPE_KEY, Metadata::APPLICATION_VALUE);124 m.set_property_value(Metadata::TYPE_KEY, Metadata::APPLICATION_VALUE);
117125
118 if (version != QJsonValue::Undefined)126 if (version != QJsonValue::Undefined)
119 m.set_property(Metadata::VERSION_KEY, version.toString());127 m.set_property_value(Metadata::VERSION_KEY, version.toString());
120128
121 ret.push_back(m);129 backups_.push_back(m);
122 }130 }
123 }131 }
124 }132 }
@@ -146,11 +154,11 @@
146 {154 {
147 const auto keystr = generate_new_uuid();155 const auto keystr = generate_new_uuid();
148 Metadata m(keystr, name);156 Metadata m(keystr, name);
149 m.set_property(Metadata::TYPE_KEY, Metadata::FOLDER_VALUE);157 m.set_property_value(Metadata::TYPE_KEY, Metadata::FOLDER_VALUE);
150 m.set_property(Metadata::SUBTYPE_KEY, locations.front());158 m.set_property_value(Metadata::SUBTYPE_KEY, locations.front());
151 ret.push_back(m);159 backups_.push_back(m);
152 }160 }
153 }161 }
154162
155 return ret;163 Q_EMIT(finished(keeper::Error::OK));
156}164}
157165
=== modified file 'src/service/backup-choices.h'
--- src/service/backup-choices.h 2016-09-05 18:38:36 +0000
+++ src/service/backup-choices.h 2017-02-27 19:05:17 +0000
@@ -27,7 +27,8 @@
27class BackupChoices: public MetadataProvider27class BackupChoices: public MetadataProvider
28{28{
29public:29public:
30 BackupChoices();30 explicit BackupChoices(QObject *parent = nullptr);
31 virtual ~BackupChoices();31 virtual ~BackupChoices();
32 QVector<Metadata> get_backups() const override;32 QVector<Metadata> get_backups() const override;
33 void get_backups_async(QString const & storage = "") override;
33};34};
3435
=== modified file 'src/service/keeper-helper.cpp'
--- src/service/keeper-helper.cpp 2016-08-10 02:06:08 +0000
+++ src/service/keeper-helper.cpp 2017-02-27 19:05:17 +0000
@@ -44,8 +44,11 @@
4444
45QDBusUnixFileDescriptor KeeperHelper::StartRestore()45QDBusUnixFileDescriptor KeeperHelper::StartRestore()
46{46{
47 // TODO get the file descriptor of the item in storage framework47 // pass it back to Keeper to do the work
48 return QDBusUnixFileDescriptor();48 Q_ASSERT(calledFromDBus());
49 auto bus = connection();
50 auto& msg = message();
51 return keeper_.StartRestore(bus, msg);
49}52}
5053
51void KeeperHelper::UpdateStatus(const QString &app_id, const QString &status, double percentage)54void KeeperHelper::UpdateStatus(const QString &app_id, const QString &status, double percentage)
5255
=== modified file 'src/service/keeper-task-backup.cpp'
--- src/service/keeper-task-backup.cpp 2016-09-06 20:08:14 +0000
+++ src/service/keeper-task-backup.cpp 2017-02-27 19:05:17 +0000
@@ -31,7 +31,7 @@
31 Q_DECLARE_PUBLIC(KeeperTaskBackup)31 Q_DECLARE_PUBLIC(KeeperTaskBackup)
32public:32public:
33 KeeperTaskBackupPrivate(KeeperTask * keeper_task,33 KeeperTaskBackupPrivate(KeeperTask * keeper_task,
34 KeeperTask::TaskData const & task_data,34 KeeperTask::TaskData & task_data,
35 QSharedPointer<HelperRegistry> const & helper_registry,35 QSharedPointer<HelperRegistry> const & helper_registry,
36 QSharedPointer<StorageFrameworkClient> const & storage)36 QSharedPointer<StorageFrameworkClient> const & storage)
37 : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage)37 : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage)
@@ -50,33 +50,52 @@
50 qDebug() << "Initializing a backup helper";50 qDebug() << "Initializing a backup helper";
51 helper_.reset(new BackupHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();});51 helper_.reset(new BackupHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();});
52 qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created";52 qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created";
53 QObject::connect(helper_.data(), &Helper::error, [this](keeper::Error error){ error_ = error;});
53 }54 }
5455
55 void ask_for_uploader(quint64 n_bytes)56 void ask_for_uploader(quint64 n_bytes, QString const & dir_name)
56 {57 {
57 qDebug() << "asking storage framework for a socket";58 qDebug() << "asking storage framework for a socket";
5859
59 helper_->set_expected_size(n_bytes);60 helper_->set_expected_size(n_bytes);
6061
62 const auto file_name = QString("%1.keeper").arg(task_data_.metadata.get_display_name());
63
61 connections_.connect_future(64 connections_.connect_future(
62 storage_->get_new_uploader(n_bytes),65 storage_->get_new_uploader(n_bytes, dir_name, file_name),
63 std::function<void(std::shared_ptr<Uploader> const&)>{66 std::function<void(std::shared_ptr<Uploader> const&)>{
64 [this](std::shared_ptr<Uploader> const& uploader){67 [this](std::shared_ptr<Uploader> const& uploader){
65 qDebug("calling helper.set_storage_framework_socket(socket=%d)", int(uploader->socket()->socketDescriptor()));68 auto fd {-1};
66 qDebug() << "Helper is " << static_cast<void*>(helper_.data());69 if (uploader) {
67 auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_);70 auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_);
68 backup_helper->set_uploader(uploader);71 backup_helper->set_uploader(uploader);
69 Q_EMIT(q_ptr->task_socket_ready(backup_helper->get_helper_socket()));72 fd = backup_helper->get_helper_socket();
73 qDebug("emitting task_socket_ready(socket=%d)", fd);
74 Q_EMIT(q_ptr->task_socket_ready(fd));
75 }
76 else
77 {
78 error_ = storage_->get_last_error();
79 qDebug("Emitting task_socket_error(error=%d)", static_cast<int>(error_));
80 Q_EMIT(q_ptr->task_socket_error(error_));
81 }
70 }82 }
71 }83 }
72 );84 );
73 }85 }
7486
87 QString get_file_name() const
88 {
89 auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_);
90 return backup_helper->get_uploader_committed_file_name();
91 }
92
75private:93private:
76 ConnectionHelper connections_;94 ConnectionHelper connections_;
95 QString file_name_;
77};96};
7897
79KeeperTaskBackup::KeeperTaskBackup(TaskData const & task_data,98KeeperTaskBackup::KeeperTaskBackup(TaskData & task_data,
80 QSharedPointer<HelperRegistry> const & helper_registry,99 QSharedPointer<HelperRegistry> const & helper_registry,
81 QSharedPointer<StorageFrameworkClient> const & storage,100 QSharedPointer<StorageFrameworkClient> const & storage,
82 QObject *parent)101 QObject *parent)
@@ -89,17 +108,27 @@
89QStringList KeeperTaskBackup::get_helper_urls() const108QStringList KeeperTaskBackup::get_helper_urls() const
90{109{
91 Q_D(const KeeperTaskBackup);110 Q_D(const KeeperTaskBackup);
111
92 return d->get_helper_urls();112 return d->get_helper_urls();
93}113}
94114
95void KeeperTaskBackup::init_helper()115void KeeperTaskBackup::init_helper()
96{116{
97 Q_D(KeeperTaskBackup);117 Q_D(KeeperTaskBackup);
118
98 d->init_helper();119 d->init_helper();
99}120}
100121
101void KeeperTaskBackup::ask_for_uploader(quint64 n_bytes)122void KeeperTaskBackup::ask_for_uploader(quint64 n_bytes, QString const & dir_name)
102{123{
103 Q_D(KeeperTaskBackup);124 Q_D(KeeperTaskBackup);
104 d->ask_for_uploader(n_bytes);125
126 d->ask_for_uploader(n_bytes, dir_name);
127}
128
129QString KeeperTaskBackup::get_file_name() const
130{
131 Q_D(const KeeperTaskBackup);
132
133 return d->get_file_name();
105}134}
106135
=== modified file 'src/service/keeper-task-backup.h'
--- src/service/keeper-task-backup.h 2016-09-06 02:13:34 +0000
+++ src/service/keeper-task-backup.h 2017-02-27 19:05:17 +0000
@@ -29,7 +29,7 @@
29 Q_DECLARE_PRIVATE(KeeperTaskBackup)29 Q_DECLARE_PRIVATE(KeeperTaskBackup)
30public:30public:
3131
32 KeeperTaskBackup(TaskData const & task_data,32 KeeperTaskBackup(TaskData & task_data,
33 QSharedPointer<HelperRegistry> const & helper_registry,33 QSharedPointer<HelperRegistry> const & helper_registry,
34 QSharedPointer<StorageFrameworkClient> const & storage,34 QSharedPointer<StorageFrameworkClient> const & storage,
35 QObject *parent = nullptr);35 QObject *parent = nullptr);
@@ -37,7 +37,9 @@
3737
38 Q_DISABLE_COPY(KeeperTaskBackup)38 Q_DISABLE_COPY(KeeperTaskBackup)
3939
40 void ask_for_uploader(quint64 n_bytes);40 void ask_for_uploader(quint64 n_bytes, QString const & dir_name);
41
42 QString get_file_name() const;
4143
42protected:44protected:
43 QStringList get_helper_urls() const override;45 QStringList get_helper_urls() const override;
4446
=== added file 'src/service/keeper-task-restore.cpp'
--- src/service/keeper-task-restore.cpp 1970-01-01 00:00:00 +0000
+++ src/service/keeper-task-restore.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,130 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 * Charles Kerr <charles.kerr@canonical.com>
19 */
20
21#include "util/connection-helper.h"
22#include "storage-framework/storage_framework_client.h"
23#include "helper/restore-helper.h"
24#include "service/app-const.h" // DEKKO_APP_ID
25#include "service/keeper-task-restore.h"
26#include "service/keeper-task.h"
27#include "service/private/keeper-task_p.h"
28
29namespace sf = unity::storage::qt::client;
30
31class KeeperTaskRestorePrivate : public KeeperTaskPrivate
32{
33 Q_DECLARE_PUBLIC(KeeperTaskRestore)
34public:
35 KeeperTaskRestorePrivate(KeeperTask * keeper_task,
36 KeeperTask::TaskData & task_data,
37 QSharedPointer<HelperRegistry> const & helper_registry,
38 QSharedPointer<StorageFrameworkClient> const & storage)
39 : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage)
40 {
41 }
42
43 ~KeeperTaskRestorePrivate() = default;
44
45 QStringList get_helper_urls() const
46 {
47 return helper_registry_->get_restore_helper_urls(task_data_.metadata);
48 }
49
50 void init_helper()
51 {
52 helper_.reset(new RestoreHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();});
53 qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created";
54 }
55
56 void ask_for_downloader()
57 {
58 qDebug() << "asking storage framework for a socket for reading";
59
60 auto file_name = task_data_.metadata.get_file_name();
61 if (file_name.isEmpty())
62 {
63 qWarning() << "ERROR: the restore task does not provide a valid file name to read from.";
64 return;
65 }
66
67 auto dir_name = task_data_.metadata.get_dir_name();
68 if (dir_name.isEmpty())
69 {
70 qWarning() << "ERROR: the restore task does not provide a valid directory name.";
71 return;
72 }
73
74 // extract the dir_name.
75 connections_.connect_future(
76 storage_->get_new_downloader(dir_name, file_name),
77 std::function<void(std::shared_ptr<Downloader> const&)>{
78 [this](std::shared_ptr<Downloader> const& downloader){
79 auto fd {-1};
80 if (downloader) {
81 auto restore_helper = qSharedPointerDynamicCast<RestoreHelper>(helper_);
82 restore_helper->set_downloader(downloader);
83 fd = restore_helper->get_helper_socket();
84 Q_EMIT(q_ptr->task_socket_ready(fd));
85 }
86 else
87 {
88 error_ = storage_->get_last_error();
89 qDebug("Emitting task_socket_error(error=%d)", static_cast<int>(error_));
90 Q_EMIT(q_ptr->task_socket_error(error_));
91 }
92 }
93 }
94 );
95 }
96
97private:
98 ConnectionHelper connections_;
99};
100
101KeeperTaskRestore::KeeperTaskRestore(TaskData & task_data,
102 QSharedPointer<HelperRegistry> const & helper_registry,
103 QSharedPointer<StorageFrameworkClient> const & storage,
104 QObject *parent)
105 : KeeperTask(*new KeeperTaskRestorePrivate(this, task_data, helper_registry, storage), parent)
106{
107}
108
109KeeperTaskRestore::~KeeperTaskRestore() = default;
110
111QStringList KeeperTaskRestore::get_helper_urls() const
112{
113 Q_D(const KeeperTaskRestore);
114
115 return d->get_helper_urls();
116}
117
118void KeeperTaskRestore::init_helper()
119{
120 Q_D(KeeperTaskRestore);
121
122 d->init_helper();
123}
124
125void KeeperTaskRestore::ask_for_downloader()
126{
127 Q_D(KeeperTaskRestore);
128
129 d->ask_for_downloader();
130}
0131
=== added file 'src/service/keeper-task-restore.h'
--- src/service/keeper-task-restore.h 1970-01-01 00:00:00 +0000
+++ src/service/keeper-task-restore.h 2017-02-27 19:05:17 +0000
@@ -0,0 +1,46 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia <xavi.garcia.mena@canonical.com>
18 * Charles Kerr <charles.kerr@canonical.com>
19 */
20#pragma once
21
22#include "keeper-task.h"
23
24class KeeperTaskRestorePrivate;
25
26class KeeperTaskRestore : public KeeperTask
27{
28 Q_OBJECT
29 Q_DECLARE_PRIVATE(KeeperTaskRestore)
30public:
31
32 KeeperTaskRestore(TaskData & task_data,
33 QSharedPointer<HelperRegistry> const & helper_registry,
34 QSharedPointer<StorageFrameworkClient> const & storage,
35 QObject *parent = nullptr);
36 virtual ~KeeperTaskRestore();
37
38 Q_DISABLE_COPY(KeeperTaskRestore)
39
40 void ask_for_downloader();
41
42protected:
43 QStringList get_helper_urls() const override;
44 void init_helper() override;
45
46};
047
=== modified file 'src/service/keeper-task.cpp'
--- src/service/keeper-task.cpp 2016-09-13 08:47:14 +0000
+++ src/service/keeper-task.cpp 2017-02-27 19:05:17 +0000
@@ -28,13 +28,14 @@
28#include <QString>28#include <QString>
2929
30KeeperTaskPrivate::KeeperTaskPrivate(KeeperTask * keeper_task,30KeeperTaskPrivate::KeeperTaskPrivate(KeeperTask * keeper_task,
31 KeeperTask::TaskData const & task_data,31 KeeperTask::TaskData & task_data,
32 QSharedPointer<HelperRegistry> const & helper_registry,32 QSharedPointer<HelperRegistry> const & helper_registry,
33 QSharedPointer<StorageFrameworkClient> const & storage)33 QSharedPointer<StorageFrameworkClient> const & storage)
34 : q_ptr(keeper_task)34 : q_ptr(keeper_task)
35 , task_data_(task_data)35 , task_data_(task_data)
36 , helper_registry_(helper_registry)36 , helper_registry_(helper_registry)
37 , storage_(storage)37 , storage_(storage)
38 , error_(keeper::Error::OK)
38{39{
39}40}
4041
@@ -49,8 +50,8 @@
49 if (urls.isEmpty())50 if (urls.isEmpty())
50 {51 {
51 task_data_.action = helper_->to_string(Helper::State::FAILED);52 task_data_.action = helper_->to_string(Helper::State::FAILED);
52 task_data_.error = "no helper information in registry";53 error_ = keeper::Error::HELPER_BAD_URL;
53 qWarning() << "ERROR: uuid: " << task_data_.metadata.uuid() << " has no url";54 qWarning() << QStringLiteral("Error: uuid %1 has no url").arg(task_data_.metadata.get_uuid());
54 calculate_and_notify_state(Helper::State::FAILED);55 calculate_and_notify_state(Helper::State::FAILED);
55 return false;56 return false;
56 }57 }
@@ -65,6 +66,10 @@
65 std::bind(&KeeperTaskPrivate::on_helper_percent_done_changed, this, std::placeholders::_1)66 std::bind(&KeeperTaskPrivate::on_helper_percent_done_changed, this, std::placeholders::_1)
66 );67 );
6768
69 QObject::connect(helper_.data(), &Helper::error, [this](keeper::Error error){
70 error_ = error;
71 });
72
68 helper_->start(urls);73 helper_->start(urls);
69 return true;74 return true;
70}75}
@@ -120,22 +125,28 @@
120{125{
121 QVariantMap ret;126 QVariantMap ret;
122127
123 auto const uuid = task_data_.metadata.uuid();128 auto const uuid = task_data_.metadata.get_uuid();
124129
125 ret.insert(QStringLiteral("action"), task_data_.action);130 ret.insert(keeper::Item::STATUS_KEY, task_data_.action);
126131 ret.insert(keeper::Item::DISPLAY_NAME_KEY, task_data_.metadata.get_display_name());
127 ret.insert(QStringLiteral("display-name"), task_data_.metadata.display_name());
128132
129 auto const speed = helper_->speed();133 auto const speed = helper_->speed();
130 ret.insert(QStringLiteral("speed"), int32_t(speed));134 ret.insert(keeper::Item::SPEED_KEY, int32_t(speed));
131135
132 auto const percent_done = helper_->percent_done();136 auto const percent_done = helper_->percent_done();
133 ret.insert(QStringLiteral("percent-done"), double(percent_done));137 ret.insert(keeper::Item::PERCENT_DONE_KEY, double(percent_done));
134138
135 if (task_data_.action == "failed")139 if (task_data_.action == "failed" || task_data_.action == "cancelled")
136 ret.insert(QStringLiteral("error"), task_data_.error);140 {
137141 auto error = error_;
138 ret.insert(QStringLiteral("uuid"), uuid);142 if (task_data_.error != keeper::Error::OK)
143 {
144 error = task_data_.error;
145 }
146 ret.insert(keeper::Item::ERROR_KEY, QVariant::fromValue(error));
147 }
148
149 ret.insert(keeper::Item::UUID_KEY, uuid);
139150
140 QJsonDocument doc(QJsonObject::fromVariantMap(ret));151 QJsonDocument doc(QJsonObject::fromVariantMap(ret));
141 qDebug() << QString(doc.toJson(QJsonDocument::Compact));152 qDebug() << QString(doc.toJson(QJsonDocument::Compact));
@@ -145,29 +156,60 @@
145156
146void KeeperTaskPrivate::calculate_and_notify_state(Helper::State state)157void KeeperTaskPrivate::calculate_and_notify_state(Helper::State state)
147{158{
159 recalculate_task_state();
160 Q_EMIT(q_ptr->task_state_changed(state));
161}
162
163void KeeperTaskPrivate::recalculate_task_state()
164{
148 state_ = calculate_task_state();165 state_ = calculate_task_state();
149 Q_EMIT(q_ptr->task_state_changed(state));166}
167
168void KeeperTaskPrivate::cancel()
169{
170 if (helper_)
171 {
172 helper_->stop();
173 }
150}174}
151175
152QVariantMap KeeperTaskPrivate::get_initial_state(KeeperTask::TaskData const &td)176QVariantMap KeeperTaskPrivate::get_initial_state(KeeperTask::TaskData const &td)
153{177{
154 QVariantMap ret;178 QVariantMap ret;
155179
156 auto const uuid = td.metadata.uuid();180 auto const uuid = td.metadata.get_uuid();
157181
158 ret.insert(QStringLiteral("action"), td.action);182 ret.insert(keeper::Item::STATUS_KEY, td.action);
159183
160 // TODO review this when we add the restore tasks.184 // TODO review this when we add the restore tasks.
161 // TODO we maybe have different fields185 // TODO we maybe have different fields
162 ret.insert(QStringLiteral("display-name"), td.metadata.display_name());186 ret.insert(keeper::Item::DISPLAY_NAME_KEY, td.metadata.get_display_name());
163 ret.insert(QStringLiteral("speed"), 0);187 ret.insert(keeper::Item::SPEED_KEY, 0);
164 ret.insert(QStringLiteral("percent-done"), double(0.0));188 ret.insert(keeper::Item::PERCENT_DONE_KEY, double(0.0));
165 ret.insert(QStringLiteral("uuid"), uuid);189 ret.insert(keeper::Item::UUID_KEY, uuid);
166190
167 return ret;191 return ret;
168}192}
169193
170KeeperTask::KeeperTask(TaskData const & task_data,194QString KeeperTaskPrivate::to_string(Helper::State state)
195{
196 if (helper_)
197 {
198 return helper_->to_string(state);
199 }
200 else
201 {
202 qWarning() << "Asking for the string of a state when the helper is not initialized yet";
203 return "bug";
204 }
205}
206
207keeper::Error KeeperTaskPrivate::error() const
208{
209 return error_;
210}
211
212KeeperTask::KeeperTask(TaskData & task_data,
171 QSharedPointer<HelperRegistry> const & helper_registry,213 QSharedPointer<HelperRegistry> const & helper_registry,
172 QSharedPointer<StorageFrameworkClient> const & storage,214 QSharedPointer<StorageFrameworkClient> const & storage,
173 QObject *parent)215 QObject *parent)
@@ -188,16 +230,47 @@
188bool KeeperTask::start()230bool KeeperTask::start()
189{231{
190 Q_D(KeeperTask);232 Q_D(KeeperTask);
233
191 return d->start();234 return d->start();
192}235}
193236
194QVariantMap KeeperTask::state() const237QVariantMap KeeperTask::state() const
195{238{
196 Q_D(const KeeperTask);239 Q_D(const KeeperTask);
240
197 return d->state();241 return d->state();
198}242}
199243
244void KeeperTask::recalculate_task_state()
245{
246 Q_D(KeeperTask);
247
248 return d->recalculate_task_state();
249}
250
251
200QVariantMap KeeperTask::get_initial_state(KeeperTask::TaskData const &td)252QVariantMap KeeperTask::get_initial_state(KeeperTask::TaskData const &td)
201{253{
202 return KeeperTaskPrivate::get_initial_state(td);254 return KeeperTaskPrivate::get_initial_state(td);
203}255}
256
257void KeeperTask::cancel()
258{
259 Q_D(KeeperTask);
260
261 return d->cancel();
262}
263
264QString KeeperTask::to_string(Helper::State state)
265{
266 Q_D(KeeperTask);
267
268 return d->to_string(state);
269}
270
271keeper::Error KeeperTask::error() const
272{
273 Q_D(const KeeperTask);
274
275 return d->error();
276}
204277
=== modified file 'src/service/keeper-task.h'
--- src/service/keeper-task.h 2016-09-07 17:07:23 +0000
+++ src/service/keeper-task.h 2017-02-27 19:05:17 +0000
@@ -20,6 +20,7 @@
2020
21#pragma once21#pragma once
2222
23#include "client/keeper-errors.h"
23#include "helper/metadata.h"24#include "helper/metadata.h"
24#include "helper/backup-helper.h"25#include "helper/backup-helper.h"
25#include "helper/helper.h"26#include "helper/helper.h"
@@ -40,11 +41,11 @@
40 struct TaskData41 struct TaskData
41 {42 {
42 QString action;43 QString action;
43 QString error;44 keeper::Error error;
44 Metadata metadata;45 Metadata metadata;
45 };46 };
4647
47 KeeperTask(TaskData const & task_data,48 KeeperTask(TaskData & task_data,
48 QSharedPointer<HelperRegistry> const & helper_registry,49 QSharedPointer<HelperRegistry> const & helper_registry,
49 QSharedPointer<StorageFrameworkClient> const & storage,50 QSharedPointer<StorageFrameworkClient> const & storage,
50 QObject *parent = nullptr);51 QObject *parent = nullptr);
@@ -54,12 +55,19 @@
5455
55 bool start();56 bool start();
56 QVariantMap state() const;57 QVariantMap state() const;
58 void recalculate_task_state();
5759
58 static QVariantMap get_initial_state(KeeperTask::TaskData const &td);60 static QVariantMap get_initial_state(KeeperTask::TaskData const &td);
5961
62 void cancel();
63
64 QString to_string(Helper::State state);
65
66 keeper::Error error() const;
60Q_SIGNALS:67Q_SIGNALS:
61 void task_state_changed(Helper::State state);68 void task_state_changed(Helper::State state);
62 void task_socket_ready(int socket_descriptor);69 void task_socket_ready(int socket_descriptor);
70 void task_socket_error(keeper::Error error);
6371
64protected:72protected:
65 KeeperTask(KeeperTaskPrivate & d, QObject *parent = nullptr);73 KeeperTask(KeeperTaskPrivate & d, QObject *parent = nullptr);
6674
=== modified file 'src/service/keeper-user.cpp'
--- src/service/keeper-user.cpp 2016-09-07 16:35:26 +0000
+++ src/service/keeper-user.cpp 2017-02-27 19:05:17 +0000
@@ -33,75 +33,67 @@
3333
34KeeperUser::~KeeperUser() =default;34KeeperUser::~KeeperUser() =default;
3535
36namespace36keeper::Items
37{
38 QVariantMap strings_to_variants(const QMap<QString,QString>& strings)
39 {
40 QVariantMap variants;
41
42 for (auto it=strings.begin(), end=strings.end(); it!=end; ++it)
43 variants.insert(it.key(), QVariant::fromValue(it.value()));
44
45 return variants;
46 }
47
48 QVariantDictMap choices_to_variant_dict_map(const QVector<Metadata>& choices)
49 {
50 QVariantDictMap ret;
51
52 for (auto const& metadata : choices)
53 ret.insert(metadata.uuid(), strings_to_variants(metadata.get_public_properties()));
54
55 return ret;
56 }
57}
58
59QVariantDictMap
60KeeperUser::GetBackupChoices()37KeeperUser::GetBackupChoices()
61{38{
62 return choices_to_variant_dict_map(keeper_.get_backup_choices());39 auto bus = connection();
40 auto& msg = message();
41 return keeper_.get_backup_choices_var_dict_map(bus, msg);
63}42}
6443
65void44void
66KeeperUser::StartBackup (const QStringList& keys)45KeeperUser::StartBackup (const QStringList& keys, QString const & storage)
67{46{
68 Q_ASSERT(calledFromDBus());47 Q_ASSERT(calledFromDBus());
6948
70 auto const unhandled = keeper_.start_tasks(keys);49 auto bus = connection();
7150 auto& msg = message();
72 if (!unhandled.empty())51 keeper_.start_tasks(keys, storage, bus, msg);
73 {
74 QString text = QStringLiteral("unhandled uuids:");
75 for (auto const& uuid : unhandled)
76 text += ' ' + uuid;
77 connection().send(message().createErrorReply(QDBusError::InvalidArgs, text));
78 }
79}52}
8053
81void54void
82KeeperUser::Cancel()55KeeperUser::Cancel()
83{56{
84 // FIXME: writeme57 keeper_.cancel();
85
86 qDebug() << "hello world";
87}58}
8859
89QVariantDictMap60keeper::Items
90KeeperUser::GetRestoreChoices()61KeeperUser::GetRestoreChoices(QString const & storage)
91{62{
92 return choices_to_variant_dict_map(keeper_.get_restore_choices());63 Q_ASSERT(calledFromDBus());
64
65 auto bus = connection();
66 auto& msg = message();
67 return keeper_.get_restore_choices(storage, bus, msg);
93}68}
9469
95void70void
96KeeperUser::StartRestore (const QStringList& keys)71KeeperUser::StartRestore (const QStringList& keys, QString const & storage)
97{72{
98 // FIXME: writeme73 Q_ASSERT(calledFromDBus());
9974
100 qDebug() << keys;75 auto bus = connection();
76 auto& msg = message();
77 // if we start a restore right after a backup the uuid
78 // will be found as a backup uuid.
79 // Just clear the backup cache to avoid that.
80 keeper_.invalidate_choices_cache();
81 keeper_.start_tasks(keys, storage, bus, msg);
101}82}
10283
103QVariantDictMap84keeper::Items
104KeeperUser::get_state() const85KeeperUser::get_state() const
105{86{
106 return keeper_.get_state();87 return keeper_.get_state();
107}88}
89
90QStringList
91KeeperUser::GetStorageAccounts()
92{
93 Q_ASSERT(calledFromDBus());
94
95 auto bus = connection();
96 auto& msg = message();
97
98 return keeper_.get_storage_accounts(bus, msg);
99}
108100
=== modified file 'src/service/keeper-user.h'
--- src/service/keeper-user.h 2016-09-05 18:38:36 +0000
+++ src/service/keeper-user.h 2017-02-27 19:05:17 +0000
@@ -37,11 +37,11 @@
37 virtual ~KeeperUser();37 virtual ~KeeperUser();
38 Q_DISABLE_COPY(KeeperUser)38 Q_DISABLE_COPY(KeeperUser)
3939
40 Q_PROPERTY(QVariantDictMap State40 Q_PROPERTY(keeper::Items State
41 READ get_state41 READ get_state
42 NOTIFY state_changed)42 NOTIFY state_changed)
4343
44 QVariantDictMap get_state() const;44 keeper::Items get_state() const;
4545
46Q_SIGNALS:46Q_SIGNALS:
4747
@@ -49,14 +49,16 @@
4949
50public Q_SLOTS:50public Q_SLOTS:
5151
52 QVariantDictMap GetBackupChoices();52 keeper::Items GetBackupChoices();
53 void StartBackup(const QStringList&);53 void StartBackup(const QStringList&, QString const & storage);
5454
55 QVariantDictMap GetRestoreChoices();55 keeper::Items GetRestoreChoices(QString const & storage);
56 void StartRestore(const QStringList&);56 void StartRestore(const QStringList&, QString const & storage);
5757
58 void Cancel();58 void Cancel();
5959
60 QStringList GetStorageAccounts();
61
60private:62private:
6163
62 Keeper& keeper_;64 Keeper& keeper_;
6365
=== modified file 'src/service/keeper.cpp'
--- src/service/keeper.cpp 2016-09-07 16:35:26 +0000
+++ src/service/keeper.cpp 2017-02-27 19:05:17 +0000
@@ -32,78 +32,232 @@
32#include <QVector>32#include <QVector>
3333
34#include <algorithm> // std::find_if34#include <algorithm> // std::find_if
3535#include <unistd.h>
36class KeeperPrivate36
37{37namespace
38{
39// QVariantMap strings_to_variants(const QMap<QString,QString>& strings)
40// {
41// QVariantMap variants;
42//
43// for (auto it=strings.begin(), end=strings.end(); it!=end; ++it)
44// variants.insert(it.key(), QVariant::fromValue(it.value()));
45//
46// return variants;
47// }
48
49 keeper::Items choices_to_variant_dict_map(QVector<Metadata> const & choices)
50 {
51 keeper::Items ret;
52
53 for (auto const& metadata : choices)
54 {
55 keeper::Item value(metadata);
56 ret.insert(metadata.get_uuid(), value);
57 }
58
59 return ret;
60 }
61}
62
63class KeeperPrivate : public QObject
64{
65 Q_OBJECT
38public:66public:
3967
40 KeeperPrivate(Keeper* keeper,68 KeeperPrivate(Keeper* keeper,
41 const QSharedPointer<HelperRegistry>& helper_registry,69 const QSharedPointer<HelperRegistry>& helper_registry,
42 const QSharedPointer<MetadataProvider>& backup_choices,70 const QSharedPointer<MetadataProvider>& backup_choices,
43 const QSharedPointer<MetadataProvider>& restore_choices)71 const QSharedPointer<MetadataProvider>& restore_choices,
44 : q_ptr(keeper)72 QObject *parent = nullptr)
73 : QObject(parent)
74 , q_ptr(keeper)
45 , storage_(new StorageFrameworkClient())75 , storage_(new StorageFrameworkClient())
46 , helper_registry_(helper_registry)76 , helper_registry_(helper_registry)
47 , backup_choices_(backup_choices)77 , backup_choices_(backup_choices)
48 , restore_choices_(restore_choices)78 , restore_choices_(restore_choices)
49 , task_manager_{helper_registry, storage_}79 , task_manager_{helper_registry, storage_}
50 {80 {
81 QObject::connect(&task_manager_, &TaskManager::finished,
82 std::bind(&KeeperPrivate::on_task_manager_finished, this)
83 );
51 }84 }
5285
86 enum class ChoicesType { BACKUP_CHOICES, RESTORES_CHOICES };
87
53 ~KeeperPrivate() =default;88 ~KeeperPrivate() =default;
5489
55 Q_DISABLE_COPY(KeeperPrivate)90 Q_DISABLE_COPY(KeeperPrivate)
5691
57 QStringList start_tasks(QStringList const & uuids)92 void start_tasks(QStringList const & uuids,
93 QString const & storage,
94 QDBusConnection bus,
95 QDBusMessage const & msg)
58 {96 {
59 auto unhandled = QSet<QString>::fromList(uuids);
60
61 auto get_tasks = [](const QVector<Metadata>& pool, QStringList const& keys){97 auto get_tasks = [](const QVector<Metadata>& pool, QStringList const& keys){
62 QMap<QString,Metadata> tasks;98 QMap<QString,Metadata> tasks;
63 for (auto const& key : keys) {99 for (auto const& key : keys) {
64 auto it = std::find_if(pool.begin(), pool.end(), [key](Metadata const & m){return m.uuid()==key;});100 auto it = std::find_if(pool.begin(), pool.end(), [key](Metadata const & m){return m.get_uuid()==key;});
65 if (it != pool.end())101 if (it != pool.end())
66 tasks[key] = *it;102 tasks[key] = *it;
67 }103 }
68 return tasks;104 return tasks;
69 };105 };
70106
71 auto tasks = get_tasks(get_backup_choices(), uuids);107 // async part
72 if (!tasks.empty())108 qDebug() << "Looking for backup options....";
73 {109 connections_.connect_oneshot(
74 if (task_manager_.start_backup(tasks.values()))110 this,
75 unhandled.subtract(QSet<QString>::fromList(tasks.keys()));111 &KeeperPrivate::backup_choices_ready,
112 std::function<void()>{[this, uuids, msg, bus, get_tasks, storage](){
113 auto tasks = get_tasks(cached_backup_choices_, uuids);
114 if (!tasks.empty())
115 {
116 auto unhandled = QSet<QString>::fromList(uuids);
117 if (task_manager_.start_backup(tasks.values(), storage))
118 unhandled.subtract(QSet<QString>::fromList(tasks.keys()));
119
120 check_for_unhandled_tasks_and_reply(unhandled, bus, msg);
121 }
122 else // restore
123 {
124 qDebug() << "Looking for restore options....";
125 connections_.connect_oneshot(
126 this,
127 &KeeperPrivate::restore_choices_ready,
128 std::function<void(keeper::Error)>{[this, uuids, msg, bus, get_tasks, storage](keeper::Error error){
129 qDebug() << "Choices ready";
130 auto unhandled = QSet<QString>::fromList(uuids);
131 if (error == keeper::Error::OK)
132 {
133 auto restore_tasks = get_tasks(cached_restore_choices_, uuids);
134 qDebug() << "After getting tasks...";
135 if (!restore_tasks.empty() && task_manager_.start_restore(restore_tasks.values(), storage))
136 unhandled.subtract(QSet<QString>::fromList(restore_tasks.keys()));
137 }
138 check_for_unhandled_tasks_and_reply(unhandled, bus, msg);
139 }}
140 );
141 get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES);
142 }
143 }}
144 );
145
146 get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES);
147 msg.setDelayedReply(true);
148 }
149
150 void emit_choices_ready(ChoicesType type, keeper::Error error)
151 {
152 switch(type)
153 {
154 case KeeperPrivate::ChoicesType::BACKUP_CHOICES:
155 Q_EMIT(backup_choices_ready(error));
156 break;
157 case KeeperPrivate::ChoicesType::RESTORES_CHOICES:
158 Q_EMIT(restore_choices_ready(error));
159 break;
160 }
161 }
162
163 void get_choices(const QSharedPointer<MetadataProvider> & provider, ChoicesType type, QString const & storage = "")
164 {
165 bool check_empty = (type == KeeperPrivate::ChoicesType::BACKUP_CHOICES)
166 ? cached_backup_choices_.isEmpty() : cached_restore_choices_.isEmpty();
167 if (check_empty)
168 {
169 connections_.connect_oneshot(
170 provider.data(),
171 &MetadataProvider::finished,
172 std::function<void(keeper::Error)>{[this, provider, type](keeper::Error error){
173 qDebug() << "Get choices finished";
174 if (error == keeper::Error::OK)
175 {
176 switch (type)
177 {
178 case KeeperPrivate::ChoicesType::BACKUP_CHOICES:
179 cached_backup_choices_ = provider->get_backups();
180 break;
181 case KeeperPrivate::ChoicesType::RESTORES_CHOICES:
182 cached_restore_choices_ = provider->get_backups();
183 break;
184 }
185 }
186 emit_choices_ready(type, error);
187 }}
188 );
189 provider->get_backups_async(storage);
76 }190 }
77 else191 else
78 {192 {
79 tasks = get_tasks(get_restore_choices(), uuids);193 emit_choices_ready(type, keeper::Error::OK);
80 if (!tasks.empty() && task_manager_.start_restore(tasks.values()))
81 unhandled.subtract(QSet<QString>::fromList(tasks.keys()));
82 }194 }
83195 }
84 if (!unhandled.empty())196
85 qWarning() << "skipped tasks" << unhandled;197 keeper::Items get_backup_choices_var_dict_map(QDBusConnection bus,
86198 QDBusMessage const & msg)
87 return QStringList::fromSet(unhandled);199 {
88 }200 connections_.connect_oneshot(
89201 this,
90 QVector<Metadata> get_backup_choices() const202 &KeeperPrivate::backup_choices_ready,
91 {203 std::function<void(keeper::Error)>{[this, msg, bus](keeper::Error error){
92 if (cached_backup_choices_.isEmpty())204 qDebug() << "Backup choices are ready";
93 cached_backup_choices_ = backup_choices_->get_backups();205 if (error == keeper::Error::OK)
94206 {
95 return cached_backup_choices_;207 // reply now to the dbus call
96 }208 auto reply = msg.createReply();
97209 reply << QVariant::fromValue(choices_to_variant_dict_map(cached_backup_choices_));
98 QVector<Metadata> get_restore_choices() const210 bus.send(reply);
99 {211 }
100 if (cached_restore_choices_.isEmpty())212 else
101 cached_restore_choices_ = restore_choices_->get_backups();213 {
102214 auto message = QStringLiteral("Error obtaining backup choices, keeper returned error: %1").arg(static_cast<int>(error));
103 return cached_restore_choices_;215 qWarning() << message;
104 }216 auto reply = msg.createErrorReply(QDBusError::Failed, message);
105217 reply << QVariant::fromValue(error);
106 QVariantDictMap get_state() const218 bus.send(reply);
219 }
220 }}
221 );
222 get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES);
223 msg.setDelayedReply(true);
224 return keeper::Items();
225 }
226
227 keeper::Items get_restore_choices_var_dict_map(QString const & storage,
228 QDBusConnection bus,
229 QDBusMessage const & msg)
230 {
231 qDebug() << "Getting restores for storage " << storage << " --------------------------------";
232 cached_restore_choices_.clear();
233 connections_.connect_oneshot(
234 this,
235 &KeeperPrivate::restore_choices_ready,
236 std::function<void(keeper::Error)>{[this, msg, bus](keeper::Error error){
237 qDebug() << "Restore choices are ready";
238 if (error == keeper::Error::OK)
239 {
240 // reply now to the dbus call
241 auto reply = msg.createReply();
242 reply << QVariant::fromValue(choices_to_variant_dict_map(cached_restore_choices_));
243 bus.send(reply);
244 }
245 else
246 {
247 auto message = QStringLiteral("Error obtaining restore choices, keeper returned error: %1").arg(static_cast<int>(error));
248 qWarning() << message;
249 auto reply = msg.createErrorReply(QDBusError::Failed, message);
250 reply << QVariant::fromValue(error);
251 bus.send(reply);
252 }
253 }}
254 );
255 get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES, storage);
256 msg.setDelayedReply(true);
257 return keeper::Items();
258 }
259
260 keeper::Items get_state() const
107 {261 {
108 return task_manager_.get_state();262 return task_manager_.get_state();
109 }263 }
@@ -127,7 +281,18 @@
127 }281 }
128 );282 );
129283
130 qDebug() << "Asking for an storage framework socket to the task manager";284 connections_.connect_oneshot(
285 &task_manager_,
286 &TaskManager::socket_error,
287 std::function<void(keeper::Error)>{
288 [bus,msg](keeper::Error error){
289 qDebug("BackupManager returned socket error: %d", static_cast<int>(error));
290 bus.send(msg.createErrorReply(QDBusError::InvalidArgs, "Error obtaining remote backup socket"));
291 }
292 }
293 );
294
295 qDebug() << "Asking for a storage framework socket from the task manager";
131 task_manager_.ask_for_uploader(n_bytes);296 task_manager_.ask_for_uploader(n_bytes);
132297
133 // tell the caller that we'll be responding async298 // tell the caller that we'll be responding async
@@ -135,7 +300,102 @@
135 return QDBusUnixFileDescriptor(0);300 return QDBusUnixFileDescriptor(0);
136 }301 }
137302
303
304 QDBusUnixFileDescriptor start_restore(QDBusConnection bus,
305 QDBusMessage const & msg)
306 {
307 qDebug() << "Keeper::StartRestore()";
308
309 connections_.connect_oneshot(
310 &task_manager_,
311 &TaskManager::socket_ready,
312 std::function<void(int)>{
313 [bus,msg](int fd){
314 qDebug("RestoreManager returned socket %d", fd);
315 auto reply = msg.createReply();
316 reply << QVariant::fromValue(QDBusUnixFileDescriptor(fd));
317 close(fd);
318 bus.send(reply);
319 }
320 }
321 );
322
323 connections_.connect_oneshot(
324 &task_manager_,
325 &TaskManager::socket_error,
326 std::function<void(keeper::Error)>{
327 [bus,msg](keeper::Error error){
328 qDebug("RestoreManager returned socket error: %d", static_cast<int>(error));
329 bus.send(msg.createErrorReply(QDBusError::InvalidArgs, "Error obtaining remote restore socket"));
330 }
331 }
332 );
333
334 qDebug() << "Asking for a storage framework socket from the task manager";
335 task_manager_.ask_for_downloader();
336
337 // tell the caller that we'll be responding async
338 msg.setDelayedReply(true);
339 return QDBusUnixFileDescriptor(0);
340 }
341
342 void cancel()
343 {
344 task_manager_.cancel();
345 }
346
347 void invalidate_choices_cache()
348 {
349 cached_backup_choices_.clear();
350 }
351
352 QStringList get_storage_accounts(QDBusConnection bus,
353 QDBusMessage const & msg)
354 {
355 connections_.connect_future(
356 storage_->get_accounts(),
357 std::function<void(QStringList const &)>{
358 [this, msg, bus](QStringList const& accounts){
359 qDebug() << "get_storage_accounts() finished";
360 // reply now to the dbus call
361 auto reply = msg.createReply();
362 reply << QVariant::fromValue(accounts);
363 bus.send(reply);
364 }
365 }
366 );
367 msg.setDelayedReply(true);
368 return QStringList();
369 }
370
371Q_SIGNALS:
372 void backup_choices_ready(keeper::Error error);
373 void restore_choices_ready(keeper::Error error);
374
138private:375private:
376 void on_task_manager_finished()
377 {
378 // force a backup choices regeneration to avoid repeating uuids
379 // between backups
380 invalidate_choices_cache();
381 }
382
383 void check_for_unhandled_tasks_and_reply(QSet<QString> const & unhandled,
384 QDBusConnection bus,
385 QDBusMessage const & msg )
386 {
387 if (!unhandled.empty())
388 {
389 qWarning() << "skipped tasks" << unhandled;
390 QString text = QStringLiteral("unhandled uuids:");
391 for (auto const& uuid : unhandled)
392 text += ' ' + uuid;
393 bus.send(msg.createErrorReply(QDBusError::InvalidArgs, text));
394 }
395
396 auto reply = msg.createReply();
397 bus.send(reply);
398 }
139399
140 Keeper * const q_ptr;400 Keeper * const q_ptr;
141 QSharedPointer<StorageFrameworkClient> storage_;401 QSharedPointer<StorageFrameworkClient> storage_;
@@ -160,12 +420,15 @@
160420
161Keeper::~Keeper() = default;421Keeper::~Keeper() = default;
162422
163QStringList423void
164Keeper::start_tasks(QStringList const & uuids)424Keeper::start_tasks(QStringList const & uuids,
425 QString const & storage,
426 QDBusConnection bus,
427 QDBusMessage const & msg)
165{428{
166 Q_D(Keeper);429 Q_D(Keeper);
167430
168 return d->start_tasks(uuids);431 d->start_tasks(uuids, storage, bus, msg);
169}432}
170433
171QDBusUnixFileDescriptor434QDBusUnixFileDescriptor
@@ -178,26 +441,66 @@
178 return d->start_backup(bus, msg, n_bytes);441 return d->start_backup(bus, msg, n_bytes);
179}442}
180443
181QVector<Metadata>444QDBusUnixFileDescriptor
182Keeper::get_backup_choices()445Keeper::StartRestore(QDBusConnection bus,
183{446 QDBusMessage const & msg)
184 Q_D(Keeper);447{
185448 Q_D(Keeper);
186 return d->get_backup_choices();449
187}450 return d->start_restore(bus, msg);
188451}
189QVector<Metadata>452
190Keeper::get_restore_choices()453keeper::Items
191{454Keeper::get_backup_choices_var_dict_map(QDBusConnection bus,
192 Q_D(Keeper);455 QDBusMessage const & msg)
193456{
194 return d->get_restore_choices();457 Q_D(Keeper);
195}458
196459 return d->get_backup_choices_var_dict_map(bus, msg);
197QVariantDictMap460}
461
462keeper::Items
463Keeper::get_restore_choices(QString const & storage,
464 QDBusConnection bus,
465 QDBusMessage const & msg)
466{
467 Q_D(Keeper);
468
469 return d->get_restore_choices_var_dict_map(storage, bus, msg);
470}
471
472keeper::Items
198Keeper::get_state() const473Keeper::get_state() const
199{474{
200 Q_D(const Keeper);475 Q_D(const Keeper);
201476
202 return d->get_state();477 return d->get_state();
203}478}
479
480void
481Keeper::cancel()
482{
483 Q_D(Keeper);
484
485 return d->cancel();
486}
487
488void
489Keeper::invalidate_choices_cache()
490{
491 Q_D(Keeper);
492
493 d->invalidate_choices_cache();
494}
495
496QStringList
497Keeper::get_storage_accounts(QDBusConnection bus,
498 QDBusMessage const & message)
499{
500 Q_D(Keeper);
501
502 return d->get_storage_accounts(bus,message);
503}
504
505
506#include "keeper.moc"
204507
=== modified file 'src/service/keeper.h'
--- src/service/keeper.h 2016-09-07 16:47:55 +0000
+++ src/service/keeper.h 2017-02-27 19:05:17 +0000
@@ -52,16 +52,30 @@
5252
53 virtual ~Keeper();53 virtual ~Keeper();
5454
55 QVector<Metadata> get_backup_choices();55 keeper::Items get_backup_choices_var_dict_map(QDBusConnection bus, QDBusMessage const & msg);
56 QVector<Metadata> get_restore_choices();56 keeper::Items get_restore_choices(QString const & storage, QDBusConnection bus, QDBusMessage const & msg);
5757
58 QDBusUnixFileDescriptor StartBackup(QDBusConnection,58 QDBusUnixFileDescriptor StartBackup(QDBusConnection,
59 QDBusMessage const & message,59 QDBusMessage const & message,
60 quint64 nbytes);60 quint64 nbytes);
6161
62 QStringList start_tasks(QStringList const & uuids);62
6363 QDBusUnixFileDescriptor StartRestore(QDBusConnection,
64 QVariantDictMap get_state() const;64 QDBusMessage const & message);
65
66 void start_tasks(QStringList const & uuids,
67 QString const & storage,
68 QDBusConnection bus,
69 QDBusMessage const & msg);
70
71 keeper::Items get_state() const;
72
73 void cancel();
74
75 void invalidate_choices_cache();
76
77 QStringList get_storage_accounts(QDBusConnection,
78 QDBusMessage const & message);
6579
66private:80private:
67 QScopedPointer<KeeperPrivate> const d_ptr;81 QScopedPointer<KeeperPrivate> const d_ptr;
6882
=== modified file 'src/service/main.cpp'
--- src/service/main.cpp 2016-08-10 05:41:26 +0000
+++ src/service/main.cpp 2017-02-27 19:05:17 +0000
@@ -20,6 +20,7 @@
2020
21#include "dbus-types.h"21#include "dbus-types.h"
22#include "helper/data-dir-registry.h"22#include "helper/data-dir-registry.h"
23#include "helper/helper.h"
23#include "service/backup-choices.h"24#include "service/backup-choices.h"
24#include "service/restore-choices.h"25#include "service/restore-choices.h"
25#include "service/keeper.h"26#include "service/keeper.h"
@@ -45,7 +46,7 @@
4546
46 QCoreApplication app(argc, argv);47 QCoreApplication app(argc, argv);
47 DBusTypes::registerMetaTypes();48 DBusTypes::registerMetaTypes();
48// Variant::registerMetaTypes();49 Helper::registerMetaTypes();
49 std::srand(unsigned(std::time(nullptr)));50 std::srand(unsigned(std::time(nullptr)));
5051
51 util::UnixSignalHandler handler([]{52 util::UnixSignalHandler handler([]{
5253
=== added file 'src/service/manifest.cpp'
--- src/service/manifest.cpp 1970-01-01 00:00:00 +0000
+++ src/service/manifest.cpp 2017-02-27 19:05:17 +0000
@@ -0,0 +1,248 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
18 */
19
20#include "manifest.h"
21
22#include "storage-framework/storage_framework_client.h"
23#include "util/connection-helper.h"
24
25#include <QJsonArray>
26#include <QJsonDocument>
27#include <QJsonObject>
28#include <QSharedPointer>
29#include <QVector>
30
31#include <fcntl.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34
35namespace sf = unity::storage::qt::client;
36
37// JSON Keys
38namespace
39{
40 constexpr const char ENTRIES_KEY[] = "entries";
41 constexpr const char MANIFEST_FILE_NAME[] = "manifest.json";
42}
43
44/***
45****
46***/
47
48class ManifestPrivate
49{
50public:
51 ManifestPrivate(QSharedPointer<StorageFrameworkClient> const & storage, QString const & dir, Manifest * manifest)
52 : q_ptr{manifest}
53 , storage_{storage}
54 , dir_{dir}
55 {
56 }
57
58 ~ManifestPrivate() = default;
59
60 Q_DISABLE_COPY(ManifestPrivate)
61
62 void add_entry(Metadata const & entry)
63 {
64 entries_.push_back(entry);
65 }
66
67 void store()
68 {
69 qDebug() << "Metadata asking storage framework for a socket";
70 auto json_data = to_json();
71 auto n_bytes = json_data.size();
72
73 connections_.connect_future(
74 storage_->get_new_uploader(n_bytes, dir_, MANIFEST_FILE_NAME),
75 std::function<void(std::shared_ptr<Uploader> const&)>{
76 [this, json_data](std::shared_ptr<Uploader> const& uploader){
77 qDebug() << "Manifest uploader is" << static_cast<void*>(uploader.get());
78 if (uploader)
79 {
80 auto socket = uploader->socket();
81 socket->write(json_data);
82 connections_.connect_oneshot(
83 uploader.get(),
84 &Uploader::commit_finished,
85 std::function<void(bool)>{[this, uploader](bool success){
86 qDebug() << "Metadata commit finished";
87 if (!success)
88 {
89 finish_with_error(QStringLiteral("Error committing manifest file to storage-framework"));
90 }
91 else
92 {
93 uploader_committed_file_name_ = uploader->file_name();
94 finish();
95 }
96 }}
97 );
98 uploader->commit();
99 }
100 else
101 {
102 finish_with_error(QStringLiteral("Error retrieving uploader for manifest file from storage-framework"));
103 }
104 }
105 }
106 );
107 }
108
109 void read()
110 {
111 connections_.connect_future(
112 storage_->get_new_downloader(dir_, MANIFEST_FILE_NAME),
113 std::function<void(std::shared_ptr<Downloader> const&)>{
114 [this](std::shared_ptr<Downloader> const& downloader){
115 if (downloader)
116 {
117 auto socket = downloader->socket();
118 if (socket->atEnd())
119 {
120 if (!socket->waitForReadyRead(5000))
121 {
122 qWarning() << "Manifest socket was not ready to read after timeout";
123 }
124 }
125 auto json_content = socket->readAll();
126 from_json(json_content);
127 downloader->finish();
128 finish();
129 }
130 else
131 {
132 finish_with_error(QStringLiteral("Error retrieving downloader for manifest file from storage-framework"));
133 }
134 }
135 }
136 );
137 }
138
139 QVector<Metadata> get_entries()
140 {
141 return entries_;
142 }
143
144 QString error() const
145 {
146 return error_string_;
147 }
148
149 QByteArray to_json() const
150 {
151 QJsonArray json_array;
152 for (auto metadata : entries_)
153 {
154 json_array.append(metadata.json());
155 }
156 QJsonObject json_root;
157 json_root[ENTRIES_KEY] = json_array;
158 QJsonDocument doc(json_root);
159
160 return doc.toJson(QJsonDocument::Compact);
161 }
162
163 void from_json(QByteArray const & json)
164 {
165 auto doc_read = QJsonDocument::fromJson(json);
166
167 auto json_read_root = doc_read.object();
168 auto items = json_read_root[ENTRIES_KEY].toArray();
169
170 QVector<Metadata> read_metadata;
171 for( auto iter = items.begin(); iter != items.end(); ++iter)
172 {
173 entries_.push_back(Metadata((*iter).toObject()));
174 }
175 }
176
177private:
178
179 void finish_with_error(QString const & message)
180 {
181 error_string_ = message;
182 Q_EMIT(q_ptr->finished(false));
183 }
184
185 void finish()
186 {
187 error_string_ = "";
188 Q_EMIT(q_ptr->finished(true));
189 }
190
191 Manifest * const q_ptr;
192 QSharedPointer<StorageFrameworkClient> storage_;
193 QString dir_;
194
195 QVector<Metadata> entries_;
196 QString error_string_;
197 QString uploader_committed_file_name_;
198
199 ConnectionHelper connections_;
200};
201
202/***
203****
204***/
205
206Manifest::Manifest(QSharedPointer<StorageFrameworkClient> const & storage, QString const & dir, QObject * parent)
207 : QObject (parent)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: