Merge lp:~charlesk/keeper/make-com.canonical.keeper.User.State-great-again into lp:keeper
- make-com.canonical.keeper.User.State-great-again
- Merge into trunk
Proposed by
Charles Kerr
Status: | Merged |
---|---|
Merge reported by: | Xavi Garcia |
Merged at revision: | not available |
Proposed branch: | lp:~charlesk/keeper/make-com.canonical.keeper.User.State-great-again |
Merge into: | lp:keeper |
Diff against target: |
449 lines (+271/-76) 3 files modified
src/service/keeper-user.cpp (+1/-6) src/service/keeper.cpp (+267/-70) src/service/keeper.h (+3/-0) |
To merge this branch: | bzr merge lp:~charlesk/keeper/make-com.canonical.keeper.User.State-great-again |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Xavi Garcia (community) | Approve | ||
Review via email: mp+302603@code.launchpad.net |
Commit message
First draft of returning meaningful values when com.canonical.
Description of the change
First draft of returning meaningful values when com.canonical.
To post a comment you must log in.
- 77. By Charles Kerr
-
in service/keeper.cpp, only rebuild the parts of state_ that change
- 78. By Charles Kerr
-
improve state notification
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/service/keeper-user.cpp' |
2 | --- src/service/keeper-user.cpp 2016-08-08 06:06:49 +0000 |
3 | +++ src/service/keeper-user.cpp 2016-08-11 00:30:32 +0000 |
4 | @@ -96,10 +96,5 @@ |
5 | QVariantDictMap |
6 | KeeperUser::get_state() const |
7 | { |
8 | - // FIXME: writeme (the code below is junk 'hello world' data for testing in d-feet) |
9 | - |
10 | - QVariantDictMap ret; |
11 | - for (const auto& item : keeper_.get_backup_choices()) |
12 | - ret[item.uuid()]; |
13 | - return ret; |
14 | + return keeper_.get_state(); |
15 | } |
16 | |
17 | === modified file 'src/service/keeper.cpp' |
18 | --- src/service/keeper.cpp 2016-08-10 07:34:02 +0000 |
19 | +++ src/service/keeper.cpp 2016-08-11 00:30:32 +0000 |
20 | @@ -24,6 +24,7 @@ |
21 | #include "service/metadata-provider.h" |
22 | #include "service/keeper.h" |
23 | #include "storage-framework/storage_framework_client.h" |
24 | +#include "util/dbus-utils.h" |
25 | |
26 | #include <QDebug> |
27 | #include <QDBusMessage> |
28 | @@ -38,31 +39,32 @@ |
29 | |
30 | class KeeperPrivate |
31 | { |
32 | + enum class TaskType { BACKUP, RESTORE }; |
33 | + |
34 | + struct TaskData |
35 | + { |
36 | + QString action; |
37 | + QString error; |
38 | + TaskType type; |
39 | + Metadata metadata; |
40 | + float percent_done; |
41 | + }; |
42 | + |
43 | public: |
44 | |
45 | - Keeper * const q_ptr; |
46 | - QSharedPointer<HelperRegistry> helper_registry_; |
47 | - QSharedPointer<MetadataProvider> backup_choices_; |
48 | - QSharedPointer<MetadataProvider> restore_choices_; |
49 | QScopedPointer<BackupHelper> backup_helper_; |
50 | QScopedPointer<StorageFrameworkClient> storage_; |
51 | - QVector<Metadata> cached_backup_choices_; |
52 | - QVector<Metadata> cached_restore_choices_; |
53 | - QStringList remaining_tasks_; |
54 | |
55 | KeeperPrivate(Keeper* keeper, |
56 | const QSharedPointer<HelperRegistry>& helper_registry, |
57 | const QSharedPointer<MetadataProvider>& backup_choices, |
58 | const QSharedPointer<MetadataProvider>& restore_choices) |
59 | - : q_ptr(keeper) |
60 | + : backup_helper_(new BackupHelper(DEKKO_APP_ID)) |
61 | + , storage_(new StorageFrameworkClient()) |
62 | + , q_ptr(keeper) |
63 | , helper_registry_(helper_registry) |
64 | , backup_choices_(backup_choices) |
65 | , restore_choices_(restore_choices) |
66 | - , backup_helper_(new BackupHelper(DEKKO_APP_ID)) |
67 | - , storage_(new StorageFrameworkClient()) |
68 | - , cached_backup_choices_() |
69 | - , cached_restore_choices_() |
70 | - , remaining_tasks_() |
71 | { |
72 | // listen for backup helper state changes |
73 | QObject::connect(backup_helper_.data(), &Helper::state_changed, |
74 | @@ -79,44 +81,62 @@ |
75 | |
76 | Q_DISABLE_COPY(KeeperPrivate) |
77 | |
78 | - void start_task(QString const &uuid) |
79 | + void start_tasks(QStringList const& uuids) |
80 | { |
81 | - qDebug() << "Starting task: " << uuid; |
82 | - auto metadata = get_uuid_metadata(cached_backup_choices_, uuid); |
83 | - if (metadata.uuid() == uuid) |
84 | - { |
85 | - qDebug() << "Task is a backup task"; |
86 | - |
87 | - const auto urls = helper_registry_->get_backup_helper_urls(metadata); |
88 | - if (urls.isEmpty()) |
89 | + if (!remaining_tasks_.isEmpty()) |
90 | + { |
91 | + // FIXME: return a dbus error here |
92 | + qWarning() << "keeper is already active"; |
93 | + return; |
94 | + } |
95 | + |
96 | + all_tasks_.clear(); |
97 | + task_data_.clear(); |
98 | + state_.clear(); |
99 | + |
100 | + for(auto const& uuid : uuids) |
101 | + { |
102 | + Metadata m; |
103 | + TaskType type; |
104 | + if (!find_task_metadata(uuid, m, type)) |
105 | { |
106 | - // TODO Report error to user |
107 | - qWarning() << "ERROR: uuid: " << uuid << " has no url"; |
108 | - return; |
109 | + qCritical() << "uuid" << uuid << "not found; skipping"; |
110 | + continue; |
111 | } |
112 | |
113 | - backup_helper_->start(urls); |
114 | - } |
115 | - } |
116 | - |
117 | - void start_tasks(QStringList const& tasks) |
118 | - { |
119 | - remaining_tasks_ = tasks; |
120 | - start_remaining_tasks(); |
121 | - } |
122 | - |
123 | - void start_remaining_tasks() |
124 | - { |
125 | - if (remaining_tasks_.size()) |
126 | - { |
127 | - auto task = remaining_tasks_.takeFirst(); |
128 | - start_task(task); |
129 | - } |
130 | - } |
131 | - |
132 | - void clear_remaining_taks() |
133 | - { |
134 | - remaining_tasks_.clear(); |
135 | + all_tasks_ << uuid; |
136 | + remaining_tasks_ << uuid; |
137 | + |
138 | + auto& td = task_data_[uuid]; |
139 | + td.metadata = m; |
140 | + td.type = type; |
141 | + td.action = QStringLiteral("queued"); |
142 | + |
143 | + update_task_state(td); |
144 | + } |
145 | + |
146 | + start_next_task(); |
147 | + } |
148 | + |
149 | + QVector<Metadata> get_backup_choices() const |
150 | + { |
151 | + if (cached_backup_choices_.isEmpty()) |
152 | + cached_backup_choices_ = backup_choices_->get_backups(); |
153 | + |
154 | + return cached_backup_choices_; |
155 | + } |
156 | + |
157 | + QVector<Metadata> get_restore_choices() const |
158 | + { |
159 | + if (cached_restore_choices_.isEmpty()) |
160 | + cached_restore_choices_ = restore_choices_->get_backups(); |
161 | + |
162 | + return cached_restore_choices_; |
163 | + } |
164 | + |
165 | + QVariantDictMap get_state() const |
166 | + { |
167 | + return state_; |
168 | } |
169 | |
170 | private: |
171 | @@ -133,14 +153,20 @@ |
172 | break; |
173 | |
174 | case Helper::State::CANCELLED: |
175 | + set_current_task_action(QStringLiteral("cancelled")); |
176 | qDebug() << "Backup helper cancelled... closing the socket."; |
177 | storage_->finish(false); |
178 | break; |
179 | + |
180 | case Helper::State::FAILED: |
181 | + set_current_task_action(QStringLiteral("failed")); |
182 | qDebug() << "Backup helper failed... closing the socket."; |
183 | storage_->finish(false); |
184 | break; |
185 | + |
186 | case Helper::State::COMPLETE: |
187 | + task_data_[current_task_].percent_done = 1; |
188 | + set_current_task_action(QStringLiteral("complete")); |
189 | qDebug() << "Backup helper finished... closing the socket."; |
190 | storage_->finish(true); |
191 | break; |
192 | @@ -150,20 +176,191 @@ |
193 | void on_storage_framework_finished() |
194 | { |
195 | qDebug() << "storage framework has finished for the current task"; |
196 | - start_remaining_tasks(); |
197 | - } |
198 | - |
199 | - Metadata get_uuid_metadata(QVector<Metadata> const &metadata, QString const & uuid) |
200 | - { |
201 | - for (auto item : metadata) |
202 | - { |
203 | - if (item.uuid() == uuid) |
204 | + start_next_task(); |
205 | + } |
206 | + |
207 | + /*** |
208 | + **** Task Queueing |
209 | + ***/ |
210 | + |
211 | + void start_next_task() |
212 | + { |
213 | + current_task_.clear(); |
214 | + |
215 | + while (!remaining_tasks_.isEmpty()) |
216 | + { |
217 | + auto uuid = remaining_tasks_.takeFirst(); |
218 | + |
219 | + if (start_task(uuid)) |
220 | + break; |
221 | + } |
222 | + } |
223 | + |
224 | + bool start_task(QString const& uuid) |
225 | + { |
226 | + if (!task_data_.contains(uuid)) |
227 | + { |
228 | + qCritical() << "no task data found for" << uuid; |
229 | + return false; |
230 | + } |
231 | + |
232 | + auto& td = task_data_[uuid]; |
233 | + if (td.type == TaskType::BACKUP) |
234 | + { |
235 | + qDebug() << "Task is a backup task"; |
236 | + |
237 | + const auto urls = helper_registry_->get_backup_helper_urls(td.metadata); |
238 | + if (urls.isEmpty()) |
239 | { |
240 | - return item; |
241 | - } |
242 | - } |
243 | - return Metadata(); |
244 | - } |
245 | + td.action = "failed"; |
246 | + td.error = "no helper information in registry"; |
247 | + qWarning() << "ERROR: uuid: " << uuid << " has no url"; |
248 | + return false; |
249 | + } |
250 | + |
251 | + current_task_ = uuid; |
252 | + set_current_task_action(QStringLiteral("saving")); |
253 | + backup_helper_->start(urls); |
254 | + return true; |
255 | + } |
256 | + else // RESTORE |
257 | + { |
258 | + current_task_ = uuid; |
259 | + set_current_task_action(QStringLiteral("restoring")); |
260 | + qWarning() << "restore not implemented yet"; |
261 | + return false; |
262 | + } |
263 | + } |
264 | + |
265 | + /*** |
266 | + **** State |
267 | + ***/ |
268 | + |
269 | + void update_task_state(QString const& uuid) |
270 | + { |
271 | + auto it = task_data_.find(uuid); |
272 | + if (it == task_data_.end()) |
273 | + { |
274 | + qCritical() << "no task data for" << uuid; |
275 | + return; |
276 | + } |
277 | + |
278 | + update_task_state(it.value()); |
279 | + } |
280 | + |
281 | + void update_task_state(TaskData& td) |
282 | + { |
283 | + state_[td.metadata.uuid()] = calculate_task_state(td); |
284 | + |
285 | +#if 0 |
286 | + // FIXME: we don't need this to work correctly for the sprint because Marcus is polling in a loop |
287 | + // but we will need this in order for him to stop doing that |
288 | + |
289 | + // TODO: compare old and new and decide if it's worth emitting a PropertyChanged signal; |
290 | + // eg don't contribute to dbus noise for minor speed fluctuations |
291 | + |
292 | + // TODO: this function is called inside a loop when initializing the state |
293 | + // after start_tasks(), so also ensure we don't have a notify flood here |
294 | + |
295 | + DBusUtils::notifyPropertyChanged( |
296 | + QDBusConnection::sessionBus(), |
297 | + *q_ptr, |
298 | + DBusTypes::KEEPER_USER_PATH, |
299 | + DBusTypes::KEEPER_USER_INTERFACE, |
300 | + QStringList(QStringLiteral("State")) |
301 | + ); |
302 | +#endif |
303 | + } |
304 | + |
305 | + QVariantMap calculate_task_state(TaskData& td) const |
306 | + { |
307 | + QVariantMap ret; |
308 | + |
309 | + auto const uuid = td.metadata.uuid(); |
310 | + bool const current = uuid == current_task_; |
311 | + |
312 | + ret.insert(QStringLiteral("action"), td.action); |
313 | + |
314 | + ret.insert(QStringLiteral("display-name"), td.metadata.display_name()); |
315 | + |
316 | + // FIXME: assuming backup_helper_ for now... |
317 | + int32_t speed {}; |
318 | + if (current) |
319 | + speed = backup_helper_->speed(); |
320 | + ret.insert(QStringLiteral("speed"), speed); |
321 | + |
322 | + if (current) |
323 | + td.percent_done = backup_helper_->percent_done(); |
324 | + ret.insert(QStringLiteral("percent-done"), td.percent_done); |
325 | + |
326 | + if (td.action == "failed") |
327 | + ret.insert(QStringLiteral("error"), td.error); |
328 | + |
329 | + ret.insert(QStringLiteral("uuid"), uuid); |
330 | + |
331 | + return ret; |
332 | + } |
333 | + |
334 | + |
335 | + void set_current_task(QString const& uuid) |
336 | + { |
337 | + auto const prev = current_task_; |
338 | + |
339 | + current_task_ = uuid; |
340 | + |
341 | + if (!prev.isEmpty()) |
342 | + update_task_state(prev); |
343 | + |
344 | + if (!uuid.isEmpty()) |
345 | + update_task_state(uuid); |
346 | + } |
347 | + |
348 | + void set_current_task_action(QString const& action) |
349 | + { |
350 | + auto& td = task_data_[current_task_]; |
351 | + td.action = action; |
352 | + update_task_state(td); |
353 | + } |
354 | + |
355 | + /*** |
356 | + **** Misc |
357 | + ***/ |
358 | + |
359 | + bool find_task_metadata(QString const& uuid, Metadata& setme_task, TaskType& setme_type) const |
360 | + { |
361 | + for (const auto& c : get_backup_choices()) { |
362 | + if (c.uuid() == uuid) { |
363 | + setme_task = c; |
364 | + setme_type = TaskType::BACKUP; |
365 | + return true; |
366 | + } |
367 | + } |
368 | + for (const auto& c : get_restore_choices()) { |
369 | + if (c.uuid() == uuid) { |
370 | + setme_task = c; |
371 | + setme_type = TaskType::RESTORE; |
372 | + return true; |
373 | + } |
374 | + } |
375 | + return false; |
376 | + } |
377 | + |
378 | + /*** |
379 | + **** |
380 | + ***/ |
381 | + |
382 | + Keeper * const q_ptr; |
383 | + QSharedPointer<HelperRegistry> helper_registry_; |
384 | + QSharedPointer<MetadataProvider> backup_choices_; |
385 | + QSharedPointer<MetadataProvider> restore_choices_; |
386 | + mutable QVector<Metadata> cached_backup_choices_; |
387 | + mutable QVector<Metadata> cached_restore_choices_; |
388 | + QStringList all_tasks_; |
389 | + QStringList remaining_tasks_; |
390 | + QString current_task_; |
391 | + QVariantDictMap state_; |
392 | + |
393 | + mutable QMap<QString,TaskData> task_data_; |
394 | }; |
395 | |
396 | |
397 | @@ -222,11 +419,7 @@ |
398 | { |
399 | Q_D(Keeper); |
400 | |
401 | - if (!d->cached_backup_choices_.size()) |
402 | - { |
403 | - d->cached_backup_choices_ = d->backup_choices_->get_backups(); |
404 | - } |
405 | - return d->cached_backup_choices_; |
406 | + return d->get_backup_choices(); |
407 | } |
408 | |
409 | QVector<Metadata> |
410 | @@ -234,9 +427,13 @@ |
411 | { |
412 | Q_D(Keeper); |
413 | |
414 | - if (!d->cached_restore_choices_.size()) |
415 | - { |
416 | - d->cached_restore_choices_ = d->restore_choices_->get_backups(); |
417 | - } |
418 | - return d->cached_restore_choices_; |
419 | + return d->get_restore_choices(); |
420 | +} |
421 | + |
422 | +QVariantDictMap |
423 | +Keeper::get_state() const |
424 | +{ |
425 | + Q_D(const Keeper); |
426 | + |
427 | + return d->get_state(); |
428 | } |
429 | |
430 | === modified file 'src/service/keeper.h' |
431 | --- src/service/keeper.h 2016-08-10 06:44:47 +0000 |
432 | +++ src/service/keeper.h 2016-08-11 00:30:32 +0000 |
433 | @@ -18,6 +18,8 @@ |
434 | |
435 | #pragma once |
436 | |
437 | +#include "qdbus-stubs/dbus-types.h" |
438 | + |
439 | #include <unity/storage/qt/client/client-api.h> |
440 | |
441 | #include <QDBusContext> |
442 | @@ -56,6 +58,7 @@ |
443 | QDBusUnixFileDescriptor StartBackup(QDBusConnection, const QDBusMessage& message, quint64 nbytes); |
444 | |
445 | void start_tasks(QStringList const & keys); |
446 | + QVariantDictMap get_state() const; |
447 | |
448 | private: |
449 | QScopedPointer<KeeperPrivate> const d_ptr; |
Looks good