From 4e6b3ce7d1ce97c3e1fb9ae53c5b2be1787acc6b Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 11 Nov 2016 13:06:27 +0100 Subject: Prepared new query based synchronization API --- examples/imapresource/imapresource.cpp | 121 ++++++++++++++++++++------- examples/imapresource/imapserverproxy.h | 16 +++- examples/maildirresource/maildirresource.cpp | 54 +++++++++--- 3 files changed, 149 insertions(+), 42 deletions(-) (limited to 'examples') diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index d5a59b9..302d681 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp @@ -272,41 +272,102 @@ public: } - KAsync::Job synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE + QList getSyncRequests(const Sink::QueryBase &query) Q_DECL_OVERRIDE { - SinkLog() << " Synchronizing"; - return KAsync::start([this]() { - SinkTrace() << "Connecting to:" << mServer << mPort; - SinkTrace() << "as:" << mUser; - auto imap = QSharedPointer::create(mServer, mPort); + QList list; + if (query.type() == ApplicationDomain::getTypeName()) { + list << Synchronizer::SyncRequest{query}; + } else if (query.type() == ApplicationDomain::getTypeName()) { + list << Synchronizer::SyncRequest{query}; + } else { + list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; + list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; + } + return list; + } - return imap->login(mUser, mPassword) - .addToContext(imap) - .onError([](const KAsync::Error &error) { - SinkWarning() << "Login failed."; - }) - .then>([this, imap]() { - auto folderList = QSharedPointer>::create(); - SinkLog() << "Login was successful"; - return imap->fetchFolders([folderList](const Folder &folder) { - *folderList << folder; - }) - .onError([](const KAsync::Error &error) { - SinkWarning() << "Folder list sync failed."; + KAsync::Job login(QSharedPointer imap) + { + SinkTrace() << "Connecting to:" << mServer << mPort; + SinkTrace() << "as:" << mUser; + return imap->login(mUser, mPassword) + .addToContext(imap) + .onError([](const KAsync::Error &error) { + SinkWarning() << "Login failed."; + }); + } + + KAsync::Job synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE + { + if (query.type() == ApplicationDomain::getTypeName()) { + return KAsync::start([this]() { + auto imap = QSharedPointer::create(mServer, mPort); + auto job = login(imap); + job = job.then>([this, imap]() { + auto folderList = QSharedPointer>::create(); + return imap->fetchFolders([folderList](const Folder &folder) { + *folderList << folder; + }) + .onError([](const KAsync::Error &error) { + SinkWarning() << "Folder list sync failed."; + }) + .syncThen>([this, folderList]() { + synchronizeFolders(*folderList); + commit(); + return *folderList; + }); + }); + return job; + }); + } else if (query.type() == ApplicationDomain::getTypeName()) { + //TODO + //if we have a folder filter: + //* execute the folder query and resolve the results to the remote identifier + //* query only those folders + //if we have a date filter: + //* apply the date filter to the fetch + //if we have no folder filter: + //* fetch list of folders from server directly and sync (because we have no guarantee that the folder sync was already processed by the pipeline). + return KAsync::start([this, query]() { + auto imap = QSharedPointer::create(mServer, mPort); + auto job = login(imap); + job = job.then>([this, imap, query]() { + SinkLog() << "Login was successful"; + //FIXME If we were able to to flush in between we could just query the local store for the folder list. + // + if (query.hasFilter()) { + QVector folders; + auto folderFilter = query.getFilter(); + auto localIds = resolveFilter(folderFilter); + auto folderRemoteIds = syncStore().resolveLocalIds(ApplicationDomain::getTypeName(), localIds); + for (const auto &r : folderRemoteIds) { + folders << Folder{r}; + } + return KAsync::value(folders); + } else { + auto folderList = QSharedPointer>::create(); + return imap->fetchFolders([folderList](const Folder &folder) { + *folderList << folder; + }) + .onError([](const KAsync::Error &error) { + SinkWarning() << "Folder list sync failed."; + }) + .syncThen>([this, folderList]() { + return *folderList; + }); + } }) - .syncThen>([this, folderList]() { - synchronizeFolders(*folderList); - commit(); - return *folderList; + .serialEach([this, imap](const Folder &folder) { + if (folder.noselect) { + return KAsync::null(); + } + return synchronizeFolder(imap, folder); }); - }) - .serialEach([this, imap](const Folder &folder) { - if (folder.noselect) { - return KAsync::null(); - } - return synchronizeFolder(imap, folder); + + return job; }); - }); + } + return KAsync::error("Nothing to do"); } public: diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h index 8b39f23..6e6626e 100644 --- a/examples/imapresource/imapserverproxy.h +++ b/examples/imapresource/imapserverproxy.h @@ -58,6 +58,20 @@ struct Message { }; struct Folder { + Folder() = default; + Folder(QList pathParts_, const QString &path_, const QChar &separator_, bool noselect_) + : pathParts(pathParts_), + path(path_), + separator(separator_), + noselect(noselect_) + { + } + + Folder(const QString &path_) + : path(path_) + { + } + QString normalizedPath() const { return pathParts.join('/'); @@ -73,7 +87,7 @@ struct Folder { QList pathParts; QString path; QChar separator; - bool noselect; + bool noselect = false; }; struct SelectResult { diff --git a/examples/maildirresource/maildirresource.cpp b/examples/maildirresource/maildirresource.cpp index 820ec2f..fc77315 100644 --- a/examples/maildirresource/maildirresource.cpp +++ b/examples/maildirresource/maildirresource.cpp @@ -330,25 +330,57 @@ public: SinkLog() << "Synchronized " << count << " mails in " << listingPath << Sink::Log::TraceTime(elapsed) << " " << elapsed/qMax(count, 1) << " [ms/mail]"; } + QList getSyncRequests(const Sink::QueryBase &query) Q_DECL_OVERRIDE + { + QList list; + if (!query.type().isEmpty()) { + //We want to synchronize something specific + list << Synchronizer::SyncRequest{query}; + } else { + //We want to synchronize everything + list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; + //FIXME we can't process the second synchronization before the pipeline of the first one is processed, otherwise we can't execute a query on the local data. + /* list << Synchronizer::SyncRequest{Flush}; */ + list << Synchronizer::SyncRequest{Sink::QueryBase(ApplicationDomain::getTypeName())}; + } + return list; + } + KAsync::Job synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE { - SinkLog() << " Synchronizing"; - return KAsync::start([this]() { + auto job = KAsync::start([this] { KPIM::Maildir maildir(mMaildirPath, true); if (!maildir.isValid(false)) { return KAsync::error(1, "Maildir path doesn't point to a valid maildir: " + mMaildirPath); } - synchronizeFolders(); - //The next sync needs the folders available - commit(); - for (const auto &folder : listAvailableFolders()) { - synchronizeMails(folder); - //Don't let the transaction grow too much - commit(); - } - SinkLog() << "Done Synchronizing"; return KAsync::null(); }); + + if (query.type() == ApplicationDomain::getTypeName()) { + job = job.syncThen([this] { + synchronizeFolders(); + }); + } else if (query.type() == ApplicationDomain::getTypeName()) { + job = job.syncThen([this, query] { + QStringList folders; + if (query.hasFilter()) { + auto folderFilter = query.getFilter(); + auto localIds = resolveFilter(folderFilter); + auto folderRemoteIds = syncStore().resolveLocalIds(ApplicationDomain::getTypeName(), localIds); + for (const auto &r : folderRemoteIds) { + folders << r; + } + } else { + folders = listAvailableFolders(); + } + for (const auto &folder : folders) { + synchronizeMails(folder); + //Don't let the transaction grow too much + commit(); + } + }); + } + return job; } public: -- cgit v1.2.3