diff options
Diffstat (limited to 'common/clientapi.cpp')
-rw-r--r-- | common/clientapi.cpp | 141 |
1 files changed, 140 insertions, 1 deletions
diff --git a/common/clientapi.cpp b/common/clientapi.cpp index e7ca99d..824ef19 100644 --- a/common/clientapi.cpp +++ b/common/clientapi.cpp | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <QEventLoop> | 25 | #include <QEventLoop> |
26 | #include <QAbstractItemModel> | 26 | #include <QAbstractItemModel> |
27 | #include <QDir> | 27 | #include <QDir> |
28 | #include <QUuid> | ||
28 | #include <functional> | 29 | #include <functional> |
29 | #include <memory> | 30 | #include <memory> |
30 | 31 | ||
@@ -204,7 +205,7 @@ KAsync::Job<void> Store::synchronize(const Akonadi2::Query &query) | |||
204 | Trace() << "Synchronizing " << resource; | 205 | Trace() << "Synchronizing " << resource; |
205 | auto resourceAccess = QSharedPointer<Akonadi2::ResourceAccess>::create(resource); | 206 | auto resourceAccess = QSharedPointer<Akonadi2::ResourceAccess>::create(resource); |
206 | resourceAccess->open(); | 207 | resourceAccess->open(); |
207 | resourceAccess->synchronizeResource(query.syncOnDemand, query.processAll).then<void>([&future, resourceAccess]() { | 208 | resourceAccess->synchronizeResource(true, false).then<void>([&future, resourceAccess]() { |
208 | future.setFinished(); | 209 | future.setFinished(); |
209 | }).exec(); | 210 | }).exec(); |
210 | }) | 211 | }) |
@@ -212,10 +213,148 @@ KAsync::Job<void> Store::synchronize(const Akonadi2::Query &query) | |||
212 | .template then<void>([](){}); | 213 | .template then<void>([](){}); |
213 | } | 214 | } |
214 | 215 | ||
216 | KAsync::Job<void> Store::flushMessageQueue(const QByteArrayList &resourceIdentifier) | ||
217 | { | ||
218 | Trace() << "flushMessageQueue" << resourceIdentifier; | ||
219 | return KAsync::iterate(resourceIdentifier) | ||
220 | .template each<void, QByteArray>([](const QByteArray &resource, KAsync::Future<void> &future) { | ||
221 | Trace() << "Flushing message queue " << resource; | ||
222 | auto resourceAccess = QSharedPointer<Akonadi2::ResourceAccess>::create(resource); | ||
223 | resourceAccess->open(); | ||
224 | resourceAccess->synchronizeResource(false, true).then<void>([&future, resourceAccess]() { | ||
225 | future.setFinished(); | ||
226 | }).exec(); | ||
227 | }) | ||
228 | //FIXME JOBAPI this is only required because we don't care about the return value of each (and each shouldn't even have a return value) | ||
229 | .template then<void>([](){}); | ||
230 | } | ||
231 | |||
232 | KAsync::Job<void> Store::flushReplayQueue(const QByteArrayList &resourceIdentifier) | ||
233 | { | ||
234 | return flushMessageQueue(resourceIdentifier); | ||
235 | } | ||
236 | |||
237 | template <class DomainType> | ||
238 | KAsync::Job<DomainType> Store::fetchOne(const Akonadi2::Query &query) | ||
239 | { | ||
240 | return KAsync::start<DomainType>([query](KAsync::Future<DomainType> &future) { | ||
241 | //FIXME We could do this more elegantly if composed jobs would have the correct type (In that case we'd simply return the value from then continuation, and could avoid the outer job entirely) | ||
242 | fetch<DomainType>(query, 1) | ||
243 | .template then<void, QList<typename DomainType::Ptr> >([&future](const QList<typename DomainType::Ptr> &list){ | ||
244 | future.setValue(*list.first()); | ||
245 | future.setFinished(); | ||
246 | }, [&future](int errorCode, const QString &errorMessage) { | ||
247 | future.setError(errorCode, errorMessage); | ||
248 | future.setFinished(); | ||
249 | }).exec(); | ||
250 | }); | ||
251 | } | ||
252 | |||
253 | template <class DomainType> | ||
254 | KAsync::Job<QList<typename DomainType::Ptr> > Store::fetchAll(const Akonadi2::Query &query) | ||
255 | { | ||
256 | return fetch<DomainType>(query); | ||
257 | } | ||
258 | |||
259 | template <class DomainType> | ||
260 | KAsync::Job<QList<typename DomainType::Ptr> > Store::fetch(const Akonadi2::Query &query, int minimumAmount) | ||
261 | { | ||
262 | auto model = loadModel<DomainType>(query); | ||
263 | auto list = QSharedPointer<QList<typename DomainType::Ptr> >::create(); | ||
264 | auto context = QSharedPointer<QObject>::create(); | ||
265 | return KAsync::start<QList<typename DomainType::Ptr> >([model, list, context, minimumAmount](KAsync::Future<QList<typename DomainType::Ptr> > &future) { | ||
266 | if (model->rowCount() >= 1) { | ||
267 | for (int i = 0; i < model->rowCount(); i++) { | ||
268 | list->append(model->index(i, 0, QModelIndex()).data(Akonadi2::Store::DomainObjectRole).template value<typename DomainType::Ptr>()); | ||
269 | } | ||
270 | } else { | ||
271 | QObject::connect(model.data(), &QAbstractItemModel::rowsInserted, context.data(), [model, &future, list](const QModelIndex &index, int start, int end) { | ||
272 | for (int i = start; i <= end; i++) { | ||
273 | list->append(model->index(i, 0, QModelIndex()).data(Akonadi2::Store::DomainObjectRole).template value<typename DomainType::Ptr>()); | ||
274 | } | ||
275 | }); | ||
276 | QObject::connect(model.data(), &QAbstractItemModel::dataChanged, context.data(), [model, &future, list, minimumAmount](const QModelIndex &, const QModelIndex &, const QVector<int> &roles) { | ||
277 | if (roles.contains(ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole)) { | ||
278 | if (list->size() < minimumAmount) { | ||
279 | future.setError(1, "Not enough values."); | ||
280 | } else { | ||
281 | future.setValue(*list); | ||
282 | } | ||
283 | future.setFinished(); | ||
284 | } | ||
285 | }); | ||
286 | } | ||
287 | if (model->data(QModelIndex(), ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole).toBool()) { | ||
288 | if (list->size() < minimumAmount) { | ||
289 | future.setError(1, "Not enough values."); | ||
290 | } else { | ||
291 | future.setValue(*list); | ||
292 | } | ||
293 | future.setFinished(); | ||
294 | } | ||
295 | }); | ||
296 | } | ||
297 | |||
298 | template <class DomainType> | ||
299 | KAsync::Job<void> Resources::inspect(const Inspection &inspectionCommand) | ||
300 | { | ||
301 | auto resource = inspectionCommand.resourceIdentifier; | ||
302 | |||
303 | Trace() << "Sending inspection " << resource; | ||
304 | auto resourceAccess = QSharedPointer<Akonadi2::ResourceAccess>::create(resource); | ||
305 | resourceAccess->open(); | ||
306 | auto notifier = QSharedPointer<Akonadi2::Notifier>::create(resourceAccess); | ||
307 | auto id = QUuid::createUuid().toByteArray(); | ||
308 | return resourceAccess->sendInspectionCommand(id, ApplicationDomain::getTypeName<DomainType>(), inspectionCommand.entityIdentifier, inspectionCommand.property, inspectionCommand.expectedValue) | ||
309 | .template then<void>([resourceAccess, notifier, id](KAsync::Future<void> &future) { | ||
310 | notifier->registerHandler([&future, id](const Notification ¬ification) { | ||
311 | if (notification.id == id) { | ||
312 | if (notification.code) { | ||
313 | future.setError(-1, "Inspection returned an error: " + notification.message); | ||
314 | } else { | ||
315 | future.setFinished(); | ||
316 | } | ||
317 | } | ||
318 | }); | ||
319 | }); | ||
320 | } | ||
321 | |||
322 | class Akonadi2::Notifier::Private { | ||
323 | public: | ||
324 | Private() | ||
325 | : context(new QObject) | ||
326 | { | ||
327 | |||
328 | } | ||
329 | QList<QSharedPointer<ResourceAccess> > resourceAccess; | ||
330 | QList<std::function<void(const Notification &)> > handler; | ||
331 | QSharedPointer<QObject> context; | ||
332 | }; | ||
333 | |||
334 | Notifier::Notifier(const QSharedPointer<ResourceAccess> &resourceAccess) | ||
335 | : d(new Akonadi2::Notifier::Private) | ||
336 | { | ||
337 | QObject::connect(resourceAccess.data(), &ResourceAccess::notification, d->context.data(), [this](const Notification ¬ification) { | ||
338 | for (const auto &handler : d->handler) { | ||
339 | handler(notification); | ||
340 | } | ||
341 | }); | ||
342 | d->resourceAccess << resourceAccess; | ||
343 | } | ||
344 | |||
345 | void Notifier::registerHandler(std::function<void(const Notification &)> handler) | ||
346 | { | ||
347 | d->handler << handler; | ||
348 | } | ||
349 | |||
215 | #define REGISTER_TYPE(T) template KAsync::Job<void> Store::remove<T>(const T &domainObject); \ | 350 | #define REGISTER_TYPE(T) template KAsync::Job<void> Store::remove<T>(const T &domainObject); \ |
216 | template KAsync::Job<void> Store::create<T>(const T &domainObject); \ | 351 | template KAsync::Job<void> Store::create<T>(const T &domainObject); \ |
217 | template KAsync::Job<void> Store::modify<T>(const T &domainObject); \ | 352 | template KAsync::Job<void> Store::modify<T>(const T &domainObject); \ |
218 | template QSharedPointer<QAbstractItemModel> Store::loadModel<T>(Query query); \ | 353 | template QSharedPointer<QAbstractItemModel> Store::loadModel<T>(Query query); \ |
354 | template KAsync::Job<void> Resources::inspect<T>(const Inspection &); \ | ||
355 | template KAsync::Job<T> Store::fetchOne<T>(const Query &); \ | ||
356 | template KAsync::Job<QList<T::Ptr> > Store::fetchAll<T>(const Query &); \ | ||
357 | template KAsync::Job<QList<T::Ptr> > Store::fetch<T>(const Query &, int); \ | ||
219 | 358 | ||
220 | REGISTER_TYPE(ApplicationDomain::Event); | 359 | REGISTER_TYPE(ApplicationDomain::Event); |
221 | REGISTER_TYPE(ApplicationDomain::Mail); | 360 | REGISTER_TYPE(ApplicationDomain::Mail); |