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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charles Kerr (community) | Approve | ||
Review via email: mp+318388@code.launchpad.net |
Commit message
Description of the change
This is just to merge what's in devel (which has apparently already mostly been released to zesty/xenial+
To post a comment you must log in.
lp:keeper/devel
updated
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
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-08-26 09:30:11 +0000 |
3 | +++ CMakeLists.txt 2017-02-27 19:05:17 +0000 |
4 | @@ -272,7 +272,7 @@ |
5 | include(CTest) |
6 | enable_testing() |
7 | |
8 | -include(EnableCoverageReport) |
9 | +find_package(CoverageReport) |
10 | |
11 | add_subdirectory(data) |
12 | add_subdirectory(src) |
13 | |
14 | === modified file 'data/CMakeLists.txt' |
15 | --- data/CMakeLists.txt 2016-08-10 07:43:36 +0000 |
16 | +++ data/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
17 | @@ -6,6 +6,12 @@ |
18 | FOLDER_BACKUP_EXEC |
19 | ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-backup.sh |
20 | ) |
21 | + |
22 | +set( |
23 | + FOLDER_RESTORE_EXEC |
24 | + ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}/folder-restore.sh |
25 | +) |
26 | + |
27 | configure_file( |
28 | ${HELPER_REGISTRY_FILENAME}.in |
29 | ${HELPER_REGISTRY_FILENAME} |
30 | |
31 | === modified file 'data/helper-registry.json.in' |
32 | --- data/helper-registry.json.in 2016-08-09 04:20:33 +0000 |
33 | +++ data/helper-registry.json.in 2017-02-27 19:05:17 +0000 |
34 | @@ -4,5 +4,10 @@ |
35 | "@FOLDER_BACKUP_EXEC@", |
36 | "${subtype}" |
37 | ] |
38 | - } |
39 | + , |
40 | + "restore-urls": [ |
41 | + "@FOLDER_RESTORE_EXEC@", |
42 | + "${subtype}" |
43 | + ] |
44 | + } |
45 | } |
46 | |
47 | === modified file 'debian/changelog' |
48 | --- debian/changelog 2016-09-15 19:20:14 +0000 |
49 | +++ debian/changelog 2017-02-27 19:05:17 +0000 |
50 | @@ -1,3 +1,17 @@ |
51 | +keeper (0.1.1-0ubuntu1) UNRELEASED; urgency=medium |
52 | + |
53 | + [ Ken Vandine ] |
54 | + * Update to handle the API/ABI break in ubuntu-app-launch. |
55 | + |
56 | + -- Rodney Dawes <rodney.dawes@canonical.com> Mon, 27 Feb 2017 13:46:45 -0500 |
57 | + |
58 | +keeper (0.1.0+17.04.20170213.1-0ubuntu1) zesty; urgency=medium |
59 | + |
60 | + [ Charles Kerr, Xavi Garcia, Xavi Garcia Mena ] |
61 | + * Adds integration tests for restore and restore cancellation. |
62 | + |
63 | + -- Xavi Garcia <xavi.garcia.mena@canonical.com> Mon, 13 Feb 2017 08:57:47 +0000 |
64 | + |
65 | keeper (0.1.0+16.10.20160915.3-0ubuntu1) yakkety; urgency=medium |
66 | |
67 | * Initial release. |
68 | |
69 | === modified file 'debian/control' |
70 | --- debian/control 2016-08-26 08:48:05 +0000 |
71 | +++ debian/control 2017-02-27 19:05:17 +0000 |
72 | @@ -9,7 +9,7 @@ |
73 | # for building the code: |
74 | libarchive-dev (>= 3.1.2), |
75 | libproperties-cpp-dev, |
76 | - libubuntu-app-launch2-dev (>= 0.9), |
77 | + libubuntu-app-launch3-dev, |
78 | storage-framework-client-dev, |
79 | libclick-0.4-dev, |
80 | uuid-dev, |
81 | @@ -45,6 +45,8 @@ |
82 | Depends: ${shlibs:Depends}, |
83 | ${misc:Depends}, |
84 | systemd | systemd-shim, |
85 | + tar, |
86 | + xz-utils |
87 | Description: Backup Tool |
88 | A backup/restore utility for Ubuntu |
89 | |
90 | @@ -53,6 +55,8 @@ |
91 | Depends: ${shlibs:Depends}, |
92 | ${misc:Depends}, |
93 | systemd | systemd-shim, |
94 | + tar, |
95 | + xz-utils |
96 | Description: Backup Tool |
97 | A backup/restore utility for Ubuntu (client application) |
98 | |
99 | |
100 | === modified file 'debian/keeper.install' |
101 | --- debian/keeper.install 2016-08-10 07:43:36 +0000 |
102 | +++ debian/keeper.install 2017-02-27 19:05:17 +0000 |
103 | @@ -1,6 +1,8 @@ |
104 | /usr/lib/*/keeper/folder-backup.sh |
105 | +/usr/lib/*/keeper/folder-restore.sh |
106 | /usr/lib/*/keeper/keeper-service |
107 | -/usr/lib/*/keeper/keeper-tar-create |
108 | +/usr/lib/*/keeper/keeper-tar |
109 | +/usr/lib/*/keeper/keeper-untar |
110 | /usr/lib/*/ubuntu-app-launch/backup-helper/exec-tool |
111 | /usr/share/keeper/helper-registry.json |
112 | /usr/share/dbus-1/services/com.canonical.keeper.service |
113 | |
114 | === modified file 'include/client/client.h' |
115 | --- include/client/client.h 2016-09-06 18:28:45 +0000 |
116 | +++ include/client/client.h 2017-02-27 19:05:17 +0000 |
117 | @@ -19,10 +19,13 @@ |
118 | |
119 | #pragma once |
120 | |
121 | +#include "keeper-errors.h" |
122 | + |
123 | #include <QObject> |
124 | #include <QScopedPointer> |
125 | #include <QStringList> |
126 | #include <QVariant> |
127 | +#include "keeper-items.h" |
128 | |
129 | struct KeeperClientPrivate; |
130 | |
131 | @@ -53,14 +56,22 @@ |
132 | |
133 | Q_INVOKABLE QString getBackupName(QString uuid); |
134 | Q_INVOKABLE void enableBackup(QString uuid, bool enabled); |
135 | - Q_INVOKABLE void startBackup(); |
136 | + Q_INVOKABLE void startBackup(QString const & storage); |
137 | + |
138 | + Q_INVOKABLE void enableRestore(QString uuid, bool enabled); |
139 | + Q_INVOKABLE void startRestore(QString const & storage); |
140 | + |
141 | + Q_INVOKABLE void cancel(); |
142 | |
143 | // C++ |
144 | public: |
145 | - QMap<QString, QVariantMap> getBackupChoices() const; |
146 | - void startBackup(QStringList const& uuids) const; |
147 | + keeper::Items getBackupChoices(keeper::Error & error) const; |
148 | + keeper::Items getRestoreChoices(QString const & storage, keeper::Error & error) const; |
149 | + void startBackup(QStringList const& uuids, QString const & storage) const; |
150 | + void startRestore(QStringList const& uuids, QString const & storage) const; |
151 | |
152 | - QMap<QString, QVariantMap> getState() const; |
153 | + keeper::Items getState() const; |
154 | + QStringList getStorageAccounts() const; |
155 | |
156 | Q_SIGNALS: |
157 | void statusChanged(); |
158 | @@ -68,6 +79,9 @@ |
159 | void readyToBackupChanged(); |
160 | void backupBusyChanged(); |
161 | |
162 | + void taskStatusChanged(QString const & displayName, QString const & status, double percentage, keeper::Error error); |
163 | + void finished(); |
164 | + |
165 | private Q_SLOTS: |
166 | void stateUpdated(); |
167 | |
168 | |
169 | === added file 'include/client/keeper-errors.h' |
170 | --- include/client/keeper-errors.h 1970-01-01 00:00:00 +0000 |
171 | +++ include/client/keeper-errors.h 2017-02-27 19:05:17 +0000 |
172 | @@ -0,0 +1,57 @@ |
173 | +/* |
174 | + * Copyright (C) 2016 Canonical, Ltd. |
175 | + * |
176 | + * This program is free software: you can redistribute it and/or modify it |
177 | + * under the terms of the GNU General Public License version 3, as published |
178 | + * by the Free Software Foundation. |
179 | + * |
180 | + * This program is distributed in the hope that it will be useful, but |
181 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
182 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
183 | + * PURPOSE. See the GNU General Public License for more details. |
184 | + * |
185 | + * You should have received a copy of the GNU General Public License along |
186 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
187 | + * |
188 | + * Authors: |
189 | + * Xavi Garcia Mena <xavi.garcia.mena@canonical.com> |
190 | + */ |
191 | + |
192 | +#pragma once |
193 | + |
194 | +#include <QDBusArgument> |
195 | +#include <QMetaType> |
196 | + |
197 | +namespace keeper |
198 | +{ |
199 | + |
200 | +enum class Error |
201 | +{ |
202 | + OK, |
203 | + UNKNOWN, |
204 | + HELPER_READ, |
205 | + HELPER_WRITE, |
206 | + HELPER_INACTIVITY_DETECTED, |
207 | + HELPER_SOCKET, |
208 | + HELPER_START_TIMEOUT, |
209 | + NO_HELPER_INFORMATION_IN_REGISTRY, |
210 | + HELPER_BAD_URL, |
211 | + MANIFEST_STORAGE, |
212 | + COMMITTING_DATA, |
213 | + |
214 | + CREATING_REMOTE_DIR, |
215 | + CREATING_REMOTE_FILE, |
216 | + READING_REMOTE_FILE, |
217 | + REMOTE_DIR_NOT_EXISTS, |
218 | + NO_REMOTE_ACCOUNTS, |
219 | + NO_REMOTE_ROOTS, |
220 | + ACCOUNT_NOT_FOUND |
221 | +}; |
222 | + |
223 | +Error convert_from_dbus_variant(const QVariant & value, bool *conversion_ok = nullptr); |
224 | +} // namespace keeper |
225 | + |
226 | +QDBusArgument &operator<<(QDBusArgument &argument, keeper::Error value); |
227 | +const QDBusArgument &operator>>(const QDBusArgument &argument, keeper::Error &val); |
228 | + |
229 | +Q_DECLARE_METATYPE(keeper::Error) |
230 | |
231 | === added file 'include/client/keeper-items.h' |
232 | --- include/client/keeper-items.h 1970-01-01 00:00:00 +0000 |
233 | +++ include/client/keeper-items.h 2017-02-27 19:05:17 +0000 |
234 | @@ -0,0 +1,102 @@ |
235 | +/* |
236 | + * Copyright (C) 2016 Canonical, Ltd. |
237 | + * |
238 | + * This program is free software: you can redistribute it and/or modify it |
239 | + * under the terms of the GNU General Public License version 3, as published |
240 | + * by the Free Software Foundation. |
241 | + * |
242 | + * This program is distributed in the hope that it will be useful, but |
243 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
244 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
245 | + * PURPOSE. See the GNU General Public License for more details. |
246 | + * |
247 | + * You should have received a copy of the GNU General Public License along |
248 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
249 | + * |
250 | + * Authors: |
251 | + * Xavi Garcia Mena <xavi.garcia.mena@canonical.com> |
252 | + */ |
253 | + |
254 | +#pragma once |
255 | + |
256 | +#include "client/keeper-errors.h" |
257 | + |
258 | +#include <QJsonObject> |
259 | + |
260 | +typedef QMap<QString, QVariantMap> QVariantDictMap; |
261 | + |
262 | +namespace keeper |
263 | +{ |
264 | + |
265 | +class Item : public QVariantMap |
266 | +{ |
267 | +public: |
268 | + Item(); |
269 | + ~Item(); |
270 | + explicit Item(QVariantMap const & values); |
271 | + |
272 | + // keys |
273 | + static QString const UUID_KEY; |
274 | + static QString const TYPE_KEY; |
275 | + static QString const SUBTYPE_KEY; |
276 | + static QString const NAME_KEY; |
277 | + static QString const PACKAGE_KEY; |
278 | + static QString const TITLE_KEY; |
279 | + static QString const VERSION_KEY; |
280 | + static QString const FILE_NAME_KEY; |
281 | + static QString const DIR_NAME_KEY; |
282 | + static QString const DISPLAY_NAME_KEY; |
283 | + static QString const STATUS_KEY; |
284 | + static QString const ERROR_KEY; |
285 | + static QString const PERCENT_DONE_KEY; |
286 | + static QString const SPEED_KEY; |
287 | + |
288 | + // values |
289 | + static QString const FOLDER_VALUE; |
290 | + static QString const SYSTEM_DATA_VALUE; |
291 | + static QString const APPLICATION_VALUE; |
292 | + |
293 | + |
294 | + // methods created for convenience |
295 | + bool has_property(QString const & property) const; |
296 | + template<typename T> T get_property(QString const & property, bool * valid) const; |
297 | + QVariant get_property_value(QString const & property) const; |
298 | + void set_property_value(QString const& property, QVariant const& value); |
299 | + |
300 | + // checks that the item is valid |
301 | + bool is_valid() const; |
302 | + |
303 | + // predefined properties |
304 | + QString get_uuid(bool *valid = nullptr) const; |
305 | + QString get_type(bool *valid = nullptr) const; |
306 | + QString get_display_name(bool *valid = nullptr) const; |
307 | + QString get_dir_name(bool *valid = nullptr) const; |
308 | + QString get_status(bool *valid = nullptr) const; |
309 | + double get_percent_done(bool *valid = nullptr) const; |
310 | + keeper::Error get_error(bool *valid = nullptr) const; |
311 | + QString get_file_name(bool *valid = nullptr) const; |
312 | + |
313 | + // d-bus |
314 | + static void registerMetaType(); |
315 | +}; |
316 | + |
317 | +class Items : public QMap<QString, Item> |
318 | +{ |
319 | +public: |
320 | + Items(); |
321 | + ~Items(); |
322 | + explicit Items(Error error); |
323 | + |
324 | + QStringList get_uuids() const; |
325 | + |
326 | + // d-bus |
327 | + static void registerMetaType(); |
328 | + |
329 | +private: |
330 | + Error error_ = Error::OK; |
331 | +}; |
332 | + |
333 | +} // namespace keeper |
334 | + |
335 | +Q_DECLARE_METATYPE(keeper::Item) |
336 | +Q_DECLARE_METATYPE(keeper::Items) |
337 | |
338 | === modified file 'include/helper/backup-helper.h' |
339 | --- include/helper/backup-helper.h 2016-09-15 16:02:54 +0000 |
340 | +++ include/helper/backup-helper.h 2017-02-27 19:05:17 +0000 |
341 | @@ -53,6 +53,7 @@ |
342 | int get_helper_socket() const; |
343 | QString to_string(Helper::State state) const override; |
344 | void set_state(State) override; |
345 | + QString get_uploader_committed_file_name() const; |
346 | protected: |
347 | void on_helper_finished() override; |
348 | |
349 | |
350 | === modified file 'include/helper/data-dir-registry.h' |
351 | --- include/helper/data-dir-registry.h 2016-08-09 05:44:25 +0000 |
352 | +++ include/helper/data-dir-registry.h 2017-02-27 19:05:17 +0000 |
353 | @@ -39,6 +39,8 @@ |
354 | |
355 | QStringList get_backup_helper_urls(Metadata const& metadata) override; |
356 | |
357 | + QStringList get_restore_helper_urls(Metadata const& metadata) override; |
358 | + |
359 | private: |
360 | class Impl; |
361 | friend class Impl; |
362 | |
363 | === modified file 'include/helper/helper.h' |
364 | --- include/helper/helper.h 2016-09-15 16:02:54 +0000 |
365 | +++ include/helper/helper.h 2017-02-27 19:05:17 +0000 |
366 | @@ -19,6 +19,7 @@ |
367 | |
368 | #pragma once |
369 | |
370 | +#include <client/keeper-errors.h> |
371 | #include <util/attributes.h> |
372 | |
373 | #include <QObject> |
374 | @@ -64,11 +65,12 @@ |
375 | virtual void start(QStringList const& urls); |
376 | virtual void stop(); |
377 | |
378 | - static constexpr int MAX_UAL_WAIT_TIME = 5000; |
379 | + static constexpr int MAX_UAL_WAIT_TIME = 10000; |
380 | |
381 | Q_SIGNALS: |
382 | void state_changed(Helper::State); |
383 | void percent_done_changed(float); |
384 | + void error(keeper::Error error); |
385 | |
386 | protected: |
387 | Helper(QString const & appid, const clock_func& clock=default_clock, QObject *parent=nullptr); |
388 | |
389 | === modified file 'include/helper/metadata.h' |
390 | --- include/helper/metadata.h 2016-09-06 18:51:30 +0000 |
391 | +++ include/helper/metadata.h 2017-02-27 19:05:17 +0000 |
392 | @@ -19,42 +19,21 @@ |
393 | |
394 | #pragma once |
395 | |
396 | +#include "client/keeper-items.h" |
397 | +#include <QJsonObject> |
398 | #include <QMap> |
399 | #include <QString> |
400 | |
401 | /** |
402 | - * Information about a backup |
403 | + * Information about a backup or restore item |
404 | */ |
405 | -class Metadata |
406 | +class Metadata : public keeper::Item |
407 | { |
408 | public: |
409 | |
410 | Metadata(); |
411 | + explicit Metadata(QJsonObject const & json_object); |
412 | Metadata(QString const& uuid, QString const& display_name); |
413 | |
414 | - // metadata keys |
415 | - static QString const TYPE_KEY; |
416 | - static QString const SUBTYPE_KEY; |
417 | - static QString const NAME_KEY; |
418 | - static QString const PACKAGE_KEY; |
419 | - static QString const TITLE_KEY; |
420 | - static QString const VERSION_KEY; |
421 | - |
422 | - // metadata values |
423 | - static QString const FOLDER_VALUE; |
424 | - static QString const SYSTEM_DATA_VALUE; |
425 | - static QString const APPLICATION_VALUE; |
426 | - |
427 | - QString uuid() const { return uuid_; } |
428 | - QString display_name() const { return display_name_; } |
429 | - bool get_property(QString const& property_name, QString& setme_value) const; |
430 | - void set_property(QString const& property_name, QString const& value); |
431 | - |
432 | - QMap<QString,QString> get_public_properties() const; |
433 | - |
434 | -private: |
435 | - |
436 | - QString uuid_; |
437 | - QString display_name_; |
438 | - QMap<QString,QString> properties_{}; |
439 | + QJsonObject json() const; |
440 | }; |
441 | |
442 | === modified file 'include/helper/registry.h' |
443 | --- include/helper/registry.h 2016-08-08 04:56:35 +0000 |
444 | +++ include/helper/registry.h 2017-02-27 19:05:17 +0000 |
445 | @@ -30,6 +30,7 @@ |
446 | Q_DISABLE_COPY(HelperRegistry) |
447 | |
448 | virtual QStringList get_backup_helper_urls(Metadata const& task) =0; |
449 | + virtual QStringList get_restore_helper_urls(Metadata const& task) =0; |
450 | |
451 | protected: |
452 | HelperRegistry() =default; |
453 | |
454 | === added file 'include/helper/restore-helper.h' |
455 | --- include/helper/restore-helper.h 1970-01-01 00:00:00 +0000 |
456 | +++ include/helper/restore-helper.h 2017-02-27 19:05:17 +0000 |
457 | @@ -0,0 +1,62 @@ |
458 | +/* |
459 | + * Copyright (C) 2016 Canonical, Ltd. |
460 | + * |
461 | + * This program is free software: you can redistribute it and/or modify it |
462 | + * under the terms of the GNU General Public License version 3, as published |
463 | + * by the Free Software Foundation. |
464 | + * |
465 | + * This program is distributed in the hope that it will be useful, but |
466 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
467 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
468 | + * PURPOSE. See the GNU General Public License for more details. |
469 | + * |
470 | + * You should have received a copy of the GNU General Public License along |
471 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
472 | + * |
473 | + * Authors: |
474 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
475 | + * Charles Kerr <charles.kerr@canonical.com> |
476 | + */ |
477 | + |
478 | +#pragma once |
479 | + |
480 | +#include "storage-framework/downloader.h" |
481 | +#include "helper/helper.h" // parent class |
482 | +#include "helper/registry.h" |
483 | + |
484 | +#include <QObject> |
485 | +#include <QScopedPointer> |
486 | +#include <QString> |
487 | + |
488 | +#include <memory> |
489 | + |
490 | +class RestoreHelperPrivate; |
491 | +class RestoreHelper final: public Helper |
492 | +{ |
493 | + Q_OBJECT |
494 | + Q_DECLARE_PRIVATE(RestoreHelper) |
495 | + |
496 | +public: |
497 | + RestoreHelper( |
498 | + QString const & appid, |
499 | + clock_func const & clock=Helper::default_clock, |
500 | + QObject * parent=nullptr |
501 | + ); |
502 | + virtual ~RestoreHelper(); |
503 | + Q_DISABLE_COPY(RestoreHelper) |
504 | + |
505 | + static constexpr int MAX_INACTIVITY_TIME = 15000; |
506 | + |
507 | + void set_downloader(std::shared_ptr<Downloader> const& downloader); |
508 | + |
509 | + void start(QStringList const& urls) override; |
510 | + void stop() override; |
511 | + int get_helper_socket() const; |
512 | + QString to_string(Helper::State state) const override; |
513 | + void set_state(State) override; |
514 | +protected: |
515 | + void on_helper_finished() override; |
516 | + |
517 | +private: |
518 | + QScopedPointer<RestoreHelperPrivate> const d_ptr; |
519 | +}; |
520 | |
521 | === modified file 'src/cli/CMakeLists.txt' |
522 | --- src/cli/CMakeLists.txt 2016-09-06 01:31:59 +0000 |
523 | +++ src/cli/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
524 | @@ -5,6 +5,9 @@ |
525 | |
526 | set(CLI_SOURCES |
527 | main.cpp |
528 | + command-line.cpp |
529 | + command-line-client.cpp |
530 | + command-line-client-view.cpp |
531 | ) |
532 | |
533 | add_executable( |
534 | @@ -19,6 +22,7 @@ |
535 | util |
536 | qdbus-stubs |
537 | ${SERVICE_DEVEL_SF_DEPS_LIBRARIES} |
538 | + ${KEEPER_CLIENT_LIB} |
539 | Qt5::Core |
540 | Qt5::DBus |
541 | ) |
542 | |
543 | === added file 'src/cli/command-line-client-view.cpp' |
544 | --- src/cli/command-line-client-view.cpp 1970-01-01 00:00:00 +0000 |
545 | +++ src/cli/command-line-client-view.cpp 2017-02-27 19:05:17 +0000 |
546 | @@ -0,0 +1,194 @@ |
547 | +/* |
548 | + * Copyright (C) 2016 Canonical, Ltd. |
549 | + * |
550 | + * This program is free software: you can redistribute it and/or modify it |
551 | + * under the terms of the GNU General Public License version 3, as published |
552 | + * by the Free Software Foundation. |
553 | + * |
554 | + * This program is distributed in the hope that it will be useful, but |
555 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
556 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
557 | + * PURPOSE. See the GNU General Public License for more details. |
558 | + * |
559 | + * You should have received a copy of the GNU General Public License along |
560 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
561 | + * |
562 | + * Authors: |
563 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
564 | + */ |
565 | +#include "command-line-client-view.h" |
566 | + |
567 | +#include <client/client.h> |
568 | + |
569 | +#include <iostream> |
570 | +#include <iomanip> |
571 | + |
572 | +CommandLineClientView::CommandLineClientView(QObject * parent) |
573 | + : QObject(parent) |
574 | +{ |
575 | + connect(&timer_status_, &QTimer::timeout, this, &CommandLineClientView::show_info); |
576 | + |
577 | + // TODO see if we can do this in a better way |
578 | + // This line is for the global progress status and percentage |
579 | + std::cout << std::endl; |
580 | +} |
581 | + |
582 | +void CommandLineClientView::progress_changed(double percentage) |
583 | +{ |
584 | + percentage_ = percentage * 100; |
585 | +} |
586 | + |
587 | +void CommandLineClientView::status_changed(QString const & status) |
588 | +{ |
589 | + if (status_ != status) |
590 | + { |
591 | + status_ = status; |
592 | + } |
593 | +} |
594 | + |
595 | +void CommandLineClientView::add_task(QString const & display_name, QString const & initial_status, double initial_percentage) |
596 | +{ |
597 | + tasks_strings_[display_name] = get_task_string(display_name, initial_status, initial_percentage, keeper::Error::OK); |
598 | + // TODO see if we can do this in a better way |
599 | + // We add a line per each backup task |
600 | + std::cout << std::endl; |
601 | +} |
602 | + |
603 | +void CommandLineClientView::clear_all_tasks() |
604 | +{ |
605 | + tasks_strings_.clear(); |
606 | +} |
607 | + |
608 | +void CommandLineClientView::start_printing_tasks() |
609 | +{ |
610 | + timer_status_.start(300); |
611 | +} |
612 | + |
613 | +void CommandLineClientView::clear_all() |
614 | +{ |
615 | + timer_status_.stop(); |
616 | + std::cout << std::endl; |
617 | +} |
618 | + |
619 | +void CommandLineClientView::print_sections(QStringList const & sections) |
620 | +{ |
621 | + for (auto const & section : sections) |
622 | + { |
623 | + std::cout << section.toStdString() << std::endl; |
624 | + } |
625 | +} |
626 | + |
627 | +void CommandLineClientView::print_error_message(QString const & error_message) |
628 | +{ |
629 | + std::cerr << error_message.toStdString() << std::endl; |
630 | +} |
631 | + |
632 | +void CommandLineClientView::show_info() |
633 | +{ |
634 | + // TODO Revisit this code to see if we can do this in a different way |
635 | + // Maybe using ncurses? |
636 | + |
637 | + // Rewind to the beginning |
638 | + std::cout << '\r' << std::flush; |
639 | + // For every backup task we go up 1 line |
640 | + for (auto i = 0; i < tasks_strings_.size(); ++i) |
641 | + { |
642 | + std::cout << "\e[A"; |
643 | + } |
644 | + // print the tasks |
645 | + for (auto iter = tasks_strings_.begin(); iter != tasks_strings_.end(); ++iter) |
646 | + { |
647 | + std::cout << (*iter).toStdString() << std::setfill(' ') << std::endl; |
648 | + } |
649 | + std::cout << '\r' << std::fixed << std::setw(30) << status_.toStdString() << std::setprecision(3) |
650 | + << std::setfill(' ') << " " << percentage_ << " % " << get_next_spin_char() << " " << std::flush; |
651 | +} |
652 | + |
653 | +char CommandLineClientView::get_next_spin_char() |
654 | +{ |
655 | + char cursor[4]={'/','-','\\','|'}; |
656 | + auto ret = cursor[spin_value_]; |
657 | + spin_value_ = (spin_value_ + 1) % 4; |
658 | + return ret; |
659 | +} |
660 | + |
661 | +QString CommandLineClientView::get_task_string(QString const & displayName, QString const & status, double percentage, keeper::Error error) |
662 | +{ |
663 | + |
664 | + if (error == keeper::Error::OK) |
665 | + return QStringLiteral("%1 %2 % %3").arg(displayName, 15).arg((percentage * 100), 10, 'f', 2, ' ').arg(status, -15); |
666 | + else |
667 | + return QStringLiteral("%1 %2 % %3 %4").arg(displayName, 15).arg((percentage * 100), 10, 'f', 2, ' ').arg(status, -15).arg(get_error_string(error)); |
668 | +} |
669 | + |
670 | +QString CommandLineClientView::get_error_string(keeper::Error error) |
671 | +{ |
672 | + QString ret; |
673 | + switch(error) |
674 | + { |
675 | + case keeper::Error::UNKNOWN: |
676 | + ret = QStringLiteral("Unknown error"); |
677 | + break; |
678 | + case keeper::Error::HELPER_BAD_URL: |
679 | + ret = QStringLiteral("Bad URL for keeper helper"); |
680 | + break; |
681 | + case keeper::Error::HELPER_INACTIVITY_DETECTED: |
682 | + ret = QStringLiteral("Inactivity detected in task"); |
683 | + break; |
684 | + case keeper::Error::HELPER_START_TIMEOUT: |
685 | + ret = QStringLiteral("Task failed to start"); |
686 | + break; |
687 | + case keeper::Error::HELPER_READ: |
688 | + ret = QStringLiteral("Read error"); |
689 | + break; |
690 | + case keeper::Error::HELPER_SOCKET: |
691 | + ret = QStringLiteral("Error creating internal socket"); |
692 | + break; |
693 | + case keeper::Error::HELPER_WRITE: |
694 | + ret = QStringLiteral("Write error"); |
695 | + break; |
696 | + case keeper::Error::MANIFEST_STORAGE: |
697 | + ret = QStringLiteral("Error storing manifest file"); |
698 | + break; |
699 | + case keeper::Error::NO_HELPER_INFORMATION_IN_REGISTRY: |
700 | + ret = QStringLiteral("No helper information in registry"); |
701 | + break; |
702 | + case keeper::Error::OK: |
703 | + ret = QStringLiteral("Success"); |
704 | + break; |
705 | + case keeper::Error::COMMITTING_DATA: |
706 | + ret = QStringLiteral("Error uploading data"); |
707 | + break; |
708 | + case keeper::Error::CREATING_REMOTE_DIR: |
709 | + ret = QStringLiteral("Error creating remote directory"); |
710 | + break; |
711 | + case keeper::Error::CREATING_REMOTE_FILE: |
712 | + ret = QStringLiteral("Error creating remote file"); |
713 | + break; |
714 | + case keeper::Error::READING_REMOTE_FILE: |
715 | + ret = QStringLiteral("Error reading remote file"); |
716 | + break; |
717 | + case keeper::Error::REMOTE_DIR_NOT_EXISTS: |
718 | + ret = QStringLiteral("Remote directory does not exist"); |
719 | + break; |
720 | + case keeper::Error::NO_REMOTE_ACCOUNTS: |
721 | + ret = QStringLiteral("No remote accounts were found"); |
722 | + break; |
723 | + case keeper::Error::NO_REMOTE_ROOTS: |
724 | + ret = QStringLiteral("No remote root accounts were found"); |
725 | + break; |
726 | + case keeper::Error::ACCOUNT_NOT_FOUND: |
727 | + ret = QStringLiteral("The storage account was not found"); |
728 | + break; |
729 | + } |
730 | + return ret; |
731 | +} |
732 | + |
733 | +void CommandLineClientView::on_task_state_changed(QString const & displayName, QString const & status, double percentage, keeper::Error error) |
734 | +{ |
735 | + auto iter = tasks_strings_.find(displayName); |
736 | + if (iter != tasks_strings_.end()) |
737 | + { |
738 | + tasks_strings_[displayName] = get_task_string(displayName, status, percentage, error); |
739 | + } |
740 | +} |
741 | |
742 | === added file 'src/cli/command-line-client-view.h' |
743 | --- src/cli/command-line-client-view.h 1970-01-01 00:00:00 +0000 |
744 | +++ src/cli/command-line-client-view.h 2017-02-27 19:05:17 +0000 |
745 | @@ -0,0 +1,60 @@ |
746 | +/* |
747 | + * Copyright (C) 2016 Canonical, Ltd. |
748 | + * |
749 | + * This program is free software: you can redistribute it and/or modify it |
750 | + * under the terms of the GNU General Public License version 3, as published |
751 | + * by the Free Software Foundation. |
752 | + * |
753 | + * This program is distributed in the hope that it will be useful, but |
754 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
755 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
756 | + * PURPOSE. See the GNU General Public License for more details. |
757 | + * |
758 | + * You should have received a copy of the GNU General Public License along |
759 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
760 | + * |
761 | + * Authors: |
762 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
763 | + */ |
764 | +#pragma once |
765 | + |
766 | +#include <client/keeper-errors.h> |
767 | + |
768 | +#include <QMap> |
769 | +#include <QObject> |
770 | +#include <QTimer> |
771 | + |
772 | +class CommandLineClientView : public QObject |
773 | +{ |
774 | + Q_OBJECT |
775 | +public: |
776 | + explicit CommandLineClientView(QObject * parent = nullptr); |
777 | + ~CommandLineClientView() = default; |
778 | + |
779 | + Q_DISABLE_COPY(CommandLineClientView) |
780 | + |
781 | + void progress_changed(double percentage); |
782 | + void status_changed(QString const & status); |
783 | + |
784 | + void add_task(QString const & display_name, QString const & initial_status, double initial_percentage); |
785 | + void clear_all_tasks(); |
786 | + void start_printing_tasks(); |
787 | + void clear_all(); |
788 | + void print_sections(QStringList const & sections); |
789 | + void print_error_message(QString const & error_message); |
790 | + QString get_error_string(keeper::Error error); |
791 | + |
792 | +public Q_SLOTS: |
793 | + void show_info(); |
794 | + void on_task_state_changed(QString const & displayName, QString const & status, double percentage, keeper::Error error); |
795 | + |
796 | +private: |
797 | + char get_next_spin_char(); |
798 | + QString get_task_string(QString const & displayName, QString const & status, double percentage, keeper::Error error); |
799 | + |
800 | + QString status_; |
801 | + QTimer timer_status_; |
802 | + double percentage_ = 0.0; |
803 | + int spin_value_ = 0; |
804 | + QMap<QString, QString> tasks_strings_; |
805 | +}; |
806 | |
807 | === added file 'src/cli/command-line-client.cpp' |
808 | --- src/cli/command-line-client.cpp 1970-01-01 00:00:00 +0000 |
809 | +++ src/cli/command-line-client.cpp 2017-02-27 19:05:17 +0000 |
810 | @@ -0,0 +1,250 @@ |
811 | +/* |
812 | + * Copyright (C) 2016 Canonical, Ltd. |
813 | + * |
814 | + * This program is free software: you can redistribute it and/or modify it |
815 | + * under the terms of the GNU General Public License version 3, as published |
816 | + * by the Free Software Foundation. |
817 | + * |
818 | + * This program is distributed in the hope that it will be useful, but |
819 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
820 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
821 | + * PURPOSE. See the GNU General Public License for more details. |
822 | + * |
823 | + * You should have received a copy of the GNU General Public License along |
824 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
825 | + * |
826 | + * Authors: |
827 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
828 | + */ |
829 | +#include "command-line-client.h" |
830 | +#include "command-line-client-view.h" |
831 | + |
832 | +#include <client/client.h> |
833 | + |
834 | +#include <QCoreApplication> |
835 | +#include <QDebug> |
836 | + |
837 | +#include <iostream> |
838 | +#include <iomanip> |
839 | + |
840 | +CommandLineClient::CommandLineClient(QObject * parent) |
841 | + : QObject(parent) |
842 | + , keeper_client_(new KeeperClient(this)) |
843 | + , view_(new CommandLineClientView(this)) |
844 | +{ |
845 | + connect(keeper_client_.data(), &KeeperClient::statusChanged, this, &CommandLineClient::on_status_changed); |
846 | + connect(keeper_client_.data(), &KeeperClient::progressChanged, this, &CommandLineClient::on_progress_changed); |
847 | + connect(keeper_client_.data(), &KeeperClient::finished, this, &CommandLineClient::on_keeper_client_finished); |
848 | + connect(keeper_client_.data(), &KeeperClient::taskStatusChanged, view_.data(), &CommandLineClientView::on_task_state_changed); |
849 | +} |
850 | + |
851 | +CommandLineClient::~CommandLineClient() = default; |
852 | + |
853 | +void CommandLineClient::run_list_sections(bool remote, QString const & storage) |
854 | +{ |
855 | + keeper::Items choices_values; |
856 | + keeper::Error error; |
857 | + if(!remote) |
858 | + { |
859 | + choices_values = keeper_client_->getBackupChoices(error); |
860 | + check_for_choices_error(error); |
861 | + list_backup_sections(choices_values); |
862 | + } |
863 | + else |
864 | + { |
865 | + choices_values = keeper_client_->getRestoreChoices(storage, error); |
866 | + check_for_choices_error(error); |
867 | + list_restore_sections(choices_values); |
868 | + } |
869 | +} |
870 | + |
871 | +void CommandLineClient::run_list_storage_accounts() |
872 | +{ |
873 | + list_storage_accounts(keeper_client_->getStorageAccounts()); |
874 | +} |
875 | + |
876 | +void CommandLineClient::run_backup(QStringList & sections, QString const & storage) |
877 | +{ |
878 | + auto unhandled_sections = sections; |
879 | + keeper::Error error; |
880 | + auto choices_values = keeper_client_->getBackupChoices(error); |
881 | + check_for_choices_error(error); |
882 | + QStringList uuids; |
883 | + |
884 | + auto uuids_choices = choices_values.get_uuids(); |
885 | + for(auto iter = uuids_choices.begin(); iter != uuids_choices.end() && unhandled_sections.size(); ++iter) |
886 | + { |
887 | + const auto& values = choices_values[(*iter)]; |
888 | + |
889 | + if (values.is_valid() && values.get_type() == keeper::Item::FOLDER_VALUE) |
890 | + { |
891 | + |
892 | + auto display_name = values.get_display_name(); |
893 | + auto index = unhandled_sections.indexOf(display_name); |
894 | + if (index != -1) |
895 | + { |
896 | + // we have to backup this section |
897 | + uuids << (*iter); |
898 | + unhandled_sections.removeAt(index); |
899 | + view_->add_task(display_name, "waiting", 0.0); |
900 | + } |
901 | + } |
902 | + } |
903 | + |
904 | + if (!unhandled_sections.isEmpty()) |
905 | + { |
906 | + QString error_message("The following sections were not found: \n"); |
907 | + for (auto const & section : unhandled_sections) |
908 | + { |
909 | + error_message += QStringLiteral("\t %1 \n").arg(section); |
910 | + } |
911 | + view_->print_error_message(error_message); |
912 | + exit(1); |
913 | + } |
914 | + |
915 | + for (auto const & uuid: uuids) |
916 | + { |
917 | + keeper_client_->enableBackup(uuid, true); |
918 | + } |
919 | + keeper_client_->startBackup(storage); |
920 | + view_->start_printing_tasks(); |
921 | +} |
922 | + |
923 | +void CommandLineClient::run_restore(QStringList & sections, QString const & storage) |
924 | +{ |
925 | + auto unhandled_sections = sections; |
926 | + keeper::Error error; |
927 | + |
928 | + auto choices_values = keeper_client_->getRestoreChoices(storage, error); |
929 | + check_for_choices_error(error); |
930 | + QStringList uuids; |
931 | + |
932 | + auto uuids_choices = choices_values.get_uuids(); |
933 | + for(auto iter = uuids_choices.begin(); iter != uuids_choices.end(); ++iter) |
934 | + { |
935 | + const auto& values = choices_values[(*iter)]; |
936 | + |
937 | + if (values.is_valid() && values.get_type() == keeper::Item::FOLDER_VALUE) |
938 | + { |
939 | + auto display_name = values.get_display_name(); |
940 | + auto dir_name = values.get_dir_name(); |
941 | + |
942 | + auto section_name = QStringLiteral("%1:%2").arg(display_name).arg(dir_name); |
943 | + auto index = unhandled_sections.indexOf(section_name); |
944 | + if (index != -1) |
945 | + { |
946 | + // we have to restore this section |
947 | + uuids << (*iter); |
948 | + unhandled_sections.removeAt(index); |
949 | + view_->add_task(display_name, "waiting", 0.0); |
950 | + } |
951 | + } |
952 | + } |
953 | + if (!unhandled_sections.isEmpty()) |
954 | + { |
955 | + QString error_message("The following sections were not found: \n"); |
956 | + for (auto const & section : unhandled_sections) |
957 | + { |
958 | + error_message += QStringLiteral("\t %1 \n").arg(section); |
959 | + } |
960 | + view_->print_error_message(error_message); |
961 | + exit(1); |
962 | + } |
963 | + |
964 | + for (auto const & uuid: uuids) |
965 | + { |
966 | + keeper_client_->enableRestore(uuid, true); |
967 | + } |
968 | + keeper_client_->startRestore(storage); |
969 | + view_->start_printing_tasks(); |
970 | +} |
971 | + |
972 | +void CommandLineClient::run_cancel() const |
973 | +{ |
974 | + keeper_client_->cancel(); |
975 | +} |
976 | + |
977 | +void CommandLineClient::list_backup_sections(keeper::Items const & choices_values) |
978 | +{ |
979 | + QStringList sections; |
980 | + for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
981 | + { |
982 | + if ((*iter).is_valid() && (*iter).get_type() == keeper::Item::FOLDER_VALUE) |
983 | + { |
984 | + sections << (*iter).get_display_name(); |
985 | + } |
986 | + } |
987 | + view_->print_sections(sections); |
988 | +} |
989 | + |
990 | +void CommandLineClient::list_restore_sections(keeper::Items const & choices_values) |
991 | +{ |
992 | + QMap<QString, QList<keeper::Item>> values_per_dir; |
993 | + |
994 | + for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
995 | + { |
996 | + if ((*iter).is_valid() && (*iter).get_type() == keeper::Item::FOLDER_VALUE) |
997 | + { |
998 | + auto dir_name = (*iter).get_dir_name(); |
999 | + if (!dir_name.isEmpty()) |
1000 | + { |
1001 | + values_per_dir[dir_name].push_back((*iter)); |
1002 | + } |
1003 | + } |
1004 | + } |
1005 | + |
1006 | + QStringList sections; |
1007 | + for(auto iter = values_per_dir.begin(); iter != values_per_dir.end(); ++iter) |
1008 | + { |
1009 | + for(auto iter_items = (*iter).begin(); iter_items != (*iter).end(); ++iter_items) |
1010 | + { |
1011 | + const auto& values = (*iter_items); |
1012 | + sections << QStringLiteral("%1:%2").arg(values.get_display_name()).arg(iter.key()); |
1013 | + } |
1014 | + sections << ""; |
1015 | + } |
1016 | + view_->print_sections(sections); |
1017 | +} |
1018 | + |
1019 | +void CommandLineClient::list_storage_accounts(QStringList const & accounts) |
1020 | +{ |
1021 | + view_->print_sections(accounts); |
1022 | +} |
1023 | + |
1024 | +void CommandLineClient::on_progress_changed() |
1025 | +{ |
1026 | + view_->progress_changed(keeper_client_->progress()); |
1027 | +} |
1028 | + |
1029 | +void CommandLineClient::on_status_changed() |
1030 | +{ |
1031 | + view_->status_changed(keeper_client_->status()); |
1032 | +} |
1033 | + |
1034 | +void CommandLineClient::on_keeper_client_finished() |
1035 | +{ |
1036 | + QCoreApplication::processEvents(); |
1037 | + view_->show_info(); |
1038 | + view_->clear_all(); |
1039 | + QCoreApplication::exit(0); |
1040 | +} |
1041 | + |
1042 | +bool CommandLineClient::find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value) |
1043 | +{ |
1044 | + auto iter = choice.find(id); |
1045 | + if (iter == choice.end()) |
1046 | + return false; |
1047 | + value = (*iter); |
1048 | + return true; |
1049 | +} |
1050 | + |
1051 | +void CommandLineClient::check_for_choices_error(keeper::Error error) |
1052 | +{ |
1053 | + if (error != keeper::Error::OK) |
1054 | + { |
1055 | + // an error occurred |
1056 | + auto error_message = QStringLiteral("Error obtaining keeper choices: %1").arg(view_->get_error_string(error)); |
1057 | + view_->print_error_message(error_message); |
1058 | + return; |
1059 | + } |
1060 | +} |
1061 | |
1062 | === added file 'src/cli/command-line-client.h' |
1063 | --- src/cli/command-line-client.h 1970-01-01 00:00:00 +0000 |
1064 | +++ src/cli/command-line-client.h 2017-02-27 19:05:17 +0000 |
1065 | @@ -0,0 +1,58 @@ |
1066 | +/* |
1067 | + * Copyright (C) 2016 Canonical, Ltd. |
1068 | + * |
1069 | + * This program is free software: you can redistribute it and/or modify it |
1070 | + * under the terms of the GNU General Public License version 3, as published |
1071 | + * by the Free Software Foundation. |
1072 | + * |
1073 | + * This program is distributed in the hope that it will be useful, but |
1074 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1075 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1076 | + * PURPOSE. See the GNU General Public License for more details. |
1077 | + * |
1078 | + * You should have received a copy of the GNU General Public License along |
1079 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1080 | + * |
1081 | + * Authors: |
1082 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
1083 | + */ |
1084 | +#pragma once |
1085 | + |
1086 | +#include <QMap> |
1087 | +#include <QObject> |
1088 | +#include <QScopedPointer> |
1089 | +#include <QTimer> |
1090 | +#include "../../include/client/keeper-items.h" |
1091 | + |
1092 | +class KeeperClient; |
1093 | +class CommandLineClientView; |
1094 | + |
1095 | +class CommandLineClient : public QObject |
1096 | +{ |
1097 | + Q_OBJECT |
1098 | +public: |
1099 | + explicit CommandLineClient(QObject * parent = nullptr); |
1100 | + ~CommandLineClient(); |
1101 | + |
1102 | + Q_DISABLE_COPY(CommandLineClient) |
1103 | + |
1104 | + void run_list_sections(bool remote, QString const & storage = ""); |
1105 | + void run_list_storage_accounts(); |
1106 | + void run_backup(QStringList & sections, QString const & storage); |
1107 | + void run_restore(QStringList & sections, QString const & storage); |
1108 | + void run_cancel() const; |
1109 | + |
1110 | +private Q_SLOTS: |
1111 | + void on_progress_changed(); |
1112 | + void on_status_changed(); |
1113 | + void on_keeper_client_finished(); |
1114 | + |
1115 | +private: |
1116 | + bool find_choice_value(QVariantMap const & choice, QString const & id, QVariant & value); |
1117 | + void list_backup_sections(keeper::Items const & choices); |
1118 | + void list_restore_sections(keeper::Items const & choices); |
1119 | + void list_storage_accounts(QStringList const & accounts); |
1120 | + void check_for_choices_error(keeper::Error error); |
1121 | + QScopedPointer<KeeperClient> keeper_client_; |
1122 | + QScopedPointer<CommandLineClientView> view_; |
1123 | +}; |
1124 | |
1125 | === added file 'src/cli/command-line.cpp' |
1126 | --- src/cli/command-line.cpp 1970-01-01 00:00:00 +0000 |
1127 | +++ src/cli/command-line.cpp 2017-02-27 19:05:17 +0000 |
1128 | @@ -0,0 +1,234 @@ |
1129 | +/* |
1130 | + * Copyright (C) 2016 Canonical, Ltd. |
1131 | + * |
1132 | + * This program is free software: you can redistribute it and/or modify it |
1133 | + * under the terms of the GNU General Public License version 3, as published |
1134 | + * by the Free Software Foundation. |
1135 | + * |
1136 | + * This program is distributed in the hope that it will be useful, but |
1137 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1138 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1139 | + * PURPOSE. See the GNU General Public License for more details. |
1140 | + * |
1141 | + * You should have received a copy of the GNU General Public License along |
1142 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1143 | + * |
1144 | + * Authors: |
1145 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
1146 | + */ |
1147 | +#include "command-line.h" |
1148 | + |
1149 | +#include <QCommandLineParser> |
1150 | +#include <QDebug> |
1151 | + |
1152 | +#include <iostream> |
1153 | + |
1154 | +namespace |
1155 | +{ |
1156 | + // arguments |
1157 | + constexpr const char ARGUMENT_LIST_SECTIONS[] = "list-sections"; |
1158 | + constexpr const char ARGUMENT_LIST_STORAGE_ACCOUNTS[] = "list-storage-configs"; |
1159 | + constexpr const char ARGUMENT_BACKUP[] = "backup"; |
1160 | + constexpr const char ARGUMENT_RESTORE[] = "restore"; |
1161 | + |
1162 | + // argument descriptions |
1163 | + constexpr const char ARGUMENT_LIST_SECTIONS_DESCRIPTION[] = "List the sections available to backup"; |
1164 | + constexpr const char ARGUMENT_LIST_STORAGE_ACCOUNTS_DESCRIPTION[] = "List the available storage accounts"; |
1165 | + constexpr const char ARGUMENT_BACKUP_DESCRIPTION[] = "Starts a backup"; |
1166 | + constexpr const char ARGUMENT_RESTORE_DESCRIPTION[] = "Starts a restore"; |
1167 | + |
1168 | + // options |
1169 | + constexpr const char OPTION_STORAGE[] = "storage"; |
1170 | + constexpr const char OPTION_SECTIONS[] = "sections"; |
1171 | + |
1172 | + // option descriptions |
1173 | + constexpr const char OPTION_STORAGE_DESCRIPTION[] = "Defines the available storage to use. Pass 'default' to use the default one"; |
1174 | + constexpr const char OPTION_SECTIONS_DESCRIPTION[] = "Lists the sections to backup or restore"; |
1175 | +} |
1176 | + |
1177 | +CommandLineParser::CommandLineParser() |
1178 | + : parser_(new QCommandLineParser) |
1179 | +{ |
1180 | + parser_->setApplicationDescription("Keeper command line client"); |
1181 | + parser_->addHelpOption(); |
1182 | + parser_->addVersionOption(); |
1183 | + parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION)); |
1184 | + parser_->addPositionalArgument(ARGUMENT_LIST_STORAGE_ACCOUNTS, QCoreApplication::translate("main", ARGUMENT_LIST_STORAGE_ACCOUNTS_DESCRIPTION)); |
1185 | + parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION)); |
1186 | + parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION)); |
1187 | +} |
1188 | + |
1189 | +bool CommandLineParser::parse(QStringList const & arguments, QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
1190 | +{ |
1191 | + parser_->parse(arguments); |
1192 | + const QStringList args = parser_->positionalArguments(); |
1193 | + if (!check_number_of_args(args)) |
1194 | + { |
1195 | + return false; |
1196 | + } |
1197 | + |
1198 | + if (args.size() == 1) |
1199 | + { |
1200 | + // if something fails at the process call the process exists |
1201 | + if (args.at(0) == ARGUMENT_LIST_SECTIONS) |
1202 | + { |
1203 | + return handle_list_sections(app, cmd_args); |
1204 | + } |
1205 | + else if (args.at(0) == ARGUMENT_LIST_STORAGE_ACCOUNTS) |
1206 | + { |
1207 | + return handle_list_storage_accounts(app, cmd_args); |
1208 | + } |
1209 | + else if (args.at(0) == ARGUMENT_BACKUP) |
1210 | + { |
1211 | + return handle_backup(app, cmd_args); |
1212 | + } |
1213 | + else if (args.at(0) == ARGUMENT_RESTORE) |
1214 | + { |
1215 | + return handle_restore(app, cmd_args); |
1216 | + } |
1217 | + else |
1218 | + { |
1219 | + std::cerr << "Bad argument." << std::endl; |
1220 | + std::cerr << parser_->errorText().toStdString() << std::endl; |
1221 | + exit(1); |
1222 | + } |
1223 | + } |
1224 | + else |
1225 | + { |
1226 | + qDebug() << "More or none arguments"; |
1227 | + // maybe we have the version or help options |
1228 | + parser_->process(app); |
1229 | + } |
1230 | + |
1231 | + return false; |
1232 | +} |
1233 | + |
1234 | +bool CommandLineParser::handle_list_sections(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
1235 | +{ |
1236 | + parser_->clearPositionalArguments(); |
1237 | + parser_->addPositionalArgument(ARGUMENT_LIST_SECTIONS, QCoreApplication::translate("main", ARGUMENT_LIST_SECTIONS_DESCRIPTION)); |
1238 | + |
1239 | + parser_->addOptions({ |
1240 | + {{"r", OPTION_STORAGE}, |
1241 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION), |
1242 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION) |
1243 | + }, |
1244 | + }); |
1245 | + parser_->process(app); |
1246 | + |
1247 | + // it didn't exit... we're good |
1248 | + cmd_args.sections.clear(); |
1249 | + cmd_args.storage.clear(); |
1250 | + if (parser_->isSet(OPTION_STORAGE)) |
1251 | + { |
1252 | + cmd_args.cmd = CommandLineParser::Command::LIST_REMOTE_SECTIONS; |
1253 | + cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE)); |
1254 | + } |
1255 | + else |
1256 | + { |
1257 | + cmd_args.cmd = CommandLineParser::Command::LIST_LOCAL_SECTIONS; |
1258 | + } |
1259 | + |
1260 | + return true; |
1261 | +} |
1262 | + |
1263 | +bool CommandLineParser::handle_list_storage_accounts(QCoreApplication const & app, CommandArgs & cmd_args) |
1264 | +{ |
1265 | + parser_->process(app); |
1266 | + // it didn't exit... we're good |
1267 | + cmd_args.sections.clear(); |
1268 | + cmd_args.storage.clear(); |
1269 | + cmd_args.cmd = CommandLineParser::Command::LIST_STORAGE_ACCOUNTS; |
1270 | + |
1271 | + return true; |
1272 | +} |
1273 | + |
1274 | +bool CommandLineParser::handle_backup(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
1275 | +{ |
1276 | + parser_->clearPositionalArguments(); |
1277 | + parser_->addPositionalArgument(ARGUMENT_BACKUP, QCoreApplication::translate("main", ARGUMENT_BACKUP_DESCRIPTION)); |
1278 | + |
1279 | + parser_->addOptions({ |
1280 | + {{"s", OPTION_SECTIONS}, |
1281 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION), |
1282 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION) |
1283 | + }, |
1284 | + {{"r", OPTION_STORAGE}, |
1285 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION), |
1286 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION) |
1287 | + }, |
1288 | + }); |
1289 | + parser_->process(app); |
1290 | + |
1291 | + // it didn't exit... we're good |
1292 | + cmd_args.sections.clear(); |
1293 | + cmd_args.storage.clear(); |
1294 | + cmd_args.cmd = CommandLineParser::Command::BACKUP; |
1295 | + if (!parser_->isSet(OPTION_SECTIONS)) |
1296 | + { |
1297 | + std::cerr << "You need to specify some sections to run a backup." << std::endl; |
1298 | + return false; |
1299 | + } |
1300 | + if (parser_->isSet(OPTION_STORAGE)) |
1301 | + { |
1302 | + cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE)); |
1303 | + } |
1304 | + cmd_args.sections = parser_->value(OPTION_SECTIONS).split(','); |
1305 | + |
1306 | + return true; |
1307 | +} |
1308 | + |
1309 | +bool CommandLineParser::handle_restore(QCoreApplication const & app, CommandLineParser::CommandArgs & cmd_args) |
1310 | +{ |
1311 | + parser_->clearPositionalArguments(); |
1312 | + parser_->addPositionalArgument(ARGUMENT_RESTORE, QCoreApplication::translate("main", ARGUMENT_RESTORE_DESCRIPTION)); |
1313 | + |
1314 | + parser_->addOptions({ |
1315 | + {{"s", OPTION_SECTIONS}, |
1316 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION), |
1317 | + QCoreApplication::translate("main", OPTION_SECTIONS_DESCRIPTION) |
1318 | + }, |
1319 | + {{"r", OPTION_STORAGE}, |
1320 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION), |
1321 | + QCoreApplication::translate("main", OPTION_STORAGE_DESCRIPTION) |
1322 | + }, |
1323 | + }); |
1324 | + parser_->process(app); |
1325 | + |
1326 | + // it didn't exit... we're good |
1327 | + cmd_args.sections.clear(); |
1328 | + cmd_args.storage.clear(); |
1329 | + cmd_args.cmd = CommandLineParser::Command::RESTORE; |
1330 | + if (!parser_->isSet(OPTION_SECTIONS)) |
1331 | + { |
1332 | + std::cerr << "You need to specify some sections to run a restore." << std::endl; |
1333 | + return false; |
1334 | + } |
1335 | + if (parser_->isSet(OPTION_STORAGE)) |
1336 | + { |
1337 | + cmd_args.storage = get_storage_string(parser_->value(OPTION_STORAGE)); |
1338 | + } |
1339 | + cmd_args.sections = parser_->value(OPTION_SECTIONS).split(','); |
1340 | + |
1341 | + return true; |
1342 | +} |
1343 | + |
1344 | +bool CommandLineParser::check_number_of_args(QStringList const & args) |
1345 | +{ |
1346 | + if (args.size() > 1) |
1347 | + { |
1348 | + std::cerr << "Please, pass only one argument." << std::endl; |
1349 | + std::cerr << parser_->helpText().toStdString() << std::endl; |
1350 | + return false; |
1351 | + } |
1352 | + return true; |
1353 | +} |
1354 | + |
1355 | +QString CommandLineParser::get_storage_string(QString const & value) |
1356 | +{ |
1357 | + if (value == "default") |
1358 | + { |
1359 | + return QString(); |
1360 | + } |
1361 | + return value; |
1362 | +} |
1363 | |
1364 | === added file 'src/cli/command-line.h' |
1365 | --- src/cli/command-line.h 1970-01-01 00:00:00 +0000 |
1366 | +++ src/cli/command-line.h 2017-02-27 19:05:17 +0000 |
1367 | @@ -0,0 +1,55 @@ |
1368 | +/* |
1369 | + * Copyright (C) 2016 Canonical, Ltd. |
1370 | + * |
1371 | + * This program is free software: you can redistribute it and/or modify it |
1372 | + * under the terms of the GNU General Public License version 3, as published |
1373 | + * by the Free Software Foundation. |
1374 | + * |
1375 | + * This program is distributed in the hope that it will be useful, but |
1376 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1377 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1378 | + * PURPOSE. See the GNU General Public License for more details. |
1379 | + * |
1380 | + * You should have received a copy of the GNU General Public License along |
1381 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1382 | + * |
1383 | + * Authors: |
1384 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
1385 | + */ |
1386 | +#pragma once |
1387 | + |
1388 | +#include <QCoreApplication> |
1389 | +#include <QSharedPointer> |
1390 | + |
1391 | +class QCommandLineParser; |
1392 | + |
1393 | +class CommandLineParser |
1394 | +{ |
1395 | +public: |
1396 | + Q_ENUMS(Command) |
1397 | + enum class Command {LIST_LOCAL_SECTIONS, LIST_REMOTE_SECTIONS, LIST_STORAGE_ACCOUNTS, BACKUP, RESTORE}; |
1398 | + struct CommandArgs |
1399 | + { |
1400 | + Command cmd; |
1401 | + QStringList sections; |
1402 | + QString storage; |
1403 | + }; |
1404 | + |
1405 | + CommandLineParser(); |
1406 | + ~CommandLineParser() = default; |
1407 | + Q_DISABLE_COPY(CommandLineParser) |
1408 | + |
1409 | + bool parse(QStringList const & arguments, QCoreApplication const & app, CommandArgs & cmd_args); |
1410 | + |
1411 | +private: |
1412 | + bool handle_list_sections(QCoreApplication const & app, CommandArgs & cmd_args); |
1413 | + bool handle_list_storage_accounts(QCoreApplication const & app, CommandArgs & cmd_args); |
1414 | + bool handle_backup(QCoreApplication const & app, CommandArgs & cmd_args); |
1415 | + bool handle_restore(QCoreApplication const & app, CommandArgs & cmd_args); |
1416 | + |
1417 | + bool check_number_of_args(QStringList const & args); |
1418 | + |
1419 | + QString get_storage_string(QString const & value); |
1420 | + |
1421 | + QSharedPointer<QCommandLineParser> parser_; |
1422 | +}; |
1423 | |
1424 | === modified file 'src/cli/main.cpp' |
1425 | --- src/cli/main.cpp 2016-08-30 14:16:19 +0000 |
1426 | +++ src/cli/main.cpp 2017-02-27 19:05:17 +0000 |
1427 | @@ -17,9 +17,12 @@ |
1428 | * Charles Kerr <charles.kerr@canonical.com> |
1429 | * Xavi Garcia <xavi.garcia.mena@canonical.com> |
1430 | */ |
1431 | +#include "command-line.h" |
1432 | +#include "command-line-client.h" |
1433 | |
1434 | #include <dbus-types.h> |
1435 | #include <util/logging.h> |
1436 | +#include "util/unix-signal-handler.h" |
1437 | |
1438 | #include <keeper_user_interface.h> |
1439 | |
1440 | @@ -29,6 +32,8 @@ |
1441 | #include <libintl.h> |
1442 | #include <cstdlib> |
1443 | #include <ctime> |
1444 | +#include <iostream> |
1445 | + |
1446 | |
1447 | int |
1448 | main(int argc, char **argv) |
1449 | @@ -37,60 +42,49 @@ |
1450 | |
1451 | QCoreApplication app(argc, argv); |
1452 | DBusTypes::registerMetaTypes(); |
1453 | -// Variant::registerMetaTypes(); |
1454 | std::srand(unsigned(std::time(nullptr))); |
1455 | |
1456 | + util::UnixSignalHandler handler([]{ |
1457 | + CommandLineClient client; |
1458 | + client.run_cancel(); |
1459 | + }); |
1460 | + handler.setupUnixSignalHandlers(); |
1461 | + |
1462 | // boilerplate locale |
1463 | bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); |
1464 | setlocale(LC_ALL, ""); |
1465 | bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); |
1466 | textdomain(GETTEXT_PACKAGE); |
1467 | |
1468 | - if (argc == 2 && QString("--print-address") == argv[1]) |
1469 | - { |
1470 | - qDebug() << QDBusConnection::sessionBus().baseService(); |
1471 | - } |
1472 | - |
1473 | - qDebug() << "Argc =" << argc; |
1474 | - if (argc == 2 && QString("--use-uuids") == argv[1]) |
1475 | - { |
1476 | - QScopedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser( |
1477 | - DBusTypes::KEEPER_SERVICE, |
1478 | - DBusTypes::KEEPER_USER_PATH, |
1479 | - QDBusConnection::sessionBus() |
1480 | - ) ); |
1481 | - QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices"); |
1482 | - if (!choices.isValid()) |
1483 | - { |
1484 | - qWarning() << "Error getting backup choices:" << choices.error().message(); |
1485 | - } |
1486 | - |
1487 | - QStringList uuids; |
1488 | - auto choices_values = choices.value(); |
1489 | - for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter) |
1490 | - { |
1491 | - const auto& values = iter.value(); |
1492 | - auto iter_values = values.find("type"); |
1493 | - if (iter_values != values.end()) |
1494 | - { |
1495 | - if (iter_values.value().toString() == "folder") |
1496 | - { |
1497 | - qDebug() << "Adding uuid" << iter.key() << "with type:" << "folder"; |
1498 | - uuids << iter.key(); |
1499 | - } |
1500 | - } |
1501 | - } |
1502 | - |
1503 | - QDBusReply<void> backup_reply = user_iface->call("StartBackup", uuids); |
1504 | - |
1505 | - if (!backup_reply.isValid()) |
1506 | - { |
1507 | - qWarning() << "Error starting backup:" << backup_reply.error().message(); |
1508 | - } |
1509 | - } |
1510 | - else |
1511 | - { |
1512 | - qWarning() << "FIXME"; |
1513 | + QCoreApplication::setApplicationName("keeper"); |
1514 | + QCoreApplication::setApplicationVersion("1.0"); |
1515 | + |
1516 | + CommandLineParser parser; |
1517 | + CommandLineClient client; |
1518 | + CommandLineParser::CommandArgs cmd_args; |
1519 | + if (parser.parse(QCoreApplication::arguments(), app, cmd_args)) |
1520 | + { |
1521 | + switch(cmd_args.cmd) |
1522 | + { |
1523 | + case CommandLineParser::Command::LIST_LOCAL_SECTIONS: |
1524 | + client.run_list_sections(false); |
1525 | + exit(0); |
1526 | + break; |
1527 | + case CommandLineParser::Command::LIST_STORAGE_ACCOUNTS: |
1528 | + client.run_list_storage_accounts(); |
1529 | + exit(0); |
1530 | + break; |
1531 | + case CommandLineParser::Command::LIST_REMOTE_SECTIONS: |
1532 | + client.run_list_sections(true, cmd_args.storage); |
1533 | + exit(0); |
1534 | + break; |
1535 | + case CommandLineParser::Command::BACKUP: |
1536 | + client.run_backup(cmd_args.sections, cmd_args.storage); |
1537 | + break; |
1538 | + case CommandLineParser::Command::RESTORE: |
1539 | + client.run_restore(cmd_args.sections, cmd_args.storage); |
1540 | + break; |
1541 | + }; |
1542 | } |
1543 | |
1544 | |
1545 | |
1546 | === modified file 'src/client/CMakeLists.txt' |
1547 | --- src/client/CMakeLists.txt 2016-08-26 09:30:11 +0000 |
1548 | +++ src/client/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
1549 | @@ -1,8 +1,24 @@ |
1550 | add_subdirectory(qml-plugin) |
1551 | |
1552 | set( |
1553 | + KEEPER_ERRORS_LIB |
1554 | + keeper-errors-lib |
1555 | +) |
1556 | + |
1557 | +add_library( |
1558 | + ${KEEPER_ERRORS_LIB} |
1559 | + STATIC |
1560 | + keeper-errors.cpp |
1561 | + ${CMAKE_SOURCE_DIR}/include/client/keeper-errors.h |
1562 | + ${CMAKE_SOURCE_DIR}/include/client/keeper-items.h |
1563 | + items.cpp |
1564 | +) |
1565 | + |
1566 | +set( |
1567 | CLIENT_HEADERS |
1568 | ${CMAKE_SOURCE_DIR}/include/client/client.h |
1569 | + ${CMAKE_SOURCE_DIR}/include/client/keeper-errors.h |
1570 | + ${CMAKE_SOURCE_DIR}/include/client/keeper-items.h |
1571 | ) |
1572 | |
1573 | add_library( |
1574 | @@ -11,8 +27,14 @@ |
1575 | ${CLIENT_HEADERS} |
1576 | ) |
1577 | |
1578 | +set_target_properties(${KEEPER_CLIENT_LIB} PROPERTIES |
1579 | + AUTOMOC TRUE |
1580 | + LINK_FLAGS "-Wl,--no-undefined" |
1581 | +) |
1582 | + |
1583 | target_link_libraries( |
1584 | ${KEEPER_CLIENT_LIB} |
1585 | + ${KEEPER_ERRORS_LIB} |
1586 | qdbus-stubs |
1587 | Qt5::Core |
1588 | Qt5::DBus |
1589 | |
1590 | === modified file 'src/client/client.cpp' |
1591 | --- src/client/client.cpp 2016-08-26 08:48:05 +0000 |
1592 | +++ src/client/client.cpp 2017-02-27 19:05:17 +0000 |
1593 | @@ -22,34 +22,100 @@ |
1594 | #include <client/client.h> |
1595 | |
1596 | #include <qdbus-stubs/keeper_user_interface.h> |
1597 | +#include <qdbus-stubs/DBusPropertiesInterface.h> |
1598 | +#include <qdbus-stubs/dbus-types.h> |
1599 | |
1600 | struct KeeperClientPrivate final |
1601 | { |
1602 | Q_DISABLE_COPY(KeeperClientPrivate) |
1603 | |
1604 | - KeeperClientPrivate(QObject* parent) |
1605 | + enum class TasksMode { IDLE_MODE, BACKUP_MODE, RESTORE_MODE }; |
1606 | + |
1607 | + explicit KeeperClientPrivate(QObject* /* parent */) |
1608 | : userIface(new DBusInterfaceKeeperUser( |
1609 | DBusTypes::KEEPER_SERVICE, |
1610 | DBusTypes::KEEPER_USER_PATH, |
1611 | QDBusConnection::sessionBus() |
1612 | - )), |
1613 | - status(""), |
1614 | - progress(0), |
1615 | - readyToBackup(false), |
1616 | - backupBusy(false), |
1617 | - stateTimer(parent) |
1618 | + )) |
1619 | + , propertiesIface(new DBusPropertiesInterface( |
1620 | + DBusTypes::KEEPER_SERVICE, |
1621 | + DBusTypes::KEEPER_USER_PATH, |
1622 | + QDBusConnection::sessionBus() |
1623 | + )) |
1624 | { |
1625 | } |
1626 | |
1627 | ~KeeperClientPrivate() = default; |
1628 | |
1629 | + struct TaskStatus |
1630 | + { |
1631 | + QString status; |
1632 | + double percentage; |
1633 | + }; |
1634 | + |
1635 | + static bool stateIsFinal(QString const & stateString) |
1636 | + { |
1637 | + return (stateString == "complete" || stateString == "cancelled" || stateString == "failed"); |
1638 | + } |
1639 | + |
1640 | + bool checkAllTasksFinished(keeper::Items const & state) const |
1641 | + { |
1642 | + bool ret = true; |
1643 | + for (auto iter = state.begin(); ret && (iter != state.end()); ++iter) |
1644 | + { |
1645 | + auto statusString = (*iter).get_status(); |
1646 | + ret = stateIsFinal(statusString); |
1647 | + } |
1648 | + return ret; |
1649 | + } |
1650 | + |
1651 | + static keeper::Items getValue(QDBusMessage const & message, keeper::Error & error) |
1652 | + { |
1653 | + if (message.errorMessage().isEmpty()) |
1654 | + { |
1655 | + if (message.arguments().count() != 1) |
1656 | + { |
1657 | + error = keeper::Error::UNKNOWN; |
1658 | + return keeper::Items(); |
1659 | + } |
1660 | + |
1661 | + auto value = message.arguments().at(0); |
1662 | + if (value.typeName() != QStringLiteral("QDBusArgument")) |
1663 | + { |
1664 | + error = keeper::Error::UNKNOWN; |
1665 | + return keeper::Items(); |
1666 | + } |
1667 | + auto dbus_arg = value.value<QDBusArgument>(); |
1668 | + error = keeper::Error::OK; |
1669 | + keeper::Items ret; |
1670 | + dbus_arg >> ret; |
1671 | + return ret; |
1672 | + } |
1673 | + if (message.arguments().count() != 2) |
1674 | + { |
1675 | + error = keeper::Error::UNKNOWN; |
1676 | + return keeper::Items(); |
1677 | + } |
1678 | + |
1679 | + // pick up the error |
1680 | + bool valid; |
1681 | + error = keeper::convert_from_dbus_variant(message.arguments().at(1), &valid); |
1682 | + if (!valid) |
1683 | + { |
1684 | + error = keeper::Error::UNKNOWN; |
1685 | + } |
1686 | + return keeper::Items(); |
1687 | + } |
1688 | + |
1689 | QScopedPointer<DBusInterfaceKeeperUser> userIface; |
1690 | + QScopedPointer<DBusPropertiesInterface> propertiesIface; |
1691 | QString status; |
1692 | - QMap<QString, QVariantMap> backups; |
1693 | - double progress; |
1694 | - bool readyToBackup; |
1695 | - bool backupBusy; |
1696 | - QTimer stateTimer; |
1697 | + keeper::Items backups; |
1698 | + double progress = 0; |
1699 | + bool readyToBackup = false; |
1700 | + bool backupBusy = false; |
1701 | + QMap<QString, TaskStatus> taskStatus; |
1702 | + TasksMode mode = TasksMode::IDLE_MODE; |
1703 | }; |
1704 | |
1705 | KeeperClient::KeeperClient(QObject* parent) : |
1706 | @@ -60,13 +126,15 @@ |
1707 | |
1708 | // Store backups list locally with an additional "enabled" pair to keep track enabled states |
1709 | // TODO: We should be listening to a backupChoicesChanged signal to keep this list updated |
1710 | - d->backups = getBackupChoices(); |
1711 | + keeper::Error error; |
1712 | + d->backups = getBackupChoices(error); |
1713 | + |
1714 | for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1715 | { |
1716 | iter.value()["enabled"] = false; |
1717 | } |
1718 | |
1719 | - connect(&d->stateTimer, &QTimer::timeout, this, &KeeperClient::stateUpdated); |
1720 | + connect(d->propertiesIface.data(), &DBusPropertiesInterface::PropertiesChanged, this, &KeeperClient::stateUpdated); |
1721 | } |
1722 | |
1723 | KeeperClient::~KeeperClient() = default; |
1724 | @@ -77,7 +145,7 @@ |
1725 | for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1726 | { |
1727 | // TODO: We currently only support "folder" type backups |
1728 | - if (iter.value().value("type").toString() == "folder") |
1729 | + if (iter.value().get_type() == keeper::Item::FOLDER_VALUE) |
1730 | { |
1731 | returnList.append(iter.key()); |
1732 | } |
1733 | @@ -120,17 +188,19 @@ |
1734 | } |
1735 | } |
1736 | |
1737 | + d->taskStatus[uuid] = KeeperClientPrivate::TaskStatus{"", 0.0}; |
1738 | + |
1739 | Q_EMIT readyToBackupChanged(); |
1740 | } |
1741 | |
1742 | -void KeeperClient::startBackup() |
1743 | +void KeeperClient::enableRestore(QString uuid, bool enabled) |
1744 | { |
1745 | - // TODO: Instead of polling for state, we should be listening to a stateChanged signal |
1746 | - if (!d->stateTimer.isActive()) |
1747 | - { |
1748 | - d->stateTimer.start(200); |
1749 | - } |
1750 | + // Until we re-design the client we treat restores as backups |
1751 | + enableBackup(uuid, enabled); |
1752 | +} |
1753 | |
1754 | +void KeeperClient::startBackup(QString const & storage) |
1755 | +{ |
1756 | // Determine which backups are enabled, and start only those |
1757 | QStringList backupList; |
1758 | for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1759 | @@ -143,8 +213,9 @@ |
1760 | |
1761 | if (!backupList.empty()) |
1762 | { |
1763 | - startBackup(backupList); |
1764 | + startBackup(backupList, storage); |
1765 | |
1766 | + d->mode = KeeperClientPrivate::TasksMode::BACKUP_MODE; |
1767 | d->status = "Preparing Backup..."; |
1768 | Q_EMIT statusChanged(); |
1769 | d->backupBusy = true; |
1770 | @@ -152,27 +223,60 @@ |
1771 | } |
1772 | } |
1773 | |
1774 | +void KeeperClient::startRestore(QString const & storage) |
1775 | +{ |
1776 | + // Determine which restores are enabled, and start only those |
1777 | + QStringList restoreList; |
1778 | + for(auto iter = d->backups.begin(); iter != d->backups.end(); ++iter) |
1779 | + { |
1780 | + if (iter.value().value("enabled").toBool()) |
1781 | + { |
1782 | + restoreList.append(iter.key()); |
1783 | + } |
1784 | + } |
1785 | + |
1786 | + if (!restoreList.empty()) |
1787 | + { |
1788 | + startRestore(restoreList, storage); |
1789 | + |
1790 | + d->mode = KeeperClientPrivate::TasksMode::RESTORE_MODE; |
1791 | + d->status = "Preparing Restore..."; |
1792 | + Q_EMIT statusChanged(); |
1793 | + d->backupBusy = true; |
1794 | + Q_EMIT backupBusyChanged(); |
1795 | + } |
1796 | +} |
1797 | + |
1798 | +void KeeperClient::cancel() |
1799 | +{ |
1800 | + QDBusReply<void> cancelReply = d->userIface->call("Cancel"); |
1801 | + |
1802 | + if (!cancelReply.isValid()) |
1803 | + { |
1804 | + qWarning() << "Error canceling" << cancelReply.error().message(); |
1805 | + } |
1806 | +} |
1807 | + |
1808 | QString KeeperClient::getBackupName(QString uuid) |
1809 | { |
1810 | - return d->backups.value(uuid).value("display-name").toString(); |
1811 | -} |
1812 | - |
1813 | -QMap<QString, QVariantMap> KeeperClient::getBackupChoices() const |
1814 | -{ |
1815 | - QDBusReply<QMap<QString, QVariantMap>> choices = d->userIface->call("GetBackupChoices"); |
1816 | - |
1817 | - if (!choices.isValid()) |
1818 | - { |
1819 | - qWarning() << "Error getting backup choices:" << choices.error().message(); |
1820 | - return QMap<QString, QVariantMap>(); |
1821 | - } |
1822 | - |
1823 | - return choices.value(); |
1824 | -} |
1825 | - |
1826 | -void KeeperClient::startBackup(const QStringList& uuids) const |
1827 | -{ |
1828 | - QDBusReply<void> backupReply = d->userIface->call("StartBackup", uuids); |
1829 | + return d->backups.value(uuid).get_display_name(); |
1830 | +} |
1831 | + |
1832 | +keeper::Items KeeperClient::getBackupChoices(keeper::Error & error) const |
1833 | +{ |
1834 | + QDBusMessage choices = d->userIface->call("GetBackupChoices"); |
1835 | + return KeeperClientPrivate::getValue(choices, error); |
1836 | +} |
1837 | + |
1838 | +keeper::Items KeeperClient::getRestoreChoices(QString const & storage, keeper::Error & error) const |
1839 | +{ |
1840 | + QDBusMessage choices = d->userIface->call("GetRestoreChoices", storage); |
1841 | + return KeeperClientPrivate::getValue(choices, error); |
1842 | +} |
1843 | + |
1844 | +void KeeperClient::startBackup(const QStringList& uuids, QString const & storage) const |
1845 | +{ |
1846 | + QDBusReply<void> backupReply = d->userIface->call("StartBackup", uuids, storage); |
1847 | |
1848 | if (!backupReply.isValid()) |
1849 | { |
1850 | @@ -180,51 +284,110 @@ |
1851 | } |
1852 | } |
1853 | |
1854 | -QMap<QString, QVariantMap> KeeperClient::getState() const |
1855 | +void KeeperClient::startRestore(const QStringList& uuids, QString const & storage) const |
1856 | +{ |
1857 | + QDBusReply<void> backupReply = d->userIface->call("StartRestore", uuids, storage); |
1858 | + |
1859 | + if (!backupReply.isValid()) |
1860 | + { |
1861 | + qWarning() << "Error starting restore:" << backupReply.error().message(); |
1862 | + } |
1863 | +} |
1864 | + |
1865 | +keeper::Items KeeperClient::getState() const |
1866 | { |
1867 | return d->userIface->state(); |
1868 | } |
1869 | |
1870 | +QStringList KeeperClient::getStorageAccounts() const |
1871 | +{ |
1872 | + QDBusPendingReply<QStringList> accountsReply = d->userIface->call("GetStorageAccounts"); |
1873 | + |
1874 | + accountsReply.waitForFinished(); |
1875 | + if (!accountsReply.isValid()) |
1876 | + { |
1877 | + qWarning() << "Error retrieving storage accounts:" << accountsReply.error().message(); |
1878 | + } |
1879 | + |
1880 | + return accountsReply.value(); |
1881 | +} |
1882 | + |
1883 | void KeeperClient::stateUpdated() |
1884 | { |
1885 | auto states = getState(); |
1886 | |
1887 | if (!states.empty()) |
1888 | { |
1889 | - // Calculate current total progress |
1890 | - // TODO: May be better to monitor each backup's progress separately instead of total |
1891 | - // to avoid irregular jumps in progress between larger and smaller backups |
1892 | + for (auto const & uuid : d->taskStatus.keys()) |
1893 | + { |
1894 | + auto iter_state = states.find(uuid); |
1895 | + if (iter_state == states.end()) |
1896 | + { |
1897 | + qWarning() << "State for uuid: " << uuid << " was not found"; |
1898 | + } |
1899 | + keeper::Item keeper_item((*iter_state)); |
1900 | + auto progress = keeper_item.get_percent_done(); |
1901 | + auto status = keeper_item.get_status(); |
1902 | + auto keeper_error = keeper_item.get_error(); |
1903 | + |
1904 | + auto current_state = d->taskStatus[uuid]; |
1905 | + if (current_state.status != status || current_state.percentage < progress) |
1906 | + { |
1907 | + d->taskStatus[uuid].status = status; |
1908 | + d->taskStatus[uuid].percentage = progress; |
1909 | + Q_EMIT(taskStatusChanged(keeper_item.get_display_name(), status, progress, keeper_error)); |
1910 | + } |
1911 | + } |
1912 | + |
1913 | double totalProgress = 0; |
1914 | for (auto const& state : states) |
1915 | { |
1916 | - totalProgress += state.value("percent-done").toDouble(); |
1917 | + keeper::Item keeper_item(state); |
1918 | + totalProgress += keeper_item.get_percent_done(); |
1919 | } |
1920 | |
1921 | d->progress = totalProgress / states.count(); |
1922 | Q_EMIT progressChanged(); |
1923 | |
1924 | + auto allTasksFinished = d->checkAllTasksFinished(states); |
1925 | // Update backup status |
1926 | + QString statusString; |
1927 | + if (d->mode == KeeperClientPrivate::TasksMode::BACKUP_MODE) |
1928 | + { |
1929 | + statusString = QStringLiteral("Backup"); |
1930 | + } |
1931 | + else if (d->mode == KeeperClientPrivate::TasksMode::RESTORE_MODE) |
1932 | + { |
1933 | + statusString = QStringLiteral("Restore"); |
1934 | + } |
1935 | if (d->progress > 0 && d->progress < 1) |
1936 | { |
1937 | - d->status = "Backup In Progress..."; |
1938 | - Q_EMIT statusChanged(); |
1939 | - |
1940 | - d->backupBusy = true; |
1941 | - Q_EMIT backupBusyChanged(); |
1942 | - } |
1943 | - else if (d->progress >= 1) |
1944 | - { |
1945 | - d->status = "Backup Complete"; |
1946 | + d->status = statusString + QStringLiteral(" In Progress..."); |
1947 | + Q_EMIT statusChanged(); |
1948 | + |
1949 | + d->backupBusy = true; |
1950 | + Q_EMIT backupBusyChanged(); |
1951 | + } |
1952 | + else if (d->progress >= 1 && !allTasksFinished) |
1953 | + { |
1954 | + d->status = statusString + QStringLiteral(" Finishing..."); |
1955 | + Q_EMIT statusChanged(); |
1956 | + |
1957 | + d->backupBusy = true; |
1958 | + Q_EMIT backupBusyChanged(); |
1959 | + } |
1960 | + else if (allTasksFinished) |
1961 | + { |
1962 | + d->status = statusString + QStringLiteral(" Complete"); |
1963 | Q_EMIT statusChanged(); |
1964 | |
1965 | d->backupBusy = false; |
1966 | Q_EMIT backupBusyChanged(); |
1967 | + } |
1968 | |
1969 | - // Stop state timer |
1970 | - if (d->stateTimer.isActive()) |
1971 | - { |
1972 | - d->stateTimer.stop(); |
1973 | - } |
1974 | + if (d->checkAllTasksFinished(states)) |
1975 | + { |
1976 | + Q_EMIT(finished()); |
1977 | } |
1978 | } |
1979 | } |
1980 | |
1981 | === added file 'src/client/items.cpp' |
1982 | --- src/client/items.cpp 1970-01-01 00:00:00 +0000 |
1983 | +++ src/client/items.cpp 2017-02-27 19:05:17 +0000 |
1984 | @@ -0,0 +1,196 @@ |
1985 | +/* |
1986 | + * Copyright (C) 2016 Canonical, Ltd. |
1987 | + * |
1988 | + * This program is free software: you can redistribute it and/or modify it |
1989 | + * under the terms of the GNU General Public License version 3, as published |
1990 | + * by the Free Software Foundation. |
1991 | + * |
1992 | + * This program is distributed in the hope that it will be useful, but |
1993 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1994 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1995 | + * PURPOSE. See the GNU General Public License for more details. |
1996 | + * |
1997 | + * You should have received a copy of the GNU General Public License along |
1998 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1999 | + * |
2000 | + * Authors: |
2001 | + * Xavi Garcia Mena <xavi.garcia.mena@canonical.com> |
2002 | + */ |
2003 | + |
2004 | +#include "client/keeper-items.h" |
2005 | + |
2006 | +#include <QtDBus> |
2007 | +#include <QVariantMap> |
2008 | + |
2009 | +namespace keeper |
2010 | +{ |
2011 | +// json keys |
2012 | +constexpr const char PROPERTIES_KEY[] = "properties"; |
2013 | + |
2014 | +// keys |
2015 | +const QString Item::UUID_KEY = QStringLiteral("uuid"); |
2016 | +const QString Item::TYPE_KEY = QStringLiteral("type"); |
2017 | +const QString Item::SUBTYPE_KEY = QStringLiteral("subtype"); |
2018 | +const QString Item::NAME_KEY = QStringLiteral("name"); |
2019 | +const QString Item::PACKAGE_KEY = QStringLiteral("package"); |
2020 | +const QString Item::TITLE_KEY = QStringLiteral("title"); |
2021 | +const QString Item::VERSION_KEY = QStringLiteral("version"); |
2022 | +const QString Item::FILE_NAME_KEY = QStringLiteral("file-name"); |
2023 | +const QString Item::DIR_NAME_KEY = QStringLiteral("dir-name"); |
2024 | +const QString Item::DISPLAY_NAME_KEY = QStringLiteral("display-name"); |
2025 | +const QString Item::STATUS_KEY = QStringLiteral("action"); |
2026 | +const QString Item::ERROR_KEY = QStringLiteral("error"); |
2027 | +const QString Item::PERCENT_DONE_KEY = QStringLiteral("percent-done"); |
2028 | +const QString Item::SPEED_KEY = QStringLiteral("speed"); |
2029 | + |
2030 | + |
2031 | +// values |
2032 | +const QString Item::FOLDER_VALUE = QStringLiteral("folder"); |
2033 | +const QString Item::SYSTEM_DATA_VALUE = QStringLiteral("system-data"); |
2034 | +const QString Item::APPLICATION_VALUE = QStringLiteral("application"); |
2035 | + |
2036 | +Item::Item() = default; |
2037 | + |
2038 | +Item::Item(QVariantMap const & values) |
2039 | + : QVariantMap(values) |
2040 | +{ |
2041 | +} |
2042 | + |
2043 | +Item::~Item() = default; |
2044 | + |
2045 | +QVariant Item::get_property_value(QString const & property) const |
2046 | +{ |
2047 | + auto iter = this->find(property); |
2048 | + if (iter != this->end()) |
2049 | + { |
2050 | + return (*iter); |
2051 | + } |
2052 | + else |
2053 | + { |
2054 | + return QVariant(); |
2055 | + } |
2056 | +} |
2057 | + |
2058 | +void Item::set_property_value(QString const& property, QVariant const& value) |
2059 | +{ |
2060 | + this->insert(property, value); |
2061 | +} |
2062 | + |
2063 | +template<typename T> T Item::get_property(QString const & property, bool * valid) const |
2064 | +{ |
2065 | + auto it = this->find(property); |
2066 | + |
2067 | + if (it == this->end()) |
2068 | + { |
2069 | + if (valid != nullptr) |
2070 | + *valid = false; |
2071 | + |
2072 | + return T{}; |
2073 | + } |
2074 | + |
2075 | + if (valid != nullptr) |
2076 | + *valid = true; |
2077 | + |
2078 | + return it->value<T>(); |
2079 | +} |
2080 | + |
2081 | +bool Item::is_valid()const |
2082 | +{ |
2083 | + // check for required properties |
2084 | + for (auto& property : {TYPE_KEY, DISPLAY_NAME_KEY}) |
2085 | + if (!this->has_property(property)) |
2086 | + return false; |
2087 | + |
2088 | + return true; |
2089 | +} |
2090 | + |
2091 | +bool Item::has_property(QString const & property) const |
2092 | +{ |
2093 | + return this->contains(property); |
2094 | +} |
2095 | + |
2096 | +QString Item::get_uuid(bool *valid) const |
2097 | +{ |
2098 | + return get_property<QString>(UUID_KEY, valid); |
2099 | +} |
2100 | + |
2101 | +QString Item::get_type(bool *valid) const |
2102 | +{ |
2103 | + return get_property<QString>(TYPE_KEY, valid); |
2104 | +} |
2105 | + |
2106 | +QString Item::get_display_name(bool *valid) const |
2107 | +{ |
2108 | + return get_property<QString>(DISPLAY_NAME_KEY, valid); |
2109 | +} |
2110 | + |
2111 | +QString Item::get_dir_name(bool *valid) const |
2112 | +{ |
2113 | + return get_property<QString>(DIR_NAME_KEY, valid); |
2114 | +} |
2115 | + |
2116 | +QString Item::get_status(bool *valid) const |
2117 | +{ |
2118 | + return get_property<QString>(STATUS_KEY, valid); |
2119 | +} |
2120 | + |
2121 | +double Item::get_percent_done(bool *valid) const |
2122 | +{ |
2123 | + return get_property<double>(PERCENT_DONE_KEY, valid); |
2124 | +} |
2125 | + |
2126 | +keeper::Error Item::get_error(bool *valid) const |
2127 | +{ |
2128 | + auto it = this->find(ERROR_KEY); |
2129 | + |
2130 | + // if no error was sent, things must be OK |
2131 | + if (it == this->end()) |
2132 | + { |
2133 | + return keeper::Error::OK; |
2134 | + } |
2135 | + |
2136 | + return keeper::convert_from_dbus_variant(*it, valid); |
2137 | +} |
2138 | + |
2139 | +QString Item::get_file_name(bool *valid) const |
2140 | +{ |
2141 | + return get_property<QString>(FILE_NAME_KEY, valid); |
2142 | +} |
2143 | + |
2144 | +void Item::registerMetaType() |
2145 | +{ |
2146 | + qRegisterMetaType<Item>("Item"); |
2147 | + |
2148 | + qDBusRegisterMetaType<Item>(); |
2149 | +} |
2150 | + |
2151 | +///// |
2152 | +// Items |
2153 | +///// |
2154 | + |
2155 | + |
2156 | +Items::Items() =default; |
2157 | + |
2158 | +Items::~Items() =default; |
2159 | + |
2160 | + |
2161 | +Items::Items(Error error) |
2162 | + : error_{error} |
2163 | +{ |
2164 | +} |
2165 | + |
2166 | +QStringList Items::get_uuids() const |
2167 | +{ |
2168 | + return this->keys(); |
2169 | +} |
2170 | + |
2171 | +void Items::registerMetaType() |
2172 | +{ |
2173 | + qRegisterMetaType<Items>("Items"); |
2174 | + |
2175 | + qDBusRegisterMetaType<Items>(); |
2176 | + |
2177 | + Item::registerMetaType(); |
2178 | +} |
2179 | + |
2180 | +} // namespace keeper |
2181 | |
2182 | === added file 'src/client/keeper-errors.cpp' |
2183 | --- src/client/keeper-errors.cpp 1970-01-01 00:00:00 +0000 |
2184 | +++ src/client/keeper-errors.cpp 2017-02-27 19:05:17 +0000 |
2185 | @@ -0,0 +1,74 @@ |
2186 | +/* |
2187 | + * Copyright (C) 2016 Canonical, Ltd. |
2188 | + * |
2189 | + * This program is free software: you can redistribute it and/or modify it |
2190 | + * under the terms of the GNU General Public License version 3, as published |
2191 | + * by the Free Software Foundation. |
2192 | + * |
2193 | + * This program is distributed in the hope that it will be useful, but |
2194 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2195 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2196 | + * PURPOSE. See the GNU General Public License for more details. |
2197 | + * |
2198 | + * You should have received a copy of the GNU General Public License along |
2199 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2200 | + * |
2201 | + * Authors: |
2202 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
2203 | + */ |
2204 | + |
2205 | +#include <client/keeper-errors.h> |
2206 | + |
2207 | +#include <QDebug> |
2208 | + |
2209 | +QDBusArgument &operator<<(QDBusArgument &argument, keeper::Error value) |
2210 | +{ |
2211 | + argument.beginStructure(); |
2212 | + argument << static_cast<int>(value); |
2213 | + argument.endStructure(); |
2214 | + return argument; |
2215 | +} |
2216 | + |
2217 | +const QDBusArgument &operator>>(const QDBusArgument &argument, keeper::Error &val) |
2218 | +{ |
2219 | + int int_val; |
2220 | + argument.beginStructure(); |
2221 | + argument >> int_val; |
2222 | + val = static_cast<keeper::Error>(int_val); |
2223 | + argument.endStructure(); |
2224 | + return argument; |
2225 | +} |
2226 | + |
2227 | +namespace keeper |
2228 | +{ |
2229 | +Error convert_from_dbus_variant(const QVariant & value, bool *conversion_ok) |
2230 | +{ |
2231 | + if (value.typeName() != QStringLiteral("QDBusArgument")) |
2232 | + { |
2233 | + qWarning() << Q_FUNC_INFO |
2234 | + << " Error converting dbus QVariant to Error, expected type is [ QDBusArgument ] and current type is: [" |
2235 | + << value.typeName() << "]"; |
2236 | + if (conversion_ok) |
2237 | + *conversion_ok = false; |
2238 | + return Error(keeper::Error::UNKNOWN); |
2239 | + } |
2240 | + auto dbus_arg = value.value<QDBusArgument>(); |
2241 | + |
2242 | + if (dbus_arg.currentSignature() != "(i)") |
2243 | + { |
2244 | + qWarning() << Q_FUNC_INFO |
2245 | + << " Error converting dbus QVariant to Error, expected signature is \"(i)\" and current signature is: \"" |
2246 | + << dbus_arg.currentSignature() << "\""; |
2247 | + if (conversion_ok) |
2248 | + *conversion_ok = false; |
2249 | + return Error(keeper::Error::UNKNOWN); |
2250 | + } |
2251 | + Error ret; |
2252 | + dbus_arg >> ret; |
2253 | + |
2254 | + if (conversion_ok) |
2255 | + *conversion_ok = true; |
2256 | + |
2257 | + return ret; |
2258 | +} |
2259 | +} |
2260 | |
2261 | === modified file 'src/client/qml-plugin/CMakeLists.txt' |
2262 | --- src/client/qml-plugin/CMakeLists.txt 2016-08-26 09:30:11 +0000 |
2263 | +++ src/client/qml-plugin/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
2264 | @@ -6,7 +6,7 @@ |
2265 | add_definitions(-DKEEPER_MAJOR=${KEEPER_MAJOR}) |
2266 | add_definitions(-DKEEPER_MINOR=${KEEPER_MINOR}) |
2267 | |
2268 | -include(QmlPlugins) |
2269 | +find_package(QmlPlugins) |
2270 | |
2271 | find_package(Qt5Quick REQUIRED) |
2272 | |
2273 | |
2274 | === modified file 'src/helper/CMakeLists.txt' |
2275 | --- src/helper/CMakeLists.txt 2016-09-06 01:31:59 +0000 |
2276 | +++ src/helper/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
2277 | @@ -18,6 +18,21 @@ |
2278 | ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR} |
2279 | ) |
2280 | |
2281 | +set( |
2282 | + FOLDER_RESTORE |
2283 | + folder-restore.sh |
2284 | +) |
2285 | +configure_file( |
2286 | + ${CMAKE_CURRENT_SOURCE_DIR}/${FOLDER_RESTORE}.in |
2287 | + ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE} |
2288 | +) |
2289 | + |
2290 | +install( |
2291 | + PROGRAMS |
2292 | + ${CMAKE_CURRENT_BINARY_DIR}/${FOLDER_RESTORE} |
2293 | + DESTINATION |
2294 | + ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR} |
2295 | +) |
2296 | |
2297 | # |
2298 | # the library |
2299 | @@ -30,7 +45,7 @@ |
2300 | |
2301 | include(FindPkgConfig) |
2302 | pkg_check_modules(BACKUP_HELPER_DEPENDENCIES REQUIRED |
2303 | - ubuntu-app-launch-2 |
2304 | + ubuntu-app-launch-3 |
2305 | properties-cpp |
2306 | ) |
2307 | |
2308 | @@ -48,10 +63,12 @@ |
2309 | ${HELPER_LIB} |
2310 | STATIC |
2311 | backup-helper.cpp |
2312 | + restore-helper.cpp |
2313 | data-dir-registry.cpp |
2314 | helper.cpp |
2315 | metadata.cpp |
2316 | ${CMAKE_SOURCE_DIR}/include/helper/backup-helper.h |
2317 | + ${CMAKE_SOURCE_DIR}/include/helper/restore-helper.h |
2318 | ${CMAKE_SOURCE_DIR}/include/helper/data-dir-registry.h |
2319 | ${CMAKE_SOURCE_DIR}/include/helper/helper.h |
2320 | ${CMAKE_SOURCE_DIR}/include/helper/registry.h |
2321 | |
2322 | === modified file 'src/helper/backup-helper.cpp' |
2323 | --- src/helper/backup-helper.cpp 2016-09-12 15:13:33 +0000 |
2324 | +++ src/helper/backup-helper.cpp 2017-02-27 19:05:17 +0000 |
2325 | @@ -62,8 +62,8 @@ |
2326 | int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds); |
2327 | if (rc == -1) |
2328 | { |
2329 | - // TODO throw exception. |
2330 | - qWarning() << "BackupHelperPrivate: error creating socket pair to communicate with helper "; |
2331 | + qWarning() << QStringLiteral("Error creating socket to communicate with helper");; |
2332 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_SOCKET)); |
2333 | return; |
2334 | } |
2335 | |
2336 | @@ -139,9 +139,14 @@ |
2337 | &Uploader::commit_finished, |
2338 | std::function<void(bool)>{[this](bool success){ |
2339 | qDebug() << "Commit finished"; |
2340 | - uploader_.reset(); |
2341 | if (!success) |
2342 | + { |
2343 | write_error_ = true; |
2344 | + Q_EMIT(q_ptr->error(keeper::Error::COMMITTING_DATA)); |
2345 | + } |
2346 | + else |
2347 | + uploader_committed_file_name_ = uploader_->file_name(); |
2348 | + uploader_.reset(); |
2349 | check_for_done(); |
2350 | }} |
2351 | ); |
2352 | @@ -162,12 +167,18 @@ |
2353 | check_for_done(); |
2354 | } |
2355 | |
2356 | + QString get_uploader_committed_file_name() const |
2357 | + { |
2358 | + return uploader_committed_file_name_; |
2359 | + } |
2360 | + |
2361 | private: |
2362 | |
2363 | void on_inactivity_detected() |
2364 | { |
2365 | stop_inactivity_timer(); |
2366 | qWarning() << "Inactivity detected in the helper...stopping it"; |
2367 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_INACTIVITY_DETECTED)); |
2368 | stop(); |
2369 | } |
2370 | |
2371 | @@ -180,7 +191,6 @@ |
2372 | { |
2373 | n_uploaded_ += n; |
2374 | q_ptr->record_data_transferred(n); |
2375 | - qDebug("n_read %zu n_uploaded %zu (newly uploaded %zu)", size_t(n_read_), size_t(n_uploaded_), size_t(n)); |
2376 | process_more(); |
2377 | check_for_done(); |
2378 | } |
2379 | @@ -201,10 +211,10 @@ |
2380 | if (n > 0) { |
2381 | n_read_ += n; |
2382 | upload_buffer_.append(readbuf, int(n)); |
2383 | - qDebug("upload_buffer_.size() is %zu after reading %zu from helper", size_t(upload_buffer_.size()), size_t(n)); |
2384 | } |
2385 | else if (n < 0) { |
2386 | read_error_ = true; |
2387 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_READ)); |
2388 | stop(); |
2389 | return; |
2390 | } |
2391 | @@ -214,13 +224,13 @@ |
2392 | const auto n = socket->write(upload_buffer_); |
2393 | if (n > 0) { |
2394 | upload_buffer_.remove(0, int(n)); |
2395 | - qDebug("upload_buffer_.size() is %zu after writing %zu to cloud", size_t(upload_buffer_.size()), size_t(n)); |
2396 | continue; |
2397 | } |
2398 | else { |
2399 | if (n < 0) { |
2400 | write_error_ = true; |
2401 | qWarning() << "Write error:" << socket->errorString(); |
2402 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE)); |
2403 | stop(); |
2404 | } |
2405 | break; |
2406 | @@ -251,6 +261,10 @@ |
2407 | { |
2408 | if (!q_ptr->is_helper_running()) |
2409 | { |
2410 | + if (n_uploaded_ > q_ptr->expected_size()) |
2411 | + { |
2412 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE)); |
2413 | + } |
2414 | q_ptr->set_state(Helper::State::FAILED); |
2415 | } |
2416 | } |
2417 | @@ -289,6 +303,7 @@ |
2418 | bool write_error_ = false; |
2419 | bool cancelled_ = false; |
2420 | ConnectionHelper connections_; |
2421 | + QString uploader_committed_file_name_; |
2422 | }; |
2423 | |
2424 | /*** |
2425 | @@ -352,14 +367,21 @@ |
2426 | { |
2427 | Q_D(BackupHelper); |
2428 | |
2429 | - qDebug() << Q_FUNC_INFO; |
2430 | + Helper::set_state(state); |
2431 | d->on_state_changed(state); |
2432 | - Helper::set_state(state); |
2433 | } |
2434 | |
2435 | void BackupHelper::on_helper_finished() |
2436 | { |
2437 | Q_D(BackupHelper); |
2438 | + |
2439 | Helper::on_helper_finished(); |
2440 | d->on_helper_finished(); |
2441 | } |
2442 | + |
2443 | +QString BackupHelper::get_uploader_committed_file_name() const |
2444 | +{ |
2445 | + Q_D(const BackupHelper); |
2446 | + |
2447 | + return d->get_uploader_committed_file_name(); |
2448 | +} |
2449 | |
2450 | === modified file 'src/helper/data-dir-registry.cpp' |
2451 | --- src/helper/data-dir-registry.cpp 2016-08-10 02:29:17 +0000 |
2452 | +++ src/helper/data-dir-registry.cpp 2017-02-27 19:05:17 +0000 |
2453 | @@ -49,15 +49,27 @@ |
2454 | |
2455 | QStringList get_backup_helper_urls(Metadata const& task) |
2456 | { |
2457 | + return get_helper_urls(task, "backup"); |
2458 | + } |
2459 | + |
2460 | + QStringList get_restore_helper_urls(Metadata const& task) |
2461 | + { |
2462 | + return get_helper_urls(task, "restore"); |
2463 | + } |
2464 | + |
2465 | +private: |
2466 | + |
2467 | + QStringList get_helper_urls(Metadata const& task, QString const & prop) |
2468 | + { |
2469 | QStringList ret; |
2470 | |
2471 | - QString type; |
2472 | - if (task.get_property(Metadata::TYPE_KEY, type)) |
2473 | + auto type = task.get_type(); |
2474 | + if (!type.isEmpty()) |
2475 | { |
2476 | - auto it = registry_.find(std::make_pair(type,QStringLiteral("backup"))); |
2477 | + auto it = registry_.find(std::make_pair(type,prop)); |
2478 | if (it == registry_.end()) |
2479 | { |
2480 | - qCritical() << "can't get backup helper urls for unhandled type" << type; |
2481 | + qCritical() << "can't get " << prop << " helper urls for unhandled type" << type; |
2482 | } |
2483 | else |
2484 | { |
2485 | @@ -73,30 +85,28 @@ |
2486 | return ret; |
2487 | } |
2488 | |
2489 | -private: |
2490 | - |
2491 | // replace "${key}" with task.get_property("key") |
2492 | QStringList perform_url_substitution(Metadata const& task, QStringList const& urls_in) |
2493 | { |
2494 | std::array<QString,6> keys = { |
2495 | - Metadata::TYPE_KEY, |
2496 | - Metadata::SUBTYPE_KEY, |
2497 | - Metadata::NAME_KEY, |
2498 | - Metadata::PACKAGE_KEY, |
2499 | - Metadata::TITLE_KEY, |
2500 | - Metadata::VERSION_KEY |
2501 | + keeper::Item::TYPE_KEY, |
2502 | + keeper::Item::SUBTYPE_KEY, |
2503 | + keeper::Item::NAME_KEY, |
2504 | + keeper::Item::PACKAGE_KEY, |
2505 | + keeper::Item::TITLE_KEY, |
2506 | + keeper::Item::VERSION_KEY |
2507 | }; |
2508 | |
2509 | QStringList urls {urls_in}; |
2510 | |
2511 | for (auto const& key : keys) |
2512 | { |
2513 | - QString after; |
2514 | - if (task.get_property(key, after)) |
2515 | + QVariant after = task.get_property_value(key); |
2516 | + if (after.isValid()) |
2517 | { |
2518 | QString before = QStringLiteral("${%1}").arg(key); |
2519 | for (auto& url : urls) |
2520 | - url.replace(before, after); |
2521 | + url.replace(before, after.toString()); |
2522 | } |
2523 | } |
2524 | |
2525 | @@ -139,6 +149,10 @@ |
2526 | * "backup-urls": [ |
2527 | * "/path/to/helper.sh", |
2528 | * "${subtype}" |
2529 | + * ], |
2530 | + * "restore-urls": [ |
2531 | + * "/path/to/helper.sh", |
2532 | + * "${subtype}" |
2533 | * ] |
2534 | * } |
2535 | * } |
2536 | @@ -156,25 +170,37 @@ |
2537 | if (error.error != QJsonParseError::NoError) |
2538 | qCritical() << path << "parse error at offset" << error.offset << error.errorString(); |
2539 | |
2540 | - auto obj = doc.object(); |
2541 | + const auto obj = doc.object(); |
2542 | for (auto tit=obj.begin(), tend=obj.end(); tit!=tend; ++tit) |
2543 | { |
2544 | auto const type = tit.key(); |
2545 | - auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))]; |
2546 | - |
2547 | auto const props = tit.value().toObject(); |
2548 | - auto const urls_jsonval = props["backup-urls"]; |
2549 | + |
2550 | + auto const &urls_jsonval = props["backup-urls"]; |
2551 | if (urls_jsonval.isArray()) |
2552 | { |
2553 | + auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))]; |
2554 | for (auto url_jsonval : urls_jsonval.toArray()) |
2555 | { |
2556 | info.urls.push_back(url_jsonval.toString()); |
2557 | } |
2558 | + qDebug() << "loaded" << type << "backup urls from" << path; |
2559 | + for(auto const& url : info.urls) |
2560 | + qDebug() << "\turl:" << url; |
2561 | } |
2562 | |
2563 | - qDebug() << "loaded" << type << "backup urls from" << path; |
2564 | - for(auto const& url : info.urls) |
2565 | - qDebug() << "\turl:" << url; |
2566 | + auto const &urls_jsonval_restore = props["restore-urls"]; |
2567 | + if (urls_jsonval_restore.isArray()) |
2568 | + { |
2569 | + auto& info = registry_[std::make_pair(type,QStringLiteral("restore"))]; |
2570 | + for (auto url_jsonval : urls_jsonval_restore.toArray()) |
2571 | + { |
2572 | + info.urls.push_back(url_jsonval.toString()); |
2573 | + } |
2574 | + qDebug() << "loaded" << type << "restore urls from" << path; |
2575 | + for(auto const& url : info.urls) |
2576 | + qDebug() << "\turl:" << url; |
2577 | + } |
2578 | } |
2579 | } |
2580 | } |
2581 | @@ -198,3 +224,9 @@ |
2582 | { |
2583 | return impl_->get_backup_helper_urls(task); |
2584 | } |
2585 | + |
2586 | +QStringList |
2587 | +DataDirRegistry::get_restore_helper_urls(Metadata const& task) |
2588 | +{ |
2589 | + return impl_->get_restore_helper_urls(task); |
2590 | +} |
2591 | |
2592 | === modified file 'src/helper/folder-backup.sh.in' |
2593 | --- src/helper/folder-backup.sh.in 2016-08-10 05:01:08 +0000 |
2594 | +++ src/helper/folder-backup.sh.in 2017-02-27 19:05:17 +0000 |
2595 | @@ -20,4 +20,4 @@ |
2596 | # |
2597 | |
2598 | echo $PWD |
2599 | -find ./ -type f -print0 | @CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-tar-create -a /com/canonical/keeper/helper |
2600 | +find ./ -type f -print0 | @CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-tar -a /com/canonical/keeper/helper |
2601 | |
2602 | === added file 'src/helper/folder-restore.sh.in' |
2603 | --- src/helper/folder-restore.sh.in 1970-01-01 00:00:00 +0000 |
2604 | +++ src/helper/folder-restore.sh.in 2017-02-27 19:05:17 +0000 |
2605 | @@ -0,0 +1,23 @@ |
2606 | +#!/bin/bash |
2607 | +# |
2608 | +# Copyright (C) 2016 Canonical, Ltd. |
2609 | +# |
2610 | +# This program is free software: you can redistribute it and/or modify it |
2611 | +# under the terms of the GNU General Public License version 3, as published |
2612 | +# by the Free Software Foundation. |
2613 | +# |
2614 | +# This program is distributed in the hope that it will be useful, but |
2615 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2616 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2617 | +# PURPOSE. See the GNU General Public License for more details. |
2618 | +# |
2619 | +# You should have received a copy of the GNU General Public License along |
2620 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2621 | +# |
2622 | +# Authors: |
2623 | +# Xavi Garcia <xavi.garcia.mena@canonical.com> |
2624 | +# Charles Kerr <charles.kerr@canonical.com> |
2625 | +# |
2626 | + |
2627 | +echo $PWD |
2628 | +@CMAKE_INSTALL_FULL_PKGLIBEXECDIR@/keeper-untar -a /com/canonical/keeper/helper |
2629 | |
2630 | === modified file 'src/helper/helper.cpp' |
2631 | --- src/helper/helper.cpp 2016-09-12 15:13:33 +0000 |
2632 | +++ src/helper/helper.cpp 2017-02-27 19:05:17 +0000 |
2633 | @@ -75,7 +75,6 @@ |
2634 | uint32_t |
2635 | speed_bytes_per_second(uint64_t now, unsigned int interval_msec=HISTORY_MSEC) const |
2636 | { |
2637 | -qDebug() << "now" << now << "cache_time" << cache_time << "interval_msec" << interval_msec; |
2638 | if (cache_time != now) |
2639 | { |
2640 | auto i = newest; |
2641 | @@ -88,22 +87,18 @@ |
2642 | break; |
2643 | |
2644 | bytes += transfers[i].size; |
2645 | -qDebug() << "i" << i << "transfers[i] .date" << transfers[i].date << ".size" << transfers[i].size << "sum" << bytes; |
2646 | |
2647 | if (--i == -1) { |
2648 | i = HISTORY_SIZE - 1; // circular history |
2649 | -qDebug() << "circular history"; |
2650 | } |
2651 | |
2652 | if (i == newest) { |
2653 | -qDebug() << "i" << i << "transfers[i] .date" << transfers[i].date << ".size" << transfers[i].size << "sum" << bytes; |
2654 | break; // we've come all the way around |
2655 | } |
2656 | } |
2657 | |
2658 | cache_val = uint32_t((bytes * 1000u) / interval_msec); |
2659 | cache_time = now; |
2660 | -qDebug() << "cache_val" << cache_val << "cache_time" << cache_time; |
2661 | } |
2662 | |
2663 | return cache_val; |
2664 | @@ -170,7 +165,10 @@ |
2665 | { |
2666 | qDebug() << "changing state of helper" << static_cast<void*>(this) << "from" << q_ptr->to_string(state_) << "to" << q_ptr->to_string(state); |
2667 | state_ = state; |
2668 | - q_ptr->state_changed(state); |
2669 | + QMetaObject::invokeMethod(q_ptr, |
2670 | + "state_changed", |
2671 | + Qt::QueuedConnection, |
2672 | + Q_ARG(Helper::State, state)); |
2673 | } |
2674 | } |
2675 | |
2676 | @@ -337,7 +335,6 @@ |
2677 | |
2678 | if (is_noteworthy) |
2679 | { |
2680 | - qDebug() << "emitting percent-done-changed" << percent_done_; |
2681 | Q_EMIT(q_ptr->percent_done_changed(percent_done_)); |
2682 | last_notified_percent_done_ = percent_done_; |
2683 | } |
2684 | @@ -356,7 +353,8 @@ |
2685 | |
2686 | void on_max_time_waiting_for_ual_started() |
2687 | { |
2688 | - qDebug() << "Max time reached waiting for UAL to start"; |
2689 | + qWarning() << "Maximum time reached waiting for the helper to start."; |
2690 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_START_TIMEOUT)); |
2691 | q_ptr->set_state(Helper::State::FAILED); |
2692 | stop_wait_for_ual_timer(); |
2693 | } |
2694 | |
2695 | === modified file 'src/helper/metadata.cpp' |
2696 | --- src/helper/metadata.cpp 2016-09-06 18:51:30 +0000 |
2697 | +++ src/helper/metadata.cpp 2017-02-27 19:05:17 +0000 |
2698 | @@ -19,63 +19,58 @@ |
2699 | |
2700 | #include "helper/metadata.h" |
2701 | |
2702 | -/// |
2703 | -/// |
2704 | - |
2705 | -// Metadata keys |
2706 | -const QString Metadata::TYPE_KEY = QStringLiteral("type"); |
2707 | -const QString Metadata::SUBTYPE_KEY = QStringLiteral("subtype"); |
2708 | -const QString Metadata::NAME_KEY = QStringLiteral("name"); |
2709 | -const QString Metadata::PACKAGE_KEY = QStringLiteral("package"); |
2710 | -const QString Metadata::TITLE_KEY = QStringLiteral("title"); |
2711 | -const QString Metadata::VERSION_KEY = QStringLiteral("version"); |
2712 | - |
2713 | -// Metadata values |
2714 | -const QString Metadata::FOLDER_VALUE = QStringLiteral("folder"); |
2715 | -const QString Metadata::SYSTEM_DATA_VALUE = QStringLiteral("system-data"); |
2716 | -const QString Metadata::APPLICATION_VALUE = QStringLiteral("application"); |
2717 | +#include <QDebug> |
2718 | +#include <QJsonArray> |
2719 | +#include <QJsonDocument> |
2720 | + |
2721 | +/// |
2722 | +/// |
2723 | + |
2724 | +// JSON Keys |
2725 | +namespace |
2726 | +{ |
2727 | + constexpr const char PROPERTIES_KEY[] = "properties"; |
2728 | +} |
2729 | |
2730 | /// |
2731 | /// |
2732 | |
2733 | Metadata::Metadata() |
2734 | - : uuid_() |
2735 | - , display_name_() |
2736 | - , properties_() |
2737 | -{ |
2738 | + : keeper::Item() |
2739 | +{ |
2740 | +} |
2741 | + |
2742 | +Metadata::Metadata(QJsonObject const & json) |
2743 | + : keeper::Item() |
2744 | +{ |
2745 | + auto properties = json[PROPERTIES_KEY].toObject(); |
2746 | + for (auto const & key : properties.keys()) |
2747 | + { |
2748 | + this->insert(key, properties[key].toString()); |
2749 | + } |
2750 | } |
2751 | |
2752 | Metadata::Metadata(QString const& uuid, QString const& display_name) |
2753 | - : uuid_(uuid) |
2754 | - , display_name_(display_name) |
2755 | - , properties_() |
2756 | -{ |
2757 | -} |
2758 | - |
2759 | -bool |
2760 | -Metadata::get_property(QString const& property_name, QString& setme) const |
2761 | -{ |
2762 | - auto it = properties_.constFind(property_name); |
2763 | - const bool found = it != properties_.end(); |
2764 | - |
2765 | - if (found) |
2766 | - setme = it.value(); |
2767 | - |
2768 | - return found; |
2769 | -} |
2770 | - |
2771 | -void |
2772 | -Metadata::set_property(QString const& property_name, QString const& value) |
2773 | -{ |
2774 | - properties_.insert(property_name, value); |
2775 | -} |
2776 | - |
2777 | -QMap<QString,QString> |
2778 | -Metadata::get_public_properties() const |
2779 | -{ |
2780 | - // they're all public so far... |
2781 | - auto ret = properties_; |
2782 | - ret.insert(QStringLiteral("uuid"), uuid_); |
2783 | - ret.insert(QStringLiteral("display-name"), display_name_); |
2784 | + : keeper::Item() |
2785 | +{ |
2786 | + this->insert(keeper::Item::UUID_KEY, uuid); |
2787 | + this->insert(keeper::Item::DISPLAY_NAME_KEY, display_name); |
2788 | +} |
2789 | + |
2790 | +QJsonObject |
2791 | +Metadata::json() const |
2792 | +{ |
2793 | + QJsonArray json_properties; |
2794 | + QJsonObject properties_obj; |
2795 | + for (auto iter = this->begin(); iter != this->end(); ++iter) |
2796 | + { |
2797 | + properties_obj[iter.key()] = (*iter).toString(); |
2798 | + } |
2799 | + |
2800 | + QJsonObject ret |
2801 | + { |
2802 | + { PROPERTIES_KEY, properties_obj } |
2803 | + }; |
2804 | + |
2805 | return ret; |
2806 | } |
2807 | |
2808 | === added file 'src/helper/restore-helper.cpp' |
2809 | --- src/helper/restore-helper.cpp 1970-01-01 00:00:00 +0000 |
2810 | +++ src/helper/restore-helper.cpp 2017-02-27 19:05:17 +0000 |
2811 | @@ -0,0 +1,377 @@ |
2812 | +/* |
2813 | + * Copyright (C) 2016 Canonical, Ltd. |
2814 | + * |
2815 | + * This program is free software: you can redistribute it and/or modify it |
2816 | + * under the terms of the GNU General Public License version 3, as published |
2817 | + * by the Free Software Foundation. |
2818 | + * |
2819 | + * This program is distributed in the hope that it will be useful, but |
2820 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
2821 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2822 | + * PURPOSE. See the GNU General Public License for more details. |
2823 | + * |
2824 | + * You should have received a copy of the GNU General Public License along |
2825 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2826 | + * |
2827 | + * Authors: |
2828 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
2829 | + * Charles Kerr <charles.kerr@canonical.com> |
2830 | + */ |
2831 | + |
2832 | +#include "util/connection-helper.h" |
2833 | +#include "helper/restore-helper.h" |
2834 | +#include "service/app-const.h" // HELPER_TYPE |
2835 | + |
2836 | +#include <QByteArray> |
2837 | +#include <QDebug> |
2838 | +#include <QLocalSocket> |
2839 | +#include <QMap> |
2840 | +#include <QObject> |
2841 | +#include <QString> |
2842 | +#include <QTimer> |
2843 | +#include <QVector> |
2844 | + |
2845 | +#include <fcntl.h> |
2846 | +#include <sys/types.h> |
2847 | +#include <sys/socket.h> |
2848 | + |
2849 | +#include <functional> // std::bind() |
2850 | + |
2851 | + |
2852 | +class RestoreHelperPrivate |
2853 | +{ |
2854 | +public: |
2855 | + |
2856 | + explicit RestoreHelperPrivate( |
2857 | + RestoreHelper* backup_helper |
2858 | + ) |
2859 | + : q_ptr(backup_helper) |
2860 | + { |
2861 | + // listen for inactivity from storage framework |
2862 | + QObject::connect(&timer_, &QTimer::timeout, |
2863 | + std::bind(&RestoreHelperPrivate::on_inactivity_detected, this) |
2864 | + ); |
2865 | + |
2866 | + // fire up the sockets |
2867 | + int fds[2]; |
2868 | + int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds); |
2869 | + if (rc == -1) |
2870 | + { |
2871 | + qWarning() << QStringLiteral("Error creating socket to communicate with helper");; |
2872 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_SOCKET)); |
2873 | + return; |
2874 | + } |
2875 | + |
2876 | + // helper socket is for the client. |
2877 | + // We don't use a QLocalSocket here as it buffers data and it makes the helper miss packets. |
2878 | + helper_socket_ = fds[1]; |
2879 | + |
2880 | + write_socket_.setSocketDescriptor(fds[0], QLocalSocket::ConnectedState, QIODevice::WriteOnly); |
2881 | + } |
2882 | + |
2883 | + ~RestoreHelperPrivate() = default; |
2884 | + |
2885 | + Q_DISABLE_COPY(RestoreHelperPrivate) |
2886 | + |
2887 | + void start(QStringList const& urls) |
2888 | + { |
2889 | + q_ptr->Helper::start(urls); |
2890 | + reset_inactivity_timer(); |
2891 | + } |
2892 | + |
2893 | + void set_downloader(std::shared_ptr<Downloader> const& downloader) |
2894 | + { |
2895 | + n_read_ = 0; |
2896 | + n_uploaded_ = 0; |
2897 | + read_error_ = false; |
2898 | + write_error_ = false; |
2899 | + cancelled_ = false; |
2900 | + |
2901 | + q_ptr->set_expected_size(downloader->file_size()); |
2902 | + downloader_ = downloader; |
2903 | + |
2904 | + connections_.remember(QObject::connect( |
2905 | + &write_socket_, &QLocalSocket::bytesWritten, |
2906 | + std::bind(&RestoreHelperPrivate::on_data_uploaded, this, std::placeholders::_1) |
2907 | + )); |
2908 | + |
2909 | + // listen for data ready to read |
2910 | + QObject::connect(downloader_->socket().get(), &QLocalSocket::readyRead, |
2911 | + std::bind(&RestoreHelperPrivate::on_ready_read, this) |
2912 | + ); |
2913 | + |
2914 | + // TODO investigate why UAL takes so long to call the helper started callback |
2915 | + // At this point we are sure that the helper started, as it is the helper |
2916 | + // the ones that asks for a downloader socket. |
2917 | + q_ptr->Helper::on_helper_started(); |
2918 | + |
2919 | + // maybe there's data already to be read |
2920 | + process_more(); |
2921 | + |
2922 | + reset_inactivity_timer(); |
2923 | + } |
2924 | + |
2925 | + void stop() |
2926 | + { |
2927 | + write_socket_.disconnectFromServer(); |
2928 | + cancelled_ = true; |
2929 | + q_ptr->Helper::stop(); |
2930 | + } |
2931 | + |
2932 | + int get_helper_socket() const |
2933 | + { |
2934 | + return helper_socket_; |
2935 | + } |
2936 | + |
2937 | + QString to_string(Helper::State state) const |
2938 | + { |
2939 | + return state == Helper::State::STARTED |
2940 | + ? QStringLiteral("restoring") |
2941 | + : q_ptr->Helper::to_string(state); |
2942 | + } |
2943 | + |
2944 | + void on_state_changed(Helper::State state) |
2945 | + { |
2946 | + switch (state) |
2947 | + { |
2948 | + case Helper::State::CANCELLED: |
2949 | + case Helper::State::FAILED: |
2950 | + qDebug() << "cancelled/failed, calling downloader_.reset()"; |
2951 | + downloader_.reset(); |
2952 | + break; |
2953 | + |
2954 | + case Helper::State::DATA_COMPLETE: { |
2955 | + qDebug() << "Restore helper finished, calling downloader_.finish()"; |
2956 | + write_socket_.disconnectFromServer(); |
2957 | + downloader_->finish(); |
2958 | + downloader_.reset(); |
2959 | + break; |
2960 | + } |
2961 | + |
2962 | + //case Helper::State::NOT_STARTED: |
2963 | + //case Helper::State::STARTED: |
2964 | + default: |
2965 | + break; |
2966 | + } |
2967 | + } |
2968 | + |
2969 | + void on_helper_finished() |
2970 | + { |
2971 | + stop_inactivity_timer(); |
2972 | + check_for_done(); |
2973 | + } |
2974 | + |
2975 | +private: |
2976 | + |
2977 | + void on_inactivity_detected() |
2978 | + { |
2979 | + stop_inactivity_timer(); |
2980 | + qWarning() << "Inactivity detected in the helper...stopping it"; |
2981 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_INACTIVITY_DETECTED)); |
2982 | + stop(); |
2983 | + } |
2984 | + |
2985 | + void on_ready_read() |
2986 | + { |
2987 | + process_more(); |
2988 | + } |
2989 | + |
2990 | + void on_data_uploaded(qint64 n) |
2991 | + { |
2992 | + n_uploaded_ += n; |
2993 | + q_ptr->record_data_transferred(n); |
2994 | + process_more(); |
2995 | + check_for_done(); |
2996 | + } |
2997 | + |
2998 | + void process_more() |
2999 | + { |
3000 | + if (!downloader_) |
3001 | + return; |
3002 | + |
3003 | + char readbuf[UPLOAD_BUFFER_MAX_]; |
3004 | + auto socket = downloader_->socket(); |
3005 | + while(socket->bytesAvailable() || upload_buffer_.size()) |
3006 | + { |
3007 | + if (socket->bytesAvailable()) |
3008 | + { |
3009 | + // try to fill the upload buf |
3010 | + int max_bytes = UPLOAD_BUFFER_MAX_ - upload_buffer_.size(); |
3011 | + if (max_bytes > 0) { |
3012 | + const auto n = socket->read(readbuf, max_bytes); |
3013 | + if (n > 0) { |
3014 | + n_read_ += n; |
3015 | + upload_buffer_.append(readbuf, int(n)); |
3016 | + } |
3017 | + else if (n < 0) { |
3018 | + read_error_ = true; |
3019 | + qDebug() << "Read error in restore helper: " << socket->errorString(); |
3020 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_READ)); |
3021 | + stop(); |
3022 | + check_for_done(); |
3023 | + return; |
3024 | + } |
3025 | + } |
3026 | + } |
3027 | + |
3028 | + if (upload_buffer_.size()) |
3029 | + { |
3030 | + // try to empty the upload buf |
3031 | + const auto n = write_socket_.write(upload_buffer_); |
3032 | + if (n > 0) { |
3033 | + upload_buffer_.remove(0, int(n)); |
3034 | + continue; |
3035 | + } |
3036 | + else { |
3037 | + if (n < 0) { |
3038 | + write_error_ = true; |
3039 | + qWarning() << "Write error:" << write_socket_.errorString(); |
3040 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE)); |
3041 | + stop(); |
3042 | + check_for_done(); |
3043 | + } |
3044 | + break; |
3045 | + } |
3046 | + } |
3047 | + } |
3048 | + |
3049 | + reset_inactivity_timer(); |
3050 | + } |
3051 | + |
3052 | + void reset_inactivity_timer() |
3053 | + { |
3054 | + static constexpr int MAX_TIME_WAITING_FOR_DATA {RestoreHelper::MAX_INACTIVITY_TIME}; |
3055 | + timer_.start(MAX_TIME_WAITING_FOR_DATA); |
3056 | + } |
3057 | + |
3058 | + void stop_inactivity_timer() |
3059 | + { |
3060 | + timer_.stop(); |
3061 | + } |
3062 | + |
3063 | + void check_for_done() |
3064 | + { |
3065 | + if (cancelled_) |
3066 | + { |
3067 | + q_ptr->set_state(Helper::State::CANCELLED); |
3068 | + } |
3069 | + else if (read_error_ || write_error_ || n_uploaded_ > q_ptr->expected_size()) |
3070 | + { |
3071 | + if (!q_ptr->is_helper_running()) |
3072 | + { |
3073 | + if (n_uploaded_ > q_ptr->expected_size()) |
3074 | + { |
3075 | + Q_EMIT(q_ptr->error(keeper::Error::HELPER_WRITE)); |
3076 | + } |
3077 | + q_ptr->set_state(Helper::State::FAILED); |
3078 | + } |
3079 | + } |
3080 | + else if (n_uploaded_ == q_ptr->expected_size()) |
3081 | + { |
3082 | + if (downloader_) |
3083 | + { |
3084 | + if (q_ptr->is_helper_running()) |
3085 | + { |
3086 | + // only in the case that the helper process finished we move to the next state |
3087 | + // this is to prevent to start the next task too early |
3088 | + q_ptr->set_state(Helper::State::DATA_COMPLETE); |
3089 | + stop_inactivity_timer(); |
3090 | + } |
3091 | + } |
3092 | + else |
3093 | + q_ptr->set_state(Helper::State::COMPLETE); |
3094 | + } |
3095 | + } |
3096 | + |
3097 | + /*** |
3098 | + **** |
3099 | + ***/ |
3100 | + |
3101 | + static constexpr int UPLOAD_BUFFER_MAX_ {1024*16}; |
3102 | + |
3103 | + RestoreHelper * const q_ptr; |
3104 | + QTimer timer_; |
3105 | + std::shared_ptr<Downloader> downloader_; |
3106 | + int helper_socket_ = -1; |
3107 | + QLocalSocket write_socket_; |
3108 | + QByteArray upload_buffer_; |
3109 | + qint64 n_read_ = 0; |
3110 | + qint64 n_uploaded_ = 0; |
3111 | + bool read_error_ = false; |
3112 | + bool write_error_ = false; |
3113 | + bool cancelled_ = false; |
3114 | + ConnectionHelper connections_; |
3115 | +}; |
3116 | + |
3117 | +/*** |
3118 | +**** |
3119 | +***/ |
3120 | + |
3121 | +RestoreHelper::RestoreHelper( |
3122 | + QString const & appid, |
3123 | + clock_func const & clock, |
3124 | + QObject * parent |
3125 | +) |
3126 | + : Helper(appid, clock, parent) |
3127 | + , d_ptr(new RestoreHelperPrivate(this)) |
3128 | +{ |
3129 | +} |
3130 | + |
3131 | +RestoreHelper::~RestoreHelper() =default; |
3132 | + |
3133 | +void |
3134 | +RestoreHelper::start(QStringList const& url) |
3135 | +{ |
3136 | + Q_D(RestoreHelper); |
3137 | + |
3138 | + d->start(url); |
3139 | +} |
3140 | + |
3141 | +void |
3142 | +RestoreHelper::stop() |
3143 | +{ |
3144 | + Q_D(RestoreHelper); |
3145 | + |
3146 | + d->stop(); |
3147 | +} |
3148 | + |
3149 | +void |
3150 | +RestoreHelper::set_downloader(std::shared_ptr<Downloader> const& downloader) |
3151 | +{ |
3152 | + Q_D(RestoreHelper); |
3153 | + |
3154 | + d->set_downloader(downloader); |
3155 | +} |
3156 | + |
3157 | +int |
3158 | +RestoreHelper::get_helper_socket() const |
3159 | +{ |
3160 | + Q_D(const RestoreHelper); |
3161 | + |
3162 | + return d->get_helper_socket(); |
3163 | +} |
3164 | + |
3165 | +QString |
3166 | +RestoreHelper::to_string(Helper::State state) const |
3167 | +{ |
3168 | + Q_D(const RestoreHelper); |
3169 | + |
3170 | + return d->to_string(state); |
3171 | +} |
3172 | + |
3173 | +void |
3174 | +RestoreHelper::set_state(Helper::State state) |
3175 | +{ |
3176 | + Q_D(RestoreHelper); |
3177 | + |
3178 | + Helper::set_state(state); |
3179 | + d->on_state_changed(state); |
3180 | +} |
3181 | + |
3182 | +void RestoreHelper::on_helper_finished() |
3183 | +{ |
3184 | + Q_D(RestoreHelper); |
3185 | + |
3186 | + Helper::on_helper_finished(); |
3187 | + d->on_helper_finished(); |
3188 | +} |
3189 | |
3190 | === modified file 'src/qdbus-stubs/CMakeLists.txt' |
3191 | --- src/qdbus-stubs/CMakeLists.txt 2016-08-10 05:41:26 +0000 |
3192 | +++ src/qdbus-stubs/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
3193 | @@ -67,6 +67,7 @@ |
3194 | ${user_xml} |
3195 | PROPERTIES |
3196 | CLASSNAME DBusInterfaceKeeperUser |
3197 | + INCLUDE "client/keeper-items.h" |
3198 | ) |
3199 | |
3200 | qt5_add_dbus_interface( |
3201 | @@ -84,6 +85,23 @@ |
3202 | KeeperUserAdaptor |
3203 | ) |
3204 | |
3205 | +set( |
3206 | + properties_xml |
3207 | + "org.freedesktop.DBus.Properties.xml" |
3208 | +) |
3209 | + |
3210 | +set_source_files_properties( |
3211 | + "${properties_xml}" |
3212 | + PROPERTIES |
3213 | + NO_NAMESPACE YES |
3214 | + CLASSNAME DBusPropertiesInterface |
3215 | +) |
3216 | + |
3217 | +qt5_add_dbus_interface( |
3218 | + interface_files |
3219 | + ${properties_xml} |
3220 | + DBusPropertiesInterface |
3221 | +) |
3222 | # |
3223 | # |
3224 | |
3225 | @@ -101,5 +119,5 @@ |
3226 | |
3227 | target_link_libraries( |
3228 | ${STUBS_LIB} |
3229 | - backup-helper |
3230 | + keeper-errors-lib |
3231 | ) |
3232 | |
3233 | === modified file 'src/qdbus-stubs/com.canonical.keeper.User.xml' |
3234 | --- src/qdbus-stubs/com.canonical.keeper.User.xml 2016-07-28 19:44:52 +0000 |
3235 | +++ src/qdbus-stubs/com.canonical.keeper.User.xml 2017-02-27 19:05:17 +0000 |
3236 | @@ -5,7 +5,7 @@ |
3237 | <interface name="com.canonical.keeper.User"> |
3238 | |
3239 | <method name="GetBackupChoices"> |
3240 | - <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantDictMap"/> |
3241 | + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="keeper::Items"/> |
3242 | <arg direction="out" name="backups" type="a{sa{sv}}"> |
3243 | <doc:doc> |
3244 | <doc:summary>A list of backup possibilities for the user to choose from</doc:summary> |
3245 | @@ -32,10 +32,32 @@ |
3246 | </doc:description> |
3247 | </doc:doc> |
3248 | </arg> |
3249 | + <arg direction="in" name="storage" type="s"> |
3250 | + <doc:doc> |
3251 | + <doc:summary>The storage identifier</doc:summary> |
3252 | + <doc:description> |
3253 | + <doc:para>Because keeper supports multiple storage providers the user can define |
3254 | + which is the storage provider to use. |
3255 | + If the passed storage id is an empty string the default storage provider |
3256 | + will be used.</doc:para> |
3257 | + </doc:description> |
3258 | + </doc:doc> |
3259 | + </arg> |
3260 | </method> |
3261 | |
3262 | <method name="GetRestoreChoices"> |
3263 | - <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantDictMap"/> |
3264 | + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="keeper::Items"/> |
3265 | + <arg direction="in" name="storage" type="s"> |
3266 | + <doc:doc> |
3267 | + <doc:summary>The storage identifier</doc:summary> |
3268 | + <doc:description> |
3269 | + <doc:para>Because keeper supports multiple storage providers the user can define |
3270 | + which is the storage provider to use. |
3271 | + If the passed storage id is an empty string the default storage provider |
3272 | + will be used.</doc:para> |
3273 | + </doc:description> |
3274 | + </doc:doc> |
3275 | + </arg> |
3276 | <arg direction="out" name="backups" type="a{sa{sv}}"> |
3277 | <doc:doc> |
3278 | <doc:summary>The backups which already exist and can be restored</doc:summary> |
3279 | @@ -62,10 +84,21 @@ |
3280 | </doc:description> |
3281 | </doc:doc> |
3282 | </arg> |
3283 | + <arg direction="in" name="storage" type="s"> |
3284 | + <doc:doc> |
3285 | + <doc:summary>The storage identifier</doc:summary> |
3286 | + <doc:description> |
3287 | + <doc:para>Because keeper supports multiple storage providers the user can define |
3288 | + which is the storage provider to use. |
3289 | + If the passed storage id is an empty string the default storage provider |
3290 | + will be used.</doc:para> |
3291 | + </doc:description> |
3292 | + </doc:doc> |
3293 | + </arg> |
3294 | </method> |
3295 | |
3296 | <property name="State" type="a{sa{sv}}" access="read"> |
3297 | - <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantDictMap"/> |
3298 | + <annotation name="org.qtproject.QtDBus.QtTypeName" value="keeper::Items"/> |
3299 | <doc:doc> |
3300 | <doc:description> |
3301 | <doc:para>Provides state information so the user interface can show |
3302 | @@ -86,6 +119,17 @@ |
3303 | </doc:doc> |
3304 | </property> |
3305 | |
3306 | + <method name="GetStorageAccounts"> |
3307 | + <arg direction="out" name="accounts" type="as"> |
3308 | + <doc:doc> |
3309 | + <doc:summary>The list of available storage accounts.</doc:summary> |
3310 | + <doc:description> |
3311 | + <doc:para>An array of the available accounts to choose from to backup/restore</doc:para> |
3312 | + </doc:description> |
3313 | + </doc:doc> |
3314 | + </arg> |
3315 | + </method> |
3316 | + |
3317 | <method name="Cancel"> |
3318 | <doc:doc> |
3319 | <doc:summary>Cancels the current backup or restore actions.</doc:summary> |
3320 | |
3321 | === modified file 'src/qdbus-stubs/dbus-types.h' |
3322 | --- src/qdbus-stubs/dbus-types.h 2016-07-14 15:31:11 +0000 |
3323 | +++ src/qdbus-stubs/dbus-types.h 2017-02-27 19:05:17 +0000 |
3324 | @@ -22,7 +22,8 @@ |
3325 | #include <QtCore> |
3326 | #include <QString> |
3327 | #include <QVariantMap> |
3328 | -#include <helper/helper.h> |
3329 | +#include <client/keeper-errors.h> |
3330 | +#include "client/keeper-items.h" |
3331 | |
3332 | typedef QMap<QString, QVariantMap> QVariantDictMap; |
3333 | Q_DECLARE_METATYPE(QVariantDictMap) |
3334 | @@ -36,10 +37,13 @@ |
3335 | { |
3336 | qRegisterMetaType<QVariantDictMap>("QVariantDictMap"); |
3337 | qRegisterMetaType<QStringMap>("QStringMap"); |
3338 | + qRegisterMetaType<keeper::Error>("keeper::Error"); |
3339 | |
3340 | qDBusRegisterMetaType<QVariantDictMap>(); |
3341 | qDBusRegisterMetaType<QStringMap>(); |
3342 | - Helper::registerMetaTypes(); |
3343 | + qDBusRegisterMetaType<keeper::Error>(); |
3344 | + |
3345 | + keeper::Items::registerMetaType(); |
3346 | } |
3347 | |
3348 | constexpr const char KEEPER_SERVICE[] = "com.canonical.keeper"; |
3349 | |
3350 | === added file 'src/qdbus-stubs/org.freedesktop.DBus.Properties.xml' |
3351 | --- src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 1970-01-01 00:00:00 +0000 |
3352 | +++ src/qdbus-stubs/org.freedesktop.DBus.Properties.xml 2017-02-27 19:05:17 +0000 |
3353 | @@ -0,0 +1,27 @@ |
3354 | +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" |
3355 | + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> |
3356 | +<node> |
3357 | + <interface name="org.freedesktop.DBus.Properties"> |
3358 | + <method name="Get"> |
3359 | + <arg type="s" name="interface_name" direction="in"/> |
3360 | + <arg type="s" name="property_name" direction="in"/> |
3361 | + <arg type="v" name="value" direction="out"/> |
3362 | + </method> |
3363 | + <method name="GetAll"> |
3364 | + <arg type="s" name="interface_name" direction="in"/> |
3365 | + <arg type="a{sv}" name="properties" direction="out"/> |
3366 | + <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> |
3367 | + </method> |
3368 | + <method name="Set"> |
3369 | + <arg type="s" name="interface_name" direction="in"/> |
3370 | + <arg type="s" name="property_name" direction="in"/> |
3371 | + <arg type="v" name="value" direction="in"/> |
3372 | + </method> |
3373 | + <signal name="PropertiesChanged"> |
3374 | + <arg type="s" name="interface_name"/> |
3375 | + <arg type="a{sv}" name="changed_properties"/> |
3376 | + <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="QVariantMap"/> |
3377 | + <arg type="as" name="invalidated_properties"/> |
3378 | + </signal> |
3379 | + </interface> |
3380 | +</node> |
3381 | |
3382 | === modified file 'src/service/CMakeLists.txt' |
3383 | --- src/service/CMakeLists.txt 2016-09-06 01:31:59 +0000 |
3384 | +++ src/service/CMakeLists.txt 2017-02-27 19:05:17 +0000 |
3385 | @@ -15,6 +15,9 @@ |
3386 | task-manager.cpp |
3387 | keeper-task.cpp |
3388 | keeper-task-backup.cpp |
3389 | + keeper-task-restore.cpp |
3390 | + manifest.cpp |
3391 | + metadata-provider.h |
3392 | ) |
3393 | add_library( |
3394 | ${SERVICE_LIB} |
3395 | @@ -46,6 +49,7 @@ |
3396 | storage-framework |
3397 | util |
3398 | qdbus-stubs |
3399 | + keeper-errors-lib |
3400 | ) |
3401 | |
3402 | target_link_libraries( |
3403 | |
3404 | === modified file 'src/service/backup-choices.cpp' |
3405 | --- src/service/backup-choices.cpp 2016-09-05 18:38:36 +0000 |
3406 | +++ src/service/backup-choices.cpp 2017-02-27 19:05:17 +0000 |
3407 | @@ -45,22 +45,30 @@ |
3408 | } |
3409 | } |
3410 | |
3411 | -BackupChoices::BackupChoices() =default; |
3412 | +BackupChoices::BackupChoices(QObject *parent) |
3413 | + : MetadataProvider(parent) |
3414 | +{ |
3415 | +} |
3416 | |
3417 | BackupChoices::~BackupChoices() =default; |
3418 | |
3419 | QVector<Metadata> |
3420 | BackupChoices::get_backups() const |
3421 | { |
3422 | - QVector<Metadata> ret; |
3423 | + return backups_; |
3424 | +} |
3425 | |
3426 | +void |
3427 | +BackupChoices::get_backups_async(QString const & /*storage*/) |
3428 | +{ |
3429 | + backups_.clear(); |
3430 | // |
3431 | // System Data |
3432 | // |
3433 | { |
3434 | Metadata m(generate_new_uuid(), "System Data"); // FIXME: how to i18n in a Qt DBus service? |
3435 | - m.set_property(Metadata::TYPE_KEY, Metadata::SYSTEM_DATA_VALUE); |
3436 | - ret.push_back(m); |
3437 | + m.set_property_value(Metadata::TYPE_KEY, Metadata::SYSTEM_DATA_VALUE); |
3438 | + backups_.push_back(m); |
3439 | } |
3440 | |
3441 | // |
3442 | @@ -112,13 +120,13 @@ |
3443 | display_name = QStringLiteral("%1 (%2)").arg(display_name).arg(version.toString()); |
3444 | |
3445 | Metadata m(generate_new_uuid(), display_name); |
3446 | - m.set_property(Metadata::PACKAGE_KEY, name.toString()); |
3447 | - m.set_property(Metadata::TYPE_KEY, Metadata::APPLICATION_VALUE); |
3448 | + m.set_property_value(Metadata::PACKAGE_KEY, name.toString()); |
3449 | + m.set_property_value(Metadata::TYPE_KEY, Metadata::APPLICATION_VALUE); |
3450 | |
3451 | if (version != QJsonValue::Undefined) |
3452 | - m.set_property(Metadata::VERSION_KEY, version.toString()); |
3453 | + m.set_property_value(Metadata::VERSION_KEY, version.toString()); |
3454 | |
3455 | - ret.push_back(m); |
3456 | + backups_.push_back(m); |
3457 | } |
3458 | } |
3459 | } |
3460 | @@ -146,11 +154,11 @@ |
3461 | { |
3462 | const auto keystr = generate_new_uuid(); |
3463 | Metadata m(keystr, name); |
3464 | - m.set_property(Metadata::TYPE_KEY, Metadata::FOLDER_VALUE); |
3465 | - m.set_property(Metadata::SUBTYPE_KEY, locations.front()); |
3466 | - ret.push_back(m); |
3467 | + m.set_property_value(Metadata::TYPE_KEY, Metadata::FOLDER_VALUE); |
3468 | + m.set_property_value(Metadata::SUBTYPE_KEY, locations.front()); |
3469 | + backups_.push_back(m); |
3470 | } |
3471 | } |
3472 | |
3473 | - return ret; |
3474 | + Q_EMIT(finished(keeper::Error::OK)); |
3475 | } |
3476 | |
3477 | === modified file 'src/service/backup-choices.h' |
3478 | --- src/service/backup-choices.h 2016-09-05 18:38:36 +0000 |
3479 | +++ src/service/backup-choices.h 2017-02-27 19:05:17 +0000 |
3480 | @@ -27,7 +27,8 @@ |
3481 | class BackupChoices: public MetadataProvider |
3482 | { |
3483 | public: |
3484 | - BackupChoices(); |
3485 | + explicit BackupChoices(QObject *parent = nullptr); |
3486 | virtual ~BackupChoices(); |
3487 | QVector<Metadata> get_backups() const override; |
3488 | + void get_backups_async(QString const & storage = "") override; |
3489 | }; |
3490 | |
3491 | === modified file 'src/service/keeper-helper.cpp' |
3492 | --- src/service/keeper-helper.cpp 2016-08-10 02:06:08 +0000 |
3493 | +++ src/service/keeper-helper.cpp 2017-02-27 19:05:17 +0000 |
3494 | @@ -44,8 +44,11 @@ |
3495 | |
3496 | QDBusUnixFileDescriptor KeeperHelper::StartRestore() |
3497 | { |
3498 | - // TODO get the file descriptor of the item in storage framework |
3499 | - return QDBusUnixFileDescriptor(); |
3500 | + // pass it back to Keeper to do the work |
3501 | + Q_ASSERT(calledFromDBus()); |
3502 | + auto bus = connection(); |
3503 | + auto& msg = message(); |
3504 | + return keeper_.StartRestore(bus, msg); |
3505 | } |
3506 | |
3507 | void KeeperHelper::UpdateStatus(const QString &app_id, const QString &status, double percentage) |
3508 | |
3509 | === modified file 'src/service/keeper-task-backup.cpp' |
3510 | --- src/service/keeper-task-backup.cpp 2016-09-06 20:08:14 +0000 |
3511 | +++ src/service/keeper-task-backup.cpp 2017-02-27 19:05:17 +0000 |
3512 | @@ -31,7 +31,7 @@ |
3513 | Q_DECLARE_PUBLIC(KeeperTaskBackup) |
3514 | public: |
3515 | KeeperTaskBackupPrivate(KeeperTask * keeper_task, |
3516 | - KeeperTask::TaskData const & task_data, |
3517 | + KeeperTask::TaskData & task_data, |
3518 | QSharedPointer<HelperRegistry> const & helper_registry, |
3519 | QSharedPointer<StorageFrameworkClient> const & storage) |
3520 | : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage) |
3521 | @@ -50,33 +50,52 @@ |
3522 | qDebug() << "Initializing a backup helper"; |
3523 | helper_.reset(new BackupHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();}); |
3524 | qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created"; |
3525 | + QObject::connect(helper_.data(), &Helper::error, [this](keeper::Error error){ error_ = error;}); |
3526 | } |
3527 | |
3528 | - void ask_for_uploader(quint64 n_bytes) |
3529 | + void ask_for_uploader(quint64 n_bytes, QString const & dir_name) |
3530 | { |
3531 | qDebug() << "asking storage framework for a socket"; |
3532 | |
3533 | helper_->set_expected_size(n_bytes); |
3534 | |
3535 | + const auto file_name = QString("%1.keeper").arg(task_data_.metadata.get_display_name()); |
3536 | + |
3537 | connections_.connect_future( |
3538 | - storage_->get_new_uploader(n_bytes), |
3539 | + storage_->get_new_uploader(n_bytes, dir_name, file_name), |
3540 | std::function<void(std::shared_ptr<Uploader> const&)>{ |
3541 | [this](std::shared_ptr<Uploader> const& uploader){ |
3542 | - qDebug("calling helper.set_storage_framework_socket(socket=%d)", int(uploader->socket()->socketDescriptor())); |
3543 | - qDebug() << "Helper is " << static_cast<void*>(helper_.data()); |
3544 | - auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_); |
3545 | - backup_helper->set_uploader(uploader); |
3546 | - Q_EMIT(q_ptr->task_socket_ready(backup_helper->get_helper_socket())); |
3547 | + auto fd {-1}; |
3548 | + if (uploader) { |
3549 | + auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_); |
3550 | + backup_helper->set_uploader(uploader); |
3551 | + fd = backup_helper->get_helper_socket(); |
3552 | + qDebug("emitting task_socket_ready(socket=%d)", fd); |
3553 | + Q_EMIT(q_ptr->task_socket_ready(fd)); |
3554 | + } |
3555 | + else |
3556 | + { |
3557 | + error_ = storage_->get_last_error(); |
3558 | + qDebug("Emitting task_socket_error(error=%d)", static_cast<int>(error_)); |
3559 | + Q_EMIT(q_ptr->task_socket_error(error_)); |
3560 | + } |
3561 | } |
3562 | } |
3563 | ); |
3564 | } |
3565 | |
3566 | + QString get_file_name() const |
3567 | + { |
3568 | + auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_); |
3569 | + return backup_helper->get_uploader_committed_file_name(); |
3570 | + } |
3571 | + |
3572 | private: |
3573 | ConnectionHelper connections_; |
3574 | + QString file_name_; |
3575 | }; |
3576 | |
3577 | -KeeperTaskBackup::KeeperTaskBackup(TaskData const & task_data, |
3578 | +KeeperTaskBackup::KeeperTaskBackup(TaskData & task_data, |
3579 | QSharedPointer<HelperRegistry> const & helper_registry, |
3580 | QSharedPointer<StorageFrameworkClient> const & storage, |
3581 | QObject *parent) |
3582 | @@ -89,17 +108,27 @@ |
3583 | QStringList KeeperTaskBackup::get_helper_urls() const |
3584 | { |
3585 | Q_D(const KeeperTaskBackup); |
3586 | + |
3587 | return d->get_helper_urls(); |
3588 | } |
3589 | |
3590 | void KeeperTaskBackup::init_helper() |
3591 | { |
3592 | Q_D(KeeperTaskBackup); |
3593 | + |
3594 | d->init_helper(); |
3595 | } |
3596 | |
3597 | -void KeeperTaskBackup::ask_for_uploader(quint64 n_bytes) |
3598 | +void KeeperTaskBackup::ask_for_uploader(quint64 n_bytes, QString const & dir_name) |
3599 | { |
3600 | Q_D(KeeperTaskBackup); |
3601 | - d->ask_for_uploader(n_bytes); |
3602 | + |
3603 | + d->ask_for_uploader(n_bytes, dir_name); |
3604 | +} |
3605 | + |
3606 | +QString KeeperTaskBackup::get_file_name() const |
3607 | +{ |
3608 | + Q_D(const KeeperTaskBackup); |
3609 | + |
3610 | + return d->get_file_name(); |
3611 | } |
3612 | |
3613 | === modified file 'src/service/keeper-task-backup.h' |
3614 | --- src/service/keeper-task-backup.h 2016-09-06 02:13:34 +0000 |
3615 | +++ src/service/keeper-task-backup.h 2017-02-27 19:05:17 +0000 |
3616 | @@ -29,7 +29,7 @@ |
3617 | Q_DECLARE_PRIVATE(KeeperTaskBackup) |
3618 | public: |
3619 | |
3620 | - KeeperTaskBackup(TaskData const & task_data, |
3621 | + KeeperTaskBackup(TaskData & task_data, |
3622 | QSharedPointer<HelperRegistry> const & helper_registry, |
3623 | QSharedPointer<StorageFrameworkClient> const & storage, |
3624 | QObject *parent = nullptr); |
3625 | @@ -37,7 +37,9 @@ |
3626 | |
3627 | Q_DISABLE_COPY(KeeperTaskBackup) |
3628 | |
3629 | - void ask_for_uploader(quint64 n_bytes); |
3630 | + void ask_for_uploader(quint64 n_bytes, QString const & dir_name); |
3631 | + |
3632 | + QString get_file_name() const; |
3633 | |
3634 | protected: |
3635 | QStringList get_helper_urls() const override; |
3636 | |
3637 | === added file 'src/service/keeper-task-restore.cpp' |
3638 | --- src/service/keeper-task-restore.cpp 1970-01-01 00:00:00 +0000 |
3639 | +++ src/service/keeper-task-restore.cpp 2017-02-27 19:05:17 +0000 |
3640 | @@ -0,0 +1,130 @@ |
3641 | +/* |
3642 | + * Copyright (C) 2016 Canonical, Ltd. |
3643 | + * |
3644 | + * This program is free software: you can redistribute it and/or modify it |
3645 | + * under the terms of the GNU General Public License version 3, as published |
3646 | + * by the Free Software Foundation. |
3647 | + * |
3648 | + * This program is distributed in the hope that it will be useful, but |
3649 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3650 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3651 | + * PURPOSE. See the GNU General Public License for more details. |
3652 | + * |
3653 | + * You should have received a copy of the GNU General Public License along |
3654 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3655 | + * |
3656 | + * Authors: |
3657 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
3658 | + * Charles Kerr <charles.kerr@canonical.com> |
3659 | + */ |
3660 | + |
3661 | +#include "util/connection-helper.h" |
3662 | +#include "storage-framework/storage_framework_client.h" |
3663 | +#include "helper/restore-helper.h" |
3664 | +#include "service/app-const.h" // DEKKO_APP_ID |
3665 | +#include "service/keeper-task-restore.h" |
3666 | +#include "service/keeper-task.h" |
3667 | +#include "service/private/keeper-task_p.h" |
3668 | + |
3669 | +namespace sf = unity::storage::qt::client; |
3670 | + |
3671 | +class KeeperTaskRestorePrivate : public KeeperTaskPrivate |
3672 | +{ |
3673 | + Q_DECLARE_PUBLIC(KeeperTaskRestore) |
3674 | +public: |
3675 | + KeeperTaskRestorePrivate(KeeperTask * keeper_task, |
3676 | + KeeperTask::TaskData & task_data, |
3677 | + QSharedPointer<HelperRegistry> const & helper_registry, |
3678 | + QSharedPointer<StorageFrameworkClient> const & storage) |
3679 | + : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage) |
3680 | + { |
3681 | + } |
3682 | + |
3683 | + ~KeeperTaskRestorePrivate() = default; |
3684 | + |
3685 | + QStringList get_helper_urls() const |
3686 | + { |
3687 | + return helper_registry_->get_restore_helper_urls(task_data_.metadata); |
3688 | + } |
3689 | + |
3690 | + void init_helper() |
3691 | + { |
3692 | + helper_.reset(new RestoreHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();}); |
3693 | + qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created"; |
3694 | + } |
3695 | + |
3696 | + void ask_for_downloader() |
3697 | + { |
3698 | + qDebug() << "asking storage framework for a socket for reading"; |
3699 | + |
3700 | + auto file_name = task_data_.metadata.get_file_name(); |
3701 | + if (file_name.isEmpty()) |
3702 | + { |
3703 | + qWarning() << "ERROR: the restore task does not provide a valid file name to read from."; |
3704 | + return; |
3705 | + } |
3706 | + |
3707 | + auto dir_name = task_data_.metadata.get_dir_name(); |
3708 | + if (dir_name.isEmpty()) |
3709 | + { |
3710 | + qWarning() << "ERROR: the restore task does not provide a valid directory name."; |
3711 | + return; |
3712 | + } |
3713 | + |
3714 | + // extract the dir_name. |
3715 | + connections_.connect_future( |
3716 | + storage_->get_new_downloader(dir_name, file_name), |
3717 | + std::function<void(std::shared_ptr<Downloader> const&)>{ |
3718 | + [this](std::shared_ptr<Downloader> const& downloader){ |
3719 | + auto fd {-1}; |
3720 | + if (downloader) { |
3721 | + auto restore_helper = qSharedPointerDynamicCast<RestoreHelper>(helper_); |
3722 | + restore_helper->set_downloader(downloader); |
3723 | + fd = restore_helper->get_helper_socket(); |
3724 | + Q_EMIT(q_ptr->task_socket_ready(fd)); |
3725 | + } |
3726 | + else |
3727 | + { |
3728 | + error_ = storage_->get_last_error(); |
3729 | + qDebug("Emitting task_socket_error(error=%d)", static_cast<int>(error_)); |
3730 | + Q_EMIT(q_ptr->task_socket_error(error_)); |
3731 | + } |
3732 | + } |
3733 | + } |
3734 | + ); |
3735 | + } |
3736 | + |
3737 | +private: |
3738 | + ConnectionHelper connections_; |
3739 | +}; |
3740 | + |
3741 | +KeeperTaskRestore::KeeperTaskRestore(TaskData & task_data, |
3742 | + QSharedPointer<HelperRegistry> const & helper_registry, |
3743 | + QSharedPointer<StorageFrameworkClient> const & storage, |
3744 | + QObject *parent) |
3745 | + : KeeperTask(*new KeeperTaskRestorePrivate(this, task_data, helper_registry, storage), parent) |
3746 | +{ |
3747 | +} |
3748 | + |
3749 | +KeeperTaskRestore::~KeeperTaskRestore() = default; |
3750 | + |
3751 | +QStringList KeeperTaskRestore::get_helper_urls() const |
3752 | +{ |
3753 | + Q_D(const KeeperTaskRestore); |
3754 | + |
3755 | + return d->get_helper_urls(); |
3756 | +} |
3757 | + |
3758 | +void KeeperTaskRestore::init_helper() |
3759 | +{ |
3760 | + Q_D(KeeperTaskRestore); |
3761 | + |
3762 | + d->init_helper(); |
3763 | +} |
3764 | + |
3765 | +void KeeperTaskRestore::ask_for_downloader() |
3766 | +{ |
3767 | + Q_D(KeeperTaskRestore); |
3768 | + |
3769 | + d->ask_for_downloader(); |
3770 | +} |
3771 | |
3772 | === added file 'src/service/keeper-task-restore.h' |
3773 | --- src/service/keeper-task-restore.h 1970-01-01 00:00:00 +0000 |
3774 | +++ src/service/keeper-task-restore.h 2017-02-27 19:05:17 +0000 |
3775 | @@ -0,0 +1,46 @@ |
3776 | +/* |
3777 | + * Copyright (C) 2016 Canonical, Ltd. |
3778 | + * |
3779 | + * This program is free software: you can redistribute it and/or modify it |
3780 | + * under the terms of the GNU General Public License version 3, as published |
3781 | + * by the Free Software Foundation. |
3782 | + * |
3783 | + * This program is distributed in the hope that it will be useful, but |
3784 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
3785 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3786 | + * PURPOSE. See the GNU General Public License for more details. |
3787 | + * |
3788 | + * You should have received a copy of the GNU General Public License along |
3789 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
3790 | + * |
3791 | + * Authors: |
3792 | + * Xavi Garcia <xavi.garcia.mena@canonical.com> |
3793 | + * Charles Kerr <charles.kerr@canonical.com> |
3794 | + */ |
3795 | +#pragma once |
3796 | + |
3797 | +#include "keeper-task.h" |
3798 | + |
3799 | +class KeeperTaskRestorePrivate; |
3800 | + |
3801 | +class KeeperTaskRestore : public KeeperTask |
3802 | +{ |
3803 | + Q_OBJECT |
3804 | + Q_DECLARE_PRIVATE(KeeperTaskRestore) |
3805 | +public: |
3806 | + |
3807 | + KeeperTaskRestore(TaskData & task_data, |
3808 | + QSharedPointer<HelperRegistry> const & helper_registry, |
3809 | + QSharedPointer<StorageFrameworkClient> const & storage, |
3810 | + QObject *parent = nullptr); |
3811 | + virtual ~KeeperTaskRestore(); |
3812 | + |
3813 | + Q_DISABLE_COPY(KeeperTaskRestore) |
3814 | + |
3815 | + void ask_for_downloader(); |
3816 | + |
3817 | +protected: |
3818 | + QStringList get_helper_urls() const override; |
3819 | + void init_helper() override; |
3820 | + |
3821 | +}; |
3822 | |
3823 | === modified file 'src/service/keeper-task.cpp' |
3824 | --- src/service/keeper-task.cpp 2016-09-13 08:47:14 +0000 |
3825 | +++ src/service/keeper-task.cpp 2017-02-27 19:05:17 +0000 |
3826 | @@ -28,13 +28,14 @@ |
3827 | #include <QString> |
3828 | |
3829 | KeeperTaskPrivate::KeeperTaskPrivate(KeeperTask * keeper_task, |
3830 | - KeeperTask::TaskData const & task_data, |
3831 | + KeeperTask::TaskData & task_data, |
3832 | QSharedPointer<HelperRegistry> const & helper_registry, |
3833 | QSharedPointer<StorageFrameworkClient> const & storage) |
3834 | : q_ptr(keeper_task) |
3835 | , task_data_(task_data) |
3836 | , helper_registry_(helper_registry) |
3837 | , storage_(storage) |
3838 | + , error_(keeper::Error::OK) |
3839 | { |
3840 | } |
3841 | |
3842 | @@ -49,8 +50,8 @@ |
3843 | if (urls.isEmpty()) |
3844 | { |
3845 | task_data_.action = helper_->to_string(Helper::State::FAILED); |
3846 | - task_data_.error = "no helper information in registry"; |
3847 | - qWarning() << "ERROR: uuid: " << task_data_.metadata.uuid() << " has no url"; |
3848 | + error_ = keeper::Error::HELPER_BAD_URL; |
3849 | + qWarning() << QStringLiteral("Error: uuid %1 has no url").arg(task_data_.metadata.get_uuid()); |
3850 | calculate_and_notify_state(Helper::State::FAILED); |
3851 | return false; |
3852 | } |
3853 | @@ -65,6 +66,10 @@ |
3854 | std::bind(&KeeperTaskPrivate::on_helper_percent_done_changed, this, std::placeholders::_1) |
3855 | ); |
3856 | |
3857 | + QObject::connect(helper_.data(), &Helper::error, [this](keeper::Error error){ |
3858 | + error_ = error; |
3859 | + }); |
3860 | + |
3861 | helper_->start(urls); |
3862 | return true; |
3863 | } |
3864 | @@ -120,22 +125,28 @@ |
3865 | { |
3866 | QVariantMap ret; |
3867 | |
3868 | - auto const uuid = task_data_.metadata.uuid(); |
3869 | - |
3870 | - ret.insert(QStringLiteral("action"), task_data_.action); |
3871 | - |
3872 | - ret.insert(QStringLiteral("display-name"), task_data_.metadata.display_name()); |
3873 | + auto const uuid = task_data_.metadata.get_uuid(); |
3874 | + |
3875 | + ret.insert(keeper::Item::STATUS_KEY, task_data_.action); |
3876 | + ret.insert(keeper::Item::DISPLAY_NAME_KEY, task_data_.metadata.get_display_name()); |
3877 | |
3878 | auto const speed = helper_->speed(); |
3879 | - ret.insert(QStringLiteral("speed"), int32_t(speed)); |
3880 | + ret.insert(keeper::Item::SPEED_KEY, int32_t(speed)); |
3881 | |
3882 | auto const percent_done = helper_->percent_done(); |
3883 | - ret.insert(QStringLiteral("percent-done"), double(percent_done)); |
3884 | - |
3885 | - if (task_data_.action == "failed") |
3886 | - ret.insert(QStringLiteral("error"), task_data_.error); |
3887 | - |
3888 | - ret.insert(QStringLiteral("uuid"), uuid); |
3889 | + ret.insert(keeper::Item::PERCENT_DONE_KEY, double(percent_done)); |
3890 | + |
3891 | + if (task_data_.action == "failed" || task_data_.action == "cancelled") |
3892 | + { |
3893 | + auto error = error_; |
3894 | + if (task_data_.error != keeper::Error::OK) |
3895 | + { |
3896 | + error = task_data_.error; |
3897 | + } |
3898 | + ret.insert(keeper::Item::ERROR_KEY, QVariant::fromValue(error)); |
3899 | + } |
3900 | + |
3901 | + ret.insert(keeper::Item::UUID_KEY, uuid); |
3902 | |
3903 | QJsonDocument doc(QJsonObject::fromVariantMap(ret)); |
3904 | qDebug() << QString(doc.toJson(QJsonDocument::Compact)); |
3905 | @@ -145,29 +156,60 @@ |
3906 | |
3907 | void KeeperTaskPrivate::calculate_and_notify_state(Helper::State state) |
3908 | { |
3909 | + recalculate_task_state(); |
3910 | + Q_EMIT(q_ptr->task_state_changed(state)); |
3911 | +} |
3912 | + |
3913 | +void KeeperTaskPrivate::recalculate_task_state() |
3914 | +{ |
3915 | state_ = calculate_task_state(); |
3916 | - Q_EMIT(q_ptr->task_state_changed(state)); |
3917 | +} |
3918 | + |
3919 | +void KeeperTaskPrivate::cancel() |
3920 | +{ |
3921 | + if (helper_) |
3922 | + { |
3923 | + helper_->stop(); |
3924 | + } |
3925 | } |
3926 | |
3927 | QVariantMap KeeperTaskPrivate::get_initial_state(KeeperTask::TaskData const &td) |
3928 | { |
3929 | QVariantMap ret; |
3930 | |
3931 | - auto const uuid = td.metadata.uuid(); |
3932 | + auto const uuid = td.metadata.get_uuid(); |
3933 | |
3934 | - ret.insert(QStringLiteral("action"), td.action); |
3935 | + ret.insert(keeper::Item::STATUS_KEY, td.action); |
3936 | |
3937 | // TODO review this when we add the restore tasks. |
3938 | // TODO we maybe have different fields |
3939 | - ret.insert(QStringLiteral("display-name"), td.metadata.display_name()); |
3940 | - ret.insert(QStringLiteral("speed"), 0); |
3941 | - ret.insert(QStringLiteral("percent-done"), double(0.0)); |
3942 | - ret.insert(QStringLiteral("uuid"), uuid); |
3943 | + ret.insert(keeper::Item::DISPLAY_NAME_KEY, td.metadata.get_display_name()); |
3944 | + ret.insert(keeper::Item::SPEED_KEY, 0); |
3945 | + ret.insert(keeper::Item::PERCENT_DONE_KEY, double(0.0)); |
3946 | + ret.insert(keeper::Item::UUID_KEY, uuid); |
3947 | |
3948 | return ret; |
3949 | } |
3950 | |
3951 | -KeeperTask::KeeperTask(TaskData const & task_data, |
3952 | +QString KeeperTaskPrivate::to_string(Helper::State state) |
3953 | +{ |
3954 | + if (helper_) |
3955 | + { |
3956 | + return helper_->to_string(state); |
3957 | + } |
3958 | + else |
3959 | + { |
3960 | + qWarning() << "Asking for the string of a state when the helper is not initialized yet"; |
3961 | + return "bug"; |
3962 | + } |
3963 | +} |
3964 | + |
3965 | +keeper::Error KeeperTaskPrivate::error() const |
3966 | +{ |
3967 | + return error_; |
3968 | +} |
3969 | + |
3970 | +KeeperTask::KeeperTask(TaskData & task_data, |
3971 | QSharedPointer<HelperRegistry> const & helper_registry, |
3972 | QSharedPointer<StorageFrameworkClient> const & storage, |
3973 | QObject *parent) |
3974 | @@ -188,16 +230,47 @@ |
3975 | bool KeeperTask::start() |
3976 | { |
3977 | Q_D(KeeperTask); |
3978 | + |
3979 | return d->start(); |
3980 | } |
3981 | |
3982 | QVariantMap KeeperTask::state() const |
3983 | { |
3984 | Q_D(const KeeperTask); |
3985 | + |
3986 | return d->state(); |
3987 | } |
3988 | |
3989 | +void KeeperTask::recalculate_task_state() |
3990 | +{ |
3991 | + Q_D(KeeperTask); |
3992 | + |
3993 | + return d->recalculate_task_state(); |
3994 | +} |
3995 | + |
3996 | + |
3997 | QVariantMap KeeperTask::get_initial_state(KeeperTask::TaskData const &td) |
3998 | { |
3999 | return KeeperTaskPrivate::get_initial_state(td); |
4000 | } |
4001 | + |
4002 | +void KeeperTask::cancel() |
4003 | +{ |
4004 | + Q_D(KeeperTask); |
4005 | + |
4006 | + return d->cancel(); |
4007 | +} |
4008 | + |
4009 | +QString KeeperTask::to_string(Helper::State state) |
4010 | +{ |
4011 | + Q_D(KeeperTask); |
4012 | + |
4013 | + return d->to_string(state); |
4014 | +} |
4015 | + |
4016 | +keeper::Error KeeperTask::error() const |
4017 | +{ |
4018 | + Q_D(const KeeperTask); |
4019 | + |
4020 | + return d->error(); |
4021 | +} |
4022 | |
4023 | === modified file 'src/service/keeper-task.h' |
4024 | --- src/service/keeper-task.h 2016-09-07 17:07:23 +0000 |
4025 | +++ src/service/keeper-task.h 2017-02-27 19:05:17 +0000 |
4026 | @@ -20,6 +20,7 @@ |
4027 | |
4028 | #pragma once |
4029 | |
4030 | +#include "client/keeper-errors.h" |
4031 | #include "helper/metadata.h" |
4032 | #include "helper/backup-helper.h" |
4033 | #include "helper/helper.h" |
4034 | @@ -40,11 +41,11 @@ |
4035 | struct TaskData |
4036 | { |
4037 | QString action; |
4038 | - QString error; |
4039 | + keeper::Error error; |
4040 | Metadata metadata; |
4041 | }; |
4042 | |
4043 | - KeeperTask(TaskData const & task_data, |
4044 | + KeeperTask(TaskData & task_data, |
4045 | QSharedPointer<HelperRegistry> const & helper_registry, |
4046 | QSharedPointer<StorageFrameworkClient> const & storage, |
4047 | QObject *parent = nullptr); |
4048 | @@ -54,12 +55,19 @@ |
4049 | |
4050 | bool start(); |
4051 | QVariantMap state() const; |
4052 | + void recalculate_task_state(); |
4053 | |
4054 | static QVariantMap get_initial_state(KeeperTask::TaskData const &td); |
4055 | |
4056 | + void cancel(); |
4057 | + |
4058 | + QString to_string(Helper::State state); |
4059 | + |
4060 | + keeper::Error error() const; |
4061 | Q_SIGNALS: |
4062 | void task_state_changed(Helper::State state); |
4063 | void task_socket_ready(int socket_descriptor); |
4064 | + void task_socket_error(keeper::Error error); |
4065 | |
4066 | protected: |
4067 | KeeperTask(KeeperTaskPrivate & d, QObject *parent = nullptr); |
4068 | |
4069 | === modified file 'src/service/keeper-user.cpp' |
4070 | --- src/service/keeper-user.cpp 2016-09-07 16:35:26 +0000 |
4071 | +++ src/service/keeper-user.cpp 2017-02-27 19:05:17 +0000 |
4072 | @@ -33,75 +33,67 @@ |
4073 | |
4074 | KeeperUser::~KeeperUser() =default; |
4075 | |
4076 | -namespace |
4077 | -{ |
4078 | - QVariantMap strings_to_variants(const QMap<QString,QString>& strings) |
4079 | - { |
4080 | - QVariantMap variants; |
4081 | - |
4082 | - for (auto it=strings.begin(), end=strings.end(); it!=end; ++it) |
4083 | - variants.insert(it.key(), QVariant::fromValue(it.value())); |
4084 | - |
4085 | - return variants; |
4086 | - } |
4087 | - |
4088 | - QVariantDictMap choices_to_variant_dict_map(const QVector<Metadata>& choices) |
4089 | - { |
4090 | - QVariantDictMap ret; |
4091 | - |
4092 | - for (auto const& metadata : choices) |
4093 | - ret.insert(metadata.uuid(), strings_to_variants(metadata.get_public_properties())); |
4094 | - |
4095 | - return ret; |
4096 | - } |
4097 | -} |
4098 | - |
4099 | -QVariantDictMap |
4100 | +keeper::Items |
4101 | KeeperUser::GetBackupChoices() |
4102 | { |
4103 | - return choices_to_variant_dict_map(keeper_.get_backup_choices()); |
4104 | + auto bus = connection(); |
4105 | + auto& msg = message(); |
4106 | + return keeper_.get_backup_choices_var_dict_map(bus, msg); |
4107 | } |
4108 | |
4109 | void |
4110 | -KeeperUser::StartBackup (const QStringList& keys) |
4111 | +KeeperUser::StartBackup (const QStringList& keys, QString const & storage) |
4112 | { |
4113 | Q_ASSERT(calledFromDBus()); |
4114 | |
4115 | - auto const unhandled = keeper_.start_tasks(keys); |
4116 | - |
4117 | - if (!unhandled.empty()) |
4118 | - { |
4119 | - QString text = QStringLiteral("unhandled uuids:"); |
4120 | - for (auto const& uuid : unhandled) |
4121 | - text += ' ' + uuid; |
4122 | - connection().send(message().createErrorReply(QDBusError::InvalidArgs, text)); |
4123 | - } |
4124 | + auto bus = connection(); |
4125 | + auto& msg = message(); |
4126 | + keeper_.start_tasks(keys, storage, bus, msg); |
4127 | } |
4128 | |
4129 | void |
4130 | KeeperUser::Cancel() |
4131 | { |
4132 | - // FIXME: writeme |
4133 | - |
4134 | - qDebug() << "hello world"; |
4135 | + keeper_.cancel(); |
4136 | } |
4137 | |
4138 | -QVariantDictMap |
4139 | -KeeperUser::GetRestoreChoices() |
4140 | +keeper::Items |
4141 | +KeeperUser::GetRestoreChoices(QString const & storage) |
4142 | { |
4143 | - return choices_to_variant_dict_map(keeper_.get_restore_choices()); |
4144 | + Q_ASSERT(calledFromDBus()); |
4145 | + |
4146 | + auto bus = connection(); |
4147 | + auto& msg = message(); |
4148 | + return keeper_.get_restore_choices(storage, bus, msg); |
4149 | } |
4150 | |
4151 | void |
4152 | -KeeperUser::StartRestore (const QStringList& keys) |
4153 | +KeeperUser::StartRestore (const QStringList& keys, QString const & storage) |
4154 | { |
4155 | - // FIXME: writeme |
4156 | + Q_ASSERT(calledFromDBus()); |
4157 | |
4158 | - qDebug() << keys; |
4159 | + auto bus = connection(); |
4160 | + auto& msg = message(); |
4161 | + // if we start a restore right after a backup the uuid |
4162 | + // will be found as a backup uuid. |
4163 | + // Just clear the backup cache to avoid that. |
4164 | + keeper_.invalidate_choices_cache(); |
4165 | + keeper_.start_tasks(keys, storage, bus, msg); |
4166 | } |
4167 | |
4168 | -QVariantDictMap |
4169 | +keeper::Items |
4170 | KeeperUser::get_state() const |
4171 | { |
4172 | return keeper_.get_state(); |
4173 | } |
4174 | + |
4175 | +QStringList |
4176 | +KeeperUser::GetStorageAccounts() |
4177 | +{ |
4178 | + Q_ASSERT(calledFromDBus()); |
4179 | + |
4180 | + auto bus = connection(); |
4181 | + auto& msg = message(); |
4182 | + |
4183 | + return keeper_.get_storage_accounts(bus, msg); |
4184 | +} |
4185 | |
4186 | === modified file 'src/service/keeper-user.h' |
4187 | --- src/service/keeper-user.h 2016-09-05 18:38:36 +0000 |
4188 | +++ src/service/keeper-user.h 2017-02-27 19:05:17 +0000 |
4189 | @@ -37,11 +37,11 @@ |
4190 | virtual ~KeeperUser(); |
4191 | Q_DISABLE_COPY(KeeperUser) |
4192 | |
4193 | - Q_PROPERTY(QVariantDictMap State |
4194 | + Q_PROPERTY(keeper::Items State |
4195 | READ get_state |
4196 | NOTIFY state_changed) |
4197 | |
4198 | - QVariantDictMap get_state() const; |
4199 | + keeper::Items get_state() const; |
4200 | |
4201 | Q_SIGNALS: |
4202 | |
4203 | @@ -49,14 +49,16 @@ |
4204 | |
4205 | public Q_SLOTS: |
4206 | |
4207 | - QVariantDictMap GetBackupChoices(); |
4208 | - void StartBackup(const QStringList&); |
4209 | + keeper::Items GetBackupChoices(); |
4210 | + void StartBackup(const QStringList&, QString const & storage); |
4211 | |
4212 | - QVariantDictMap GetRestoreChoices(); |
4213 | - void StartRestore(const QStringList&); |
4214 | + keeper::Items GetRestoreChoices(QString const & storage); |
4215 | + void StartRestore(const QStringList&, QString const & storage); |
4216 | |
4217 | void Cancel(); |
4218 | |
4219 | + QStringList GetStorageAccounts(); |
4220 | + |
4221 | private: |
4222 | |
4223 | Keeper& keeper_; |
4224 | |
4225 | === modified file 'src/service/keeper.cpp' |
4226 | --- src/service/keeper.cpp 2016-09-07 16:35:26 +0000 |
4227 | +++ src/service/keeper.cpp 2017-02-27 19:05:17 +0000 |
4228 | @@ -32,78 +32,232 @@ |
4229 | #include <QVector> |
4230 | |
4231 | #include <algorithm> // std::find_if |
4232 | - |
4233 | -class KeeperPrivate |
4234 | -{ |
4235 | +#include <unistd.h> |
4236 | + |
4237 | +namespace |
4238 | +{ |
4239 | +// QVariantMap strings_to_variants(const QMap<QString,QString>& strings) |
4240 | +// { |
4241 | +// QVariantMap variants; |
4242 | +// |
4243 | +// for (auto it=strings.begin(), end=strings.end(); it!=end; ++it) |
4244 | +// variants.insert(it.key(), QVariant::fromValue(it.value())); |
4245 | +// |
4246 | +// return variants; |
4247 | +// } |
4248 | + |
4249 | + keeper::Items choices_to_variant_dict_map(QVector<Metadata> const & choices) |
4250 | + { |
4251 | + keeper::Items ret; |
4252 | + |
4253 | + for (auto const& metadata : choices) |
4254 | + { |
4255 | + keeper::Item value(metadata); |
4256 | + ret.insert(metadata.get_uuid(), value); |
4257 | + } |
4258 | + |
4259 | + return ret; |
4260 | + } |
4261 | +} |
4262 | + |
4263 | +class KeeperPrivate : public QObject |
4264 | +{ |
4265 | + Q_OBJECT |
4266 | public: |
4267 | |
4268 | KeeperPrivate(Keeper* keeper, |
4269 | const QSharedPointer<HelperRegistry>& helper_registry, |
4270 | const QSharedPointer<MetadataProvider>& backup_choices, |
4271 | - const QSharedPointer<MetadataProvider>& restore_choices) |
4272 | - : q_ptr(keeper) |
4273 | + const QSharedPointer<MetadataProvider>& restore_choices, |
4274 | + QObject *parent = nullptr) |
4275 | + : QObject(parent) |
4276 | + , q_ptr(keeper) |
4277 | , storage_(new StorageFrameworkClient()) |
4278 | , helper_registry_(helper_registry) |
4279 | , backup_choices_(backup_choices) |
4280 | , restore_choices_(restore_choices) |
4281 | , task_manager_{helper_registry, storage_} |
4282 | { |
4283 | + QObject::connect(&task_manager_, &TaskManager::finished, |
4284 | + std::bind(&KeeperPrivate::on_task_manager_finished, this) |
4285 | + ); |
4286 | } |
4287 | |
4288 | + enum class ChoicesType { BACKUP_CHOICES, RESTORES_CHOICES }; |
4289 | + |
4290 | ~KeeperPrivate() =default; |
4291 | |
4292 | Q_DISABLE_COPY(KeeperPrivate) |
4293 | |
4294 | - QStringList start_tasks(QStringList const & uuids) |
4295 | + void start_tasks(QStringList const & uuids, |
4296 | + QString const & storage, |
4297 | + QDBusConnection bus, |
4298 | + QDBusMessage const & msg) |
4299 | { |
4300 | - auto unhandled = QSet<QString>::fromList(uuids); |
4301 | - |
4302 | auto get_tasks = [](const QVector<Metadata>& pool, QStringList const& keys){ |
4303 | QMap<QString,Metadata> tasks; |
4304 | for (auto const& key : keys) { |
4305 | - auto it = std::find_if(pool.begin(), pool.end(), [key](Metadata const & m){return m.uuid()==key;}); |
4306 | + auto it = std::find_if(pool.begin(), pool.end(), [key](Metadata const & m){return m.get_uuid()==key;}); |
4307 | if (it != pool.end()) |
4308 | tasks[key] = *it; |
4309 | } |
4310 | return tasks; |
4311 | }; |
4312 | |
4313 | - auto tasks = get_tasks(get_backup_choices(), uuids); |
4314 | - if (!tasks.empty()) |
4315 | - { |
4316 | - if (task_manager_.start_backup(tasks.values())) |
4317 | - unhandled.subtract(QSet<QString>::fromList(tasks.keys())); |
4318 | + // async part |
4319 | + qDebug() << "Looking for backup options...."; |
4320 | + connections_.connect_oneshot( |
4321 | + this, |
4322 | + &KeeperPrivate::backup_choices_ready, |
4323 | + std::function<void()>{[this, uuids, msg, bus, get_tasks, storage](){ |
4324 | + auto tasks = get_tasks(cached_backup_choices_, uuids); |
4325 | + if (!tasks.empty()) |
4326 | + { |
4327 | + auto unhandled = QSet<QString>::fromList(uuids); |
4328 | + if (task_manager_.start_backup(tasks.values(), storage)) |
4329 | + unhandled.subtract(QSet<QString>::fromList(tasks.keys())); |
4330 | + |
4331 | + check_for_unhandled_tasks_and_reply(unhandled, bus, msg); |
4332 | + } |
4333 | + else // restore |
4334 | + { |
4335 | + qDebug() << "Looking for restore options...."; |
4336 | + connections_.connect_oneshot( |
4337 | + this, |
4338 | + &KeeperPrivate::restore_choices_ready, |
4339 | + std::function<void(keeper::Error)>{[this, uuids, msg, bus, get_tasks, storage](keeper::Error error){ |
4340 | + qDebug() << "Choices ready"; |
4341 | + auto unhandled = QSet<QString>::fromList(uuids); |
4342 | + if (error == keeper::Error::OK) |
4343 | + { |
4344 | + auto restore_tasks = get_tasks(cached_restore_choices_, uuids); |
4345 | + qDebug() << "After getting tasks..."; |
4346 | + if (!restore_tasks.empty() && task_manager_.start_restore(restore_tasks.values(), storage)) |
4347 | + unhandled.subtract(QSet<QString>::fromList(restore_tasks.keys())); |
4348 | + } |
4349 | + check_for_unhandled_tasks_and_reply(unhandled, bus, msg); |
4350 | + }} |
4351 | + ); |
4352 | + get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES); |
4353 | + } |
4354 | + }} |
4355 | + ); |
4356 | + |
4357 | + get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES); |
4358 | + msg.setDelayedReply(true); |
4359 | + } |
4360 | + |
4361 | + void emit_choices_ready(ChoicesType type, keeper::Error error) |
4362 | + { |
4363 | + switch(type) |
4364 | + { |
4365 | + case KeeperPrivate::ChoicesType::BACKUP_CHOICES: |
4366 | + Q_EMIT(backup_choices_ready(error)); |
4367 | + break; |
4368 | + case KeeperPrivate::ChoicesType::RESTORES_CHOICES: |
4369 | + Q_EMIT(restore_choices_ready(error)); |
4370 | + break; |
4371 | + } |
4372 | + } |
4373 | + |
4374 | + void get_choices(const QSharedPointer<MetadataProvider> & provider, ChoicesType type, QString const & storage = "") |
4375 | + { |
4376 | + bool check_empty = (type == KeeperPrivate::ChoicesType::BACKUP_CHOICES) |
4377 | + ? cached_backup_choices_.isEmpty() : cached_restore_choices_.isEmpty(); |
4378 | + if (check_empty) |
4379 | + { |
4380 | + connections_.connect_oneshot( |
4381 | + provider.data(), |
4382 | + &MetadataProvider::finished, |
4383 | + std::function<void(keeper::Error)>{[this, provider, type](keeper::Error error){ |
4384 | + qDebug() << "Get choices finished"; |
4385 | + if (error == keeper::Error::OK) |
4386 | + { |
4387 | + switch (type) |
4388 | + { |
4389 | + case KeeperPrivate::ChoicesType::BACKUP_CHOICES: |
4390 | + cached_backup_choices_ = provider->get_backups(); |
4391 | + break; |
4392 | + case KeeperPrivate::ChoicesType::RESTORES_CHOICES: |
4393 | + cached_restore_choices_ = provider->get_backups(); |
4394 | + break; |
4395 | + } |
4396 | + } |
4397 | + emit_choices_ready(type, error); |
4398 | + }} |
4399 | + ); |
4400 | + provider->get_backups_async(storage); |
4401 | } |
4402 | else |
4403 | { |
4404 | - tasks = get_tasks(get_restore_choices(), uuids); |
4405 | - if (!tasks.empty() && task_manager_.start_restore(tasks.values())) |
4406 | - unhandled.subtract(QSet<QString>::fromList(tasks.keys())); |
4407 | + emit_choices_ready(type, keeper::Error::OK); |
4408 | } |
4409 | - |
4410 | - if (!unhandled.empty()) |
4411 | - qWarning() << "skipped tasks" << unhandled; |
4412 | - |
4413 | - return QStringList::fromSet(unhandled); |
4414 | - } |
4415 | - |
4416 | - QVector<Metadata> get_backup_choices() const |
4417 | - { |
4418 | - if (cached_backup_choices_.isEmpty()) |
4419 | - cached_backup_choices_ = backup_choices_->get_backups(); |
4420 | - |
4421 | - return cached_backup_choices_; |
4422 | - } |
4423 | - |
4424 | - QVector<Metadata> get_restore_choices() const |
4425 | - { |
4426 | - if (cached_restore_choices_.isEmpty()) |
4427 | - cached_restore_choices_ = restore_choices_->get_backups(); |
4428 | - |
4429 | - return cached_restore_choices_; |
4430 | - } |
4431 | - |
4432 | - QVariantDictMap get_state() const |
4433 | + } |
4434 | + |
4435 | + keeper::Items get_backup_choices_var_dict_map(QDBusConnection bus, |
4436 | + QDBusMessage const & msg) |
4437 | + { |
4438 | + connections_.connect_oneshot( |
4439 | + this, |
4440 | + &KeeperPrivate::backup_choices_ready, |
4441 | + std::function<void(keeper::Error)>{[this, msg, bus](keeper::Error error){ |
4442 | + qDebug() << "Backup choices are ready"; |
4443 | + if (error == keeper::Error::OK) |
4444 | + { |
4445 | + // reply now to the dbus call |
4446 | + auto reply = msg.createReply(); |
4447 | + reply << QVariant::fromValue(choices_to_variant_dict_map(cached_backup_choices_)); |
4448 | + bus.send(reply); |
4449 | + } |
4450 | + else |
4451 | + { |
4452 | + auto message = QStringLiteral("Error obtaining backup choices, keeper returned error: %1").arg(static_cast<int>(error)); |
4453 | + qWarning() << message; |
4454 | + auto reply = msg.createErrorReply(QDBusError::Failed, message); |
4455 | + reply << QVariant::fromValue(error); |
4456 | + bus.send(reply); |
4457 | + } |
4458 | + }} |
4459 | + ); |
4460 | + get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES); |
4461 | + msg.setDelayedReply(true); |
4462 | + return keeper::Items(); |
4463 | + } |
4464 | + |
4465 | + keeper::Items get_restore_choices_var_dict_map(QString const & storage, |
4466 | + QDBusConnection bus, |
4467 | + QDBusMessage const & msg) |
4468 | + { |
4469 | + qDebug() << "Getting restores for storage " << storage << " --------------------------------"; |
4470 | + cached_restore_choices_.clear(); |
4471 | + connections_.connect_oneshot( |
4472 | + this, |
4473 | + &KeeperPrivate::restore_choices_ready, |
4474 | + std::function<void(keeper::Error)>{[this, msg, bus](keeper::Error error){ |
4475 | + qDebug() << "Restore choices are ready"; |
4476 | + if (error == keeper::Error::OK) |
4477 | + { |
4478 | + // reply now to the dbus call |
4479 | + auto reply = msg.createReply(); |
4480 | + reply << QVariant::fromValue(choices_to_variant_dict_map(cached_restore_choices_)); |
4481 | + bus.send(reply); |
4482 | + } |
4483 | + else |
4484 | + { |
4485 | + auto message = QStringLiteral("Error obtaining restore choices, keeper returned error: %1").arg(static_cast<int>(error)); |
4486 | + qWarning() << message; |
4487 | + auto reply = msg.createErrorReply(QDBusError::Failed, message); |
4488 | + reply << QVariant::fromValue(error); |
4489 | + bus.send(reply); |
4490 | + } |
4491 | + }} |
4492 | + ); |
4493 | + get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES, storage); |
4494 | + msg.setDelayedReply(true); |
4495 | + return keeper::Items(); |
4496 | + } |
4497 | + |
4498 | + keeper::Items get_state() const |
4499 | { |
4500 | return task_manager_.get_state(); |
4501 | } |
4502 | @@ -127,7 +281,18 @@ |
4503 | } |
4504 | ); |
4505 | |
4506 | - qDebug() << "Asking for an storage framework socket to the task manager"; |
4507 | + connections_.connect_oneshot( |
4508 | + &task_manager_, |
4509 | + &TaskManager::socket_error, |
4510 | + std::function<void(keeper::Error)>{ |
4511 | + [bus,msg](keeper::Error error){ |
4512 | + qDebug("BackupManager returned socket error: %d", static_cast<int>(error)); |
4513 | + bus.send(msg.createErrorReply(QDBusError::InvalidArgs, "Error obtaining remote backup socket")); |
4514 | + } |
4515 | + } |
4516 | + ); |
4517 | + |
4518 | + qDebug() << "Asking for a storage framework socket from the task manager"; |
4519 | task_manager_.ask_for_uploader(n_bytes); |
4520 | |
4521 | // tell the caller that we'll be responding async |
4522 | @@ -135,7 +300,102 @@ |
4523 | return QDBusUnixFileDescriptor(0); |
4524 | } |
4525 | |
4526 | + |
4527 | + QDBusUnixFileDescriptor start_restore(QDBusConnection bus, |
4528 | + QDBusMessage const & msg) |
4529 | + { |
4530 | + qDebug() << "Keeper::StartRestore()"; |
4531 | + |
4532 | + connections_.connect_oneshot( |
4533 | + &task_manager_, |
4534 | + &TaskManager::socket_ready, |
4535 | + std::function<void(int)>{ |
4536 | + [bus,msg](int fd){ |
4537 | + qDebug("RestoreManager returned socket %d", fd); |
4538 | + auto reply = msg.createReply(); |
4539 | + reply << QVariant::fromValue(QDBusUnixFileDescriptor(fd)); |
4540 | + close(fd); |
4541 | + bus.send(reply); |
4542 | + } |
4543 | + } |
4544 | + ); |
4545 | + |
4546 | + connections_.connect_oneshot( |
4547 | + &task_manager_, |
4548 | + &TaskManager::socket_error, |
4549 | + std::function<void(keeper::Error)>{ |
4550 | + [bus,msg](keeper::Error error){ |
4551 | + qDebug("RestoreManager returned socket error: %d", static_cast<int>(error)); |
4552 | + bus.send(msg.createErrorReply(QDBusError::InvalidArgs, "Error obtaining remote restore socket")); |
4553 | + } |
4554 | + } |
4555 | + ); |
4556 | + |
4557 | + qDebug() << "Asking for a storage framework socket from the task manager"; |
4558 | + task_manager_.ask_for_downloader(); |
4559 | + |
4560 | + // tell the caller that we'll be responding async |
4561 | + msg.setDelayedReply(true); |
4562 | + return QDBusUnixFileDescriptor(0); |
4563 | + } |
4564 | + |
4565 | + void cancel() |
4566 | + { |
4567 | + task_manager_.cancel(); |
4568 | + } |
4569 | + |
4570 | + void invalidate_choices_cache() |
4571 | + { |
4572 | + cached_backup_choices_.clear(); |
4573 | + } |
4574 | + |
4575 | + QStringList get_storage_accounts(QDBusConnection bus, |
4576 | + QDBusMessage const & msg) |
4577 | + { |
4578 | + connections_.connect_future( |
4579 | + storage_->get_accounts(), |
4580 | + std::function<void(QStringList const &)>{ |
4581 | + [this, msg, bus](QStringList const& accounts){ |
4582 | + qDebug() << "get_storage_accounts() finished"; |
4583 | + // reply now to the dbus call |
4584 | + auto reply = msg.createReply(); |
4585 | + reply << QVariant::fromValue(accounts); |
4586 | + bus.send(reply); |
4587 | + } |
4588 | + } |
4589 | + ); |
4590 | + msg.setDelayedReply(true); |
4591 | + return QStringList(); |
4592 | + } |
4593 | + |
4594 | +Q_SIGNALS: |
4595 | + void backup_choices_ready(keeper::Error error); |
4596 | + void restore_choices_ready(keeper::Error error); |
4597 | + |
4598 | private: |
4599 | + void on_task_manager_finished() |
4600 | + { |
4601 | + // force a backup choices regeneration to avoid repeating uuids |
4602 | + // between backups |
4603 | + invalidate_choices_cache(); |
4604 | + } |
4605 | + |
4606 | + void check_for_unhandled_tasks_and_reply(QSet<QString> const & unhandled, |
4607 | + QDBusConnection bus, |
4608 | + QDBusMessage const & msg ) |
4609 | + { |
4610 | + if (!unhandled.empty()) |
4611 | + { |
4612 | + qWarning() << "skipped tasks" << unhandled; |
4613 | + QString text = QStringLiteral("unhandled uuids:"); |
4614 | + for (auto const& uuid : unhandled) |
4615 | + text += ' ' + uuid; |
4616 | + bus.send(msg.createErrorReply(QDBusError::InvalidArgs, text)); |
4617 | + } |
4618 | + |
4619 | + auto reply = msg.createReply(); |
4620 | + bus.send(reply); |
4621 | + } |
4622 | |
4623 | Keeper * const q_ptr; |
4624 | QSharedPointer<StorageFrameworkClient> storage_; |
4625 | @@ -160,12 +420,15 @@ |
4626 | |
4627 | Keeper::~Keeper() = default; |
4628 | |
4629 | -QStringList |
4630 | -Keeper::start_tasks(QStringList const & uuids) |
4631 | +void |
4632 | +Keeper::start_tasks(QStringList const & uuids, |
4633 | + QString const & storage, |
4634 | + QDBusConnection bus, |
4635 | + QDBusMessage const & msg) |
4636 | { |
4637 | Q_D(Keeper); |
4638 | |
4639 | - return d->start_tasks(uuids); |
4640 | + d->start_tasks(uuids, storage, bus, msg); |
4641 | } |
4642 | |
4643 | QDBusUnixFileDescriptor |
4644 | @@ -178,26 +441,66 @@ |
4645 | return d->start_backup(bus, msg, n_bytes); |
4646 | } |
4647 | |
4648 | -QVector<Metadata> |
4649 | -Keeper::get_backup_choices() |
4650 | -{ |
4651 | - Q_D(Keeper); |
4652 | - |
4653 | - return d->get_backup_choices(); |
4654 | -} |
4655 | - |
4656 | -QVector<Metadata> |
4657 | -Keeper::get_restore_choices() |
4658 | -{ |
4659 | - Q_D(Keeper); |
4660 | - |
4661 | - return d->get_restore_choices(); |
4662 | -} |
4663 | - |
4664 | -QVariantDictMap |
4665 | +QDBusUnixFileDescriptor |
4666 | +Keeper::StartRestore(QDBusConnection bus, |
4667 | + QDBusMessage const & msg) |
4668 | +{ |
4669 | + Q_D(Keeper); |
4670 | + |
4671 | + return d->start_restore(bus, msg); |
4672 | +} |
4673 | + |
4674 | +keeper::Items |
4675 | +Keeper::get_backup_choices_var_dict_map(QDBusConnection bus, |
4676 | + QDBusMessage const & msg) |
4677 | +{ |
4678 | + Q_D(Keeper); |
4679 | + |
4680 | + return d->get_backup_choices_var_dict_map(bus, msg); |
4681 | +} |
4682 | + |
4683 | +keeper::Items |
4684 | +Keeper::get_restore_choices(QString const & storage, |
4685 | + QDBusConnection bus, |
4686 | + QDBusMessage const & msg) |
4687 | +{ |
4688 | + Q_D(Keeper); |
4689 | + |
4690 | + return d->get_restore_choices_var_dict_map(storage, bus, msg); |
4691 | +} |
4692 | + |
4693 | +keeper::Items |
4694 | Keeper::get_state() const |
4695 | { |
4696 | Q_D(const Keeper); |
4697 | |
4698 | return d->get_state(); |
4699 | } |
4700 | + |
4701 | +void |
4702 | +Keeper::cancel() |
4703 | +{ |
4704 | + Q_D(Keeper); |
4705 | + |
4706 | + return d->cancel(); |
4707 | +} |
4708 | + |
4709 | +void |
4710 | +Keeper::invalidate_choices_cache() |
4711 | +{ |
4712 | + Q_D(Keeper); |
4713 | + |
4714 | + d->invalidate_choices_cache(); |
4715 | +} |
4716 | + |
4717 | +QStringList |
4718 | +Keeper::get_storage_accounts(QDBusConnection bus, |
4719 | + QDBusMessage const & message) |
4720 | +{ |
4721 | + Q_D(Keeper); |
4722 | + |
4723 | + return d->get_storage_accounts(bus,message); |
4724 | +} |
4725 | + |
4726 | + |
4727 | +#include "keeper.moc" |
4728 | |
4729 | === modified file 'src/service/keeper.h' |
4730 | --- src/service/keeper.h 2016-09-07 16:47:55 +0000 |
4731 | +++ src/service/keeper.h 2017-02-27 19:05:17 +0000 |
4732 | @@ -52,16 +52,30 @@ |
4733 | |
4734 | virtual ~Keeper(); |
4735 | |
4736 | - QVector<Metadata> get_backup_choices(); |
4737 | - QVector<Metadata> get_restore_choices(); |
4738 | + keeper::Items get_backup_choices_var_dict_map(QDBusConnection bus, QDBusMessage const & msg); |
4739 | + keeper::Items get_restore_choices(QString const & storage, QDBusConnection bus, QDBusMessage const & msg); |
4740 | |
4741 | QDBusUnixFileDescriptor StartBackup(QDBusConnection, |
4742 | QDBusMessage const & message, |
4743 | quint64 nbytes); |
4744 | |
4745 | - QStringList start_tasks(QStringList const & uuids); |
4746 | - |
4747 | - QVariantDictMap get_state() const; |
4748 | + |
4749 | + QDBusUnixFileDescriptor StartRestore(QDBusConnection, |
4750 | + QDBusMessage const & message); |
4751 | + |
4752 | + void start_tasks(QStringList const & uuids, |
4753 | + QString const & storage, |
4754 | + QDBusConnection bus, |
4755 | + QDBusMessage const & msg); |
4756 | + |
4757 | + keeper::Items get_state() const; |
4758 | + |
4759 | + void cancel(); |
4760 | + |
4761 | + void invalidate_choices_cache(); |
4762 | + |
4763 | + QStringList get_storage_accounts(QDBusConnection, |
4764 | + QDBusMessage const & message); |
4765 | |
4766 | private: |
4767 | QScopedPointer<KeeperPrivate> const d_ptr; |
4768 | |
4769 | === modified file 'src/service/main.cpp' |
4770 | --- src/service/main.cpp 2016-08-10 05:41:26 +0000 |
4771 | +++ src/service/main.cpp 2017-02-27 19:05:17 +0000 |
4772 | @@ -20,6 +20,7 @@ |
4773 | |
4774 | #include "dbus-types.h" |
4775 | #include "helper/data-dir-registry.h" |
4776 | +#include "helper/helper.h" |
4777 | #include "service/backup-choices.h" |
4778 | #include "service/restore-choices.h" |
4779 | #include "service/keeper.h" |
4780 | @@ -45,7 +46,7 @@ |
4781 | |
4782 | QCoreApplication app(argc, argv); |
4783 | DBusTypes::registerMetaTypes(); |
4784 | -// Variant::registerMetaTypes(); |
4785 | + Helper::registerMetaTypes(); |
4786 | std::srand(unsigned(std::time(nullptr))); |
4787 | |
4788 | util::UnixSignalHandler handler([]{ |
4789 | |
4790 | === added file 'src/service/manifest.cpp' |
4791 | --- src/service/manifest.cpp 1970-01-01 00:00:00 +0000 |
4792 | +++ src/service/manifest.cpp 2017-02-27 19:05:17 +0000 |
4793 | @@ -0,0 +1,248 @@ |
4794 | +/* |
4795 | + * Copyright (C) 2016 Canonical, Ltd. |
4796 | + * |
4797 | + * This program is free software: you can redistribute it and/or modify it |
4798 | + * under the terms of the GNU General Public License version 3, as published |
4799 | + * by the Free Software Foundation. |
4800 | + * |
4801 | + * This program is distributed in the hope that it will be useful, but |
4802 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
4803 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
4804 | + * PURPOSE. See the GNU General Public License for more details. |
4805 | + * |
4806 | + * You should have received a copy of the GNU General Public License along |
4807 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
4808 | + * |
4809 | + * Authors: |
4810 | + * Xavi Garcia Mena <xavi.garcia.mena@canonical.com> |
4811 | + */ |
4812 | + |
4813 | +#include "manifest.h" |
4814 | + |
4815 | +#include "storage-framework/storage_framework_client.h" |
4816 | +#include "util/connection-helper.h" |
4817 | + |
4818 | +#include <QJsonArray> |
4819 | +#include <QJsonDocument> |
4820 | +#include <QJsonObject> |
4821 | +#include <QSharedPointer> |
4822 | +#include <QVector> |
4823 | + |
4824 | +#include <fcntl.h> |
4825 | +#include <sys/types.h> |
4826 | +#include <sys/socket.h> |
4827 | + |
4828 | +namespace sf = unity::storage::qt::client; |
4829 | + |
4830 | +// JSON Keys |
4831 | +namespace |
4832 | +{ |
4833 | + constexpr const char ENTRIES_KEY[] = "entries"; |
4834 | + constexpr const char MANIFEST_FILE_NAME[] = "manifest.json"; |
4835 | +} |
4836 | + |
4837 | +/*** |
4838 | +**** |
4839 | +***/ |
4840 | + |
4841 | +class ManifestPrivate |
4842 | +{ |
4843 | +public: |
4844 | + ManifestPrivate(QSharedPointer<StorageFrameworkClient> const & storage, QString const & dir, Manifest * manifest) |
4845 | + : q_ptr{manifest} |
4846 | + , storage_{storage} |
4847 | + , dir_{dir} |
4848 | + { |
4849 | + } |
4850 | + |
4851 | + ~ManifestPrivate() = default; |
4852 | + |
4853 | + Q_DISABLE_COPY(ManifestPrivate) |
4854 | + |
4855 | + void add_entry(Metadata const & entry) |
4856 | + { |
4857 | + entries_.push_back(entry); |
4858 | + } |
4859 | + |
4860 | + void store() |
4861 | + { |
4862 | + qDebug() << "Metadata asking storage framework for a socket"; |
4863 | + auto json_data = to_json(); |
4864 | + auto n_bytes = json_data.size(); |
4865 | + |
4866 | + connections_.connect_future( |
4867 | + storage_->get_new_uploader(n_bytes, dir_, MANIFEST_FILE_NAME), |
4868 | + std::function<void(std::shared_ptr<Uploader> const&)>{ |
4869 | + [this, json_data](std::shared_ptr<Uploader> const& uploader){ |
4870 | + qDebug() << "Manifest uploader is" << static_cast<void*>(uploader.get()); |
4871 | + if (uploader) |
4872 | + { |
4873 | + auto socket = uploader->socket(); |
4874 | + socket->write(json_data); |
4875 | + connections_.connect_oneshot( |
4876 | + uploader.get(), |
4877 | + &Uploader::commit_finished, |
4878 | + std::function<void(bool)>{[this, uploader](bool success){ |
4879 | + qDebug() << "Metadata commit finished"; |
4880 | + if (!success) |
4881 | + { |
4882 | + finish_with_error(QStringLiteral("Error committing manifest file to storage-framework")); |
4883 | + } |
4884 | + else |
4885 | + { |
4886 | + uploader_committed_file_name_ = uploader->file_name(); |
4887 | + finish(); |
4888 | + } |
4889 | + }} |
4890 | + ); |
4891 | + uploader->commit(); |
4892 | + } |
4893 | + else |
4894 | + { |
4895 | + finish_with_error(QStringLiteral("Error retrieving uploader for manifest file from storage-framework")); |
4896 | + } |
4897 | + } |
4898 | + } |
4899 | + ); |
4900 | + } |
4901 | + |
4902 | + void read() |
4903 | + { |
4904 | + connections_.connect_future( |
4905 | + storage_->get_new_downloader(dir_, MANIFEST_FILE_NAME), |
4906 | + std::function<void(std::shared_ptr<Downloader> const&)>{ |
4907 | + [this](std::shared_ptr<Downloader> const& downloader){ |
4908 | + if (downloader) |
4909 | + { |
4910 | + auto socket = downloader->socket(); |
4911 | + if (socket->atEnd()) |
4912 | + { |
4913 | + if (!socket->waitForReadyRead(5000)) |
4914 | + { |
4915 | + qWarning() << "Manifest socket was not ready to read after timeout"; |
4916 | + } |
4917 | + } |
4918 | + auto json_content = socket->readAll(); |
4919 | + from_json(json_content); |
4920 | + downloader->finish(); |
4921 | + finish(); |
4922 | + } |
4923 | + else |
4924 | + { |
4925 | + finish_with_error(QStringLiteral("Error retrieving downloader for manifest file from storage-framework")); |
4926 | + } |
4927 | + } |
4928 | + } |
4929 | + ); |
4930 | + } |
4931 | + |
4932 | + QVector<Metadata> get_entries() |
4933 | + { |
4934 | + return entries_; |
4935 | + } |
4936 | + |
4937 | + QString error() const |
4938 | + { |
4939 | + return error_string_; |
4940 | + } |
4941 | + |
4942 | + QByteArray to_json() const |
4943 | + { |
4944 | + QJsonArray json_array; |
4945 | + for (auto metadata : entries_) |
4946 | + { |
4947 | + json_array.append(metadata.json()); |
4948 | + } |
4949 | + QJsonObject json_root; |
4950 | + json_root[ENTRIES_KEY] = json_array; |
4951 | + QJsonDocument doc(json_root); |
4952 | + |
4953 | + return doc.toJson(QJsonDocument::Compact); |
4954 | + } |
4955 | + |
4956 | + void from_json(QByteArray const & json) |
4957 | + { |
4958 | + auto doc_read = QJsonDocument::fromJson(json); |
4959 | + |
4960 | + auto json_read_root = doc_read.object(); |
4961 | + auto items = json_read_root[ENTRIES_KEY].toArray(); |
4962 | + |
4963 | + QVector<Metadata> read_metadata; |
4964 | + for( auto iter = items.begin(); iter != items.end(); ++iter) |
4965 | + { |
4966 | + entries_.push_back(Metadata((*iter).toObject())); |
4967 | + } |
4968 | + } |
4969 | + |
4970 | +private: |
4971 | + |
4972 | + void finish_with_error(QString const & message) |
4973 | + { |
4974 | + error_string_ = message; |
4975 | + Q_EMIT(q_ptr->finished(false)); |
4976 | + } |
4977 | + |
4978 | + void finish() |
4979 | + { |
4980 | + error_string_ = ""; |
4981 | + Q_EMIT(q_ptr->finished(true)); |
4982 | + } |
4983 | + |
4984 | + Manifest * const q_ptr; |
4985 | + QSharedPointer<StorageFrameworkClient> storage_; |
4986 | + QString dir_; |
4987 | + |
4988 | + QVector<Metadata> entries_; |
4989 | + QString error_string_; |
4990 | + QString uploader_committed_file_name_; |
4991 | + |
4992 | + ConnectionHelper connections_; |
4993 | +}; |
4994 | + |
4995 | +/*** |
4996 | +**** |
4997 | +***/ |
4998 | + |
4999 | +Manifest::Manifest(QSharedPointer<StorageFrameworkClient> const & storage, QString const & dir, QObject * parent) |
5000 | + : QObject (parent) |
The diff has been truncated for viewing.