diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-02-08 14:09:43 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2017-02-08 14:09:43 +0100 |
commit | a41d7ee237918584ea45405d20dee4f680fe7071 (patch) | |
tree | aa87ba170b2f5b5e9f67254dd598193cd4c15987 | |
parent | a21368827de7a2d70ef2a260cb35c25fcf5967e8 (diff) | |
download | sink-a41d7ee237918584ea45405d20dee4f680fe7071.tar.gz sink-a41d7ee237918584ea45405d20dee4f680fe7071.zip |
Added session cache.
So we can avoid logging in for every command.
-rw-r--r-- | examples/imapresource/imapresource.cpp | 9 | ||||
-rw-r--r-- | examples/imapresource/imapserverproxy.cpp | 83 | ||||
-rw-r--r-- | examples/imapresource/imapserverproxy.h | 87 |
3 files changed, 125 insertions, 54 deletions
diff --git a/examples/imapresource/imapresource.cpp b/examples/imapresource/imapresource.cpp index 06dc340..04cedff 100644 --- a/examples/imapresource/imapresource.cpp +++ b/examples/imapresource/imapresource.cpp | |||
@@ -89,6 +89,7 @@ static QByteArray parentRid(const Imap::Folder &folder) | |||
89 | 89 | ||
90 | 90 | ||
91 | class ImapSynchronizer : public Sink::Synchronizer { | 91 | class ImapSynchronizer : public Sink::Synchronizer { |
92 | Q_OBJECT | ||
92 | public: | 93 | public: |
93 | ImapSynchronizer(const ResourceContext &resourceContext) | 94 | ImapSynchronizer(const ResourceContext &resourceContext) |
94 | : Sink::Synchronizer(resourceContext) | 95 | : Sink::Synchronizer(resourceContext) |
@@ -432,7 +433,7 @@ public: | |||
432 | 433 | ||
433 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE | 434 | KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE |
434 | { | 435 | { |
435 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | 436 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); |
436 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { | 437 | if (query.type() == ApplicationDomain::getTypeName<ApplicationDomain::Folder>()) { |
437 | return login(imap) | 438 | return login(imap) |
438 | .then([=] { | 439 | .then([=] { |
@@ -528,7 +529,7 @@ public: | |||
528 | 529 | ||
529 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 530 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
530 | { | 531 | { |
531 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | 532 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); |
532 | auto login = imap->login(mUser, mPassword); | 533 | auto login = imap->login(mUser, mPassword); |
533 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); | 534 | KAsync::Job<QByteArray> job = KAsync::null<QByteArray>(); |
534 | if (operation == Sink::Operation_Creation) { | 535 | if (operation == Sink::Operation_Creation) { |
@@ -607,7 +608,7 @@ public: | |||
607 | 608 | ||
608 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE | 609 | KAsync::Job<QByteArray> replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList<QByteArray> &changedProperties) Q_DECL_OVERRIDE |
609 | { | 610 | { |
610 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort); | 611 | auto imap = QSharedPointer<ImapServerProxy>::create(mServer, mPort, &mSessionCache); |
611 | auto login = imap->login(mUser, mPassword); | 612 | auto login = imap->login(mUser, mPassword); |
612 | if (operation == Sink::Operation_Creation) { | 613 | if (operation == Sink::Operation_Creation) { |
613 | QString parentFolder; | 614 | QString parentFolder; |
@@ -684,6 +685,7 @@ public: | |||
684 | QString mUser; | 685 | QString mUser; |
685 | QString mPassword; | 686 | QString mPassword; |
686 | QByteArray mResourceInstanceIdentifier; | 687 | QByteArray mResourceInstanceIdentifier; |
688 | Imap::SessionCache mSessionCache; | ||
687 | }; | 689 | }; |
688 | 690 | ||
689 | class ImapInspector : public Sink::Inspector { | 691 | class ImapInspector : public Sink::Inspector { |
@@ -908,3 +910,4 @@ void ImapResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifie | |||
908 | ImapResource::removeFromDisk(instanceIdentifier); | 910 | ImapResource::removeFromDisk(instanceIdentifier); |
909 | } | 911 | } |
910 | 912 | ||
913 | #include "imapresource.moc" | ||
diff --git a/examples/imapresource/imapserverproxy.cpp b/examples/imapresource/imapserverproxy.cpp index 304a0e8..4ef3000 100644 --- a/examples/imapresource/imapserverproxy.cpp +++ b/examples/imapresource/imapserverproxy.cpp | |||
@@ -98,22 +98,35 @@ static KAsync::Job<void> runJob(KJob *job) | |||
98 | }); | 98 | }); |
99 | } | 99 | } |
100 | 100 | ||
101 | ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port) : mSession(new KIMAP2::Session(serverUrl, qint16(port))) | 101 | ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache) : mSession(new KIMAP2::Session(serverUrl, qint16(port))), mSessionCache(sessionCache) |
102 | { | 102 | { |
103 | QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList<QSslError> &errors) { | 103 | QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList<QSslError> &errors) { |
104 | SinkLog() << "Got ssl error: " << errors; | 104 | SinkLog() << "Received ssl error: " << errors; |
105 | mSession->ignoreErrors(errors); | 105 | mSession->ignoreErrors(errors); |
106 | }); | 106 | }); |
107 | 107 | ||
108 | if (Sink::Test::testModeEnabled()) { | 108 | if (Sink::Test::testModeEnabled()) { |
109 | mSession->setTimeout(1); | 109 | mSession->setTimeout(1); |
110 | } else { | 110 | } else { |
111 | mSession->setTimeout(20); | 111 | mSession->setTimeout(40); |
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString &password) | 115 | KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString &password) |
116 | { | 116 | { |
117 | if (mSessionCache) { | ||
118 | auto session = mSessionCache->getSession(); | ||
119 | if (session.isValid()) { | ||
120 | mSession = session.mSession; | ||
121 | mCapabilities = session.mCapabilities; | ||
122 | mNamespaces = session.mNamespaces; | ||
123 | } | ||
124 | } | ||
125 | Q_ASSERT(mSession); | ||
126 | if (mSession->state() == KIMAP2::Session::Authenticated || mSession->state() == KIMAP2::Session::Selected) { | ||
127 | SinkLog() << "Reusing existing session."; | ||
128 | return KAsync::null(); | ||
129 | } | ||
117 | auto loginJob = new KIMAP2::LoginJob(mSession); | 130 | auto loginJob = new KIMAP2::LoginJob(mSession); |
118 | loginJob->setUserName(username); | 131 | loginJob->setUserName(username); |
119 | loginJob->setPassword(password); | 132 | loginJob->setPassword(password); |
@@ -140,28 +153,25 @@ KAsync::Job<void> ImapServerProxy::login(const QString &username, const QString | |||
140 | } | 153 | } |
141 | } | 154 | } |
142 | }).then(runJob(namespaceJob)).then([this, namespaceJob] { | 155 | }).then(runJob(namespaceJob)).then([this, namespaceJob] { |
143 | for (const auto &ns :namespaceJob->personalNamespaces()) { | 156 | mNamespaces.personal = namespaceJob->personalNamespaces(); |
144 | mPersonalNamespaces << ns.name; | 157 | mNamespaces.shared = namespaceJob->sharedNamespaces(); |
145 | mPersonalNamespaceSeparator = ns.separator; | 158 | mNamespaces.user = namespaceJob->userNamespaces(); |
146 | } | 159 | // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; |
147 | for (const auto &ns :namespaceJob->sharedNamespaces()) { | 160 | // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; |
148 | mSharedNamespaces << ns.name; | 161 | // SinkTrace() << "Found user namespaces: " << mNamespaces.user; |
149 | mSharedNamespaceSeparator = ns.separator; | ||
150 | } | ||
151 | for (const auto &ns :namespaceJob->userNamespaces()) { | ||
152 | mUserNamespaces << ns.name; | ||
153 | mUserNamespaceSeparator = ns.separator; | ||
154 | } | ||
155 | SinkTrace() << "Found personal namespaces: " << mPersonalNamespaces << mPersonalNamespaceSeparator; | ||
156 | SinkTrace() << "Found shared namespaces: " << mSharedNamespaces << mSharedNamespaceSeparator; | ||
157 | SinkTrace() << "Found user namespaces: " << mUserNamespaces << mUserNamespaceSeparator; | ||
158 | }); | 162 | }); |
159 | } | 163 | } |
160 | 164 | ||
161 | KAsync::Job<void> ImapServerProxy::logout() | 165 | KAsync::Job<void> ImapServerProxy::logout() |
162 | { | 166 | { |
163 | auto logoutJob = new KIMAP2::LogoutJob(mSession); | 167 | if (mSessionCache) { |
164 | return runJob(logoutJob); | 168 | auto session = CachedSession{mSession, mCapabilities, mNamespaces}; |
169 | if (session.isConnected()) { | ||
170 | mSessionCache->recycleSession(session); | ||
171 | return KAsync::null(); | ||
172 | } | ||
173 | } | ||
174 | return runJob(new KIMAP2::LogoutJob(mSession)); | ||
165 | } | 175 | } |
166 | 176 | ||
167 | KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox) | 177 | KAsync::Job<SelectResult> ImapServerProxy::select(const QString &mailbox) |
@@ -376,12 +386,13 @@ KAsync::Job<void> ImapServerProxy::move(const QString &mailbox, const KIMAP2::Im | |||
376 | KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName) | 386 | KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName) |
377 | { | 387 | { |
378 | return KAsync::start<QString>([this, parentMailbox, folderName]() { | 388 | return KAsync::start<QString>([this, parentMailbox, folderName]() { |
379 | Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); | ||
380 | QString folder; | 389 | QString folder; |
381 | if (parentMailbox.isEmpty()) { | 390 | if (parentMailbox.isEmpty()) { |
382 | folder = mPersonalNamespaces.isEmpty() ? "" : mPersonalNamespaces.toList().first() + folderName; | 391 | auto ns = mNamespaces.getDefaultNamespace(); |
392 | folder = ns.name + folderName; | ||
383 | } else { | 393 | } else { |
384 | folder = parentMailbox + mPersonalNamespaceSeparator + folderName; | 394 | auto ns = mNamespaces.getNamespace(parentMailbox); |
395 | folder = parentMailbox + ns.separator + folderName; | ||
385 | } | 396 | } |
386 | SinkTrace() << "Creating subfolder: " << folder; | 397 | SinkTrace() << "Creating subfolder: " << folder; |
387 | return create(folder) | 398 | return create(folder) |
@@ -394,10 +405,10 @@ KAsync::Job<QString> ImapServerProxy::createSubfolder(const QString &parentMailb | |||
394 | KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName) | 405 | KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName) |
395 | { | 406 | { |
396 | return KAsync::start<QString>([this, oldMailbox, newName] { | 407 | return KAsync::start<QString>([this, oldMailbox, newName] { |
397 | Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); | 408 | auto ns = mNamespaces.getNamespace(oldMailbox); |
398 | auto parts = oldMailbox.split(mPersonalNamespaceSeparator); | 409 | auto parts = oldMailbox.split(ns.separator); |
399 | parts.removeLast(); | 410 | parts.removeLast(); |
400 | QString folder = parts.join(mPersonalNamespaceSeparator) + mPersonalNamespaceSeparator + newName; | 411 | QString folder = parts.join(ns.separator) + ns.separator + newName; |
401 | SinkTrace() << "Renaming subfolder: " << oldMailbox << folder; | 412 | SinkTrace() << "Renaming subfolder: " << oldMailbox << folder; |
402 | return rename(oldMailbox, folder) | 413 | return rename(oldMailbox, folder) |
403 | .then([=]() { | 414 | .then([=]() { |
@@ -408,22 +419,8 @@ KAsync::Job<QString> ImapServerProxy::renameSubfolder(const QString &oldMailbox, | |||
408 | 419 | ||
409 | QString ImapServerProxy::getNamespace(const QString &name) | 420 | QString ImapServerProxy::getNamespace(const QString &name) |
410 | { | 421 | { |
411 | for (const auto &ns : mPersonalNamespaces) { | 422 | auto ns = mNamespaces.getNamespace(name); |
412 | if (name.startsWith(ns)) { | 423 | return ns.name; |
413 | return ns; | ||
414 | } | ||
415 | } | ||
416 | for (const auto &ns : mSharedNamespaces) { | ||
417 | if (name.startsWith(ns)) { | ||
418 | return ns; | ||
419 | } | ||
420 | } | ||
421 | for (const auto &ns : mUserNamespaces) { | ||
422 | if (name.startsWith(ns)) { | ||
423 | return ns; | ||
424 | } | ||
425 | } | ||
426 | return QString{}; | ||
427 | } | 424 | } |
428 | 425 | ||
429 | KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) | 426 | KAsync::Job<void> ImapServerProxy::fetchFolders(std::function<void(const Folder &)> callback) |
@@ -474,7 +471,6 @@ KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, qint64 ui | |||
474 | { | 471 | { |
475 | auto time = QSharedPointer<QTime>::create(); | 472 | auto time = QSharedPointer<QTime>::create(); |
476 | time->start(); | 473 | time->start(); |
477 | Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); | ||
478 | return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidNext](const SelectResult &selectResult) -> KAsync::Job<void> { | 474 | return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidNext](const SelectResult &selectResult) -> KAsync::Job<void> { |
479 | SinkTrace() << "UIDNEXT " << folder.path() << selectResult.uidNext << uidNext; | 475 | SinkTrace() << "UIDNEXT " << folder.path() << selectResult.uidNext << uidNext; |
480 | if (selectResult.uidNext == (uidNext + 1)) { | 476 | if (selectResult.uidNext == (uidNext + 1)) { |
@@ -498,7 +494,6 @@ KAsync::Job<void> ImapServerProxy::fetchMessages(const Folder &folder, const QVe | |||
498 | { | 494 | { |
499 | auto time = QSharedPointer<QTime>::create(); | 495 | auto time = QSharedPointer<QTime>::create(); |
500 | time->start(); | 496 | time->start(); |
501 | Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); | ||
502 | return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidsToFetch, headersOnly](const SelectResult &selectResult) -> KAsync::Job<void> { | 497 | return select(mailboxFromFolder(folder)).then<void, SelectResult>([this, callback, folder, time, progress, uidsToFetch, headersOnly](const SelectResult &selectResult) -> KAsync::Job<void> { |
503 | 498 | ||
504 | SinkTrace() << "Fetching messages" << folder.path(); | 499 | SinkTrace() << "Fetching messages" << folder.path(); |
diff --git a/examples/imapresource/imapserverproxy.h b/examples/imapresource/imapserverproxy.h index 6785fc2..081750f 100644 --- a/examples/imapresource/imapserverproxy.h +++ b/examples/imapresource/imapserverproxy.h | |||
@@ -124,19 +124,91 @@ struct SelectResult { | |||
124 | quint64 highestModSequence; | 124 | quint64 highestModSequence; |
125 | }; | 125 | }; |
126 | 126 | ||
127 | class Namespaces { | ||
128 | public: | ||
129 | QList<KIMAP2::MailBoxDescriptor> personal; | ||
130 | QList<KIMAP2::MailBoxDescriptor> shared; | ||
131 | QList<KIMAP2::MailBoxDescriptor> user; | ||
132 | |||
133 | KIMAP2::MailBoxDescriptor getDefaultNamespace() | ||
134 | { | ||
135 | return personal.isEmpty() ? KIMAP2::MailBoxDescriptor{} : personal.first(); | ||
136 | } | ||
137 | |||
138 | KIMAP2::MailBoxDescriptor getNamespace(const QString &mailbox) | ||
139 | { | ||
140 | for (const auto &ns : personal) { | ||
141 | if (mailbox.startsWith(ns.name)) { | ||
142 | return ns; | ||
143 | } | ||
144 | } | ||
145 | for (const auto &ns : shared) { | ||
146 | if (mailbox.startsWith(ns.name)) { | ||
147 | return ns; | ||
148 | } | ||
149 | } | ||
150 | for (const auto &ns : user) { | ||
151 | if (mailbox.startsWith(ns.name)) { | ||
152 | return ns; | ||
153 | } | ||
154 | } | ||
155 | return KIMAP2::MailBoxDescriptor{}; | ||
156 | } | ||
157 | }; | ||
158 | |||
159 | class CachedSession { | ||
160 | public: | ||
161 | |||
162 | CachedSession() = default; | ||
163 | CachedSession(KIMAP2::Session *session, const QStringList &cap, const Namespaces &ns) : mSession(session), mCapabilities(cap), mNamespaces(ns) | ||
164 | { | ||
165 | } | ||
166 | |||
167 | bool isConnected() | ||
168 | { | ||
169 | return (mSession->state() == KIMAP2::Session::State::Authenticated || mSession->state() == KIMAP2::Session::State::Selected) ; | ||
170 | } | ||
171 | |||
172 | bool isValid() | ||
173 | { | ||
174 | return mSession; | ||
175 | } | ||
176 | |||
177 | KIMAP2::Session *mSession = nullptr; | ||
178 | QStringList mCapabilities; | ||
179 | Namespaces mNamespaces; | ||
180 | }; | ||
181 | |||
182 | class SessionCache : public QObject { | ||
183 | Q_OBJECT | ||
184 | public: | ||
185 | void recycleSession(const CachedSession &session) | ||
186 | { | ||
187 | mSessions << session; | ||
188 | } | ||
189 | |||
190 | CachedSession getSession() | ||
191 | { | ||
192 | while (!mSessions.isEmpty()) { | ||
193 | auto session = mSessions.takeLast(); | ||
194 | if (session.isConnected()) { | ||
195 | return session; | ||
196 | } | ||
197 | } | ||
198 | return CachedSession{}; | ||
199 | } | ||
200 | private: | ||
201 | QList<CachedSession> mSessions; | ||
202 | }; | ||
203 | |||
127 | class ImapServerProxy { | 204 | class ImapServerProxy { |
128 | KIMAP2::Session *mSession; | 205 | KIMAP2::Session *mSession; |
129 | QStringList mCapabilities; | 206 | QStringList mCapabilities; |
207 | Namespaces mNamespaces; | ||
130 | 208 | ||
131 | QSet<QString> mPersonalNamespaces; | ||
132 | QChar mPersonalNamespaceSeparator; | ||
133 | QSet<QString> mSharedNamespaces; | ||
134 | QChar mSharedNamespaceSeparator; | ||
135 | QSet<QString> mUserNamespaces; | ||
136 | QChar mUserNamespaceSeparator; | ||
137 | 209 | ||
138 | public: | 210 | public: |
139 | ImapServerProxy(const QString &serverUrl, int port); | 211 | ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache = nullptr); |
140 | 212 | ||
141 | //Standard IMAP calls | 213 | //Standard IMAP calls |
142 | KAsync::Job<void> login(const QString &username, const QString &password); | 214 | KAsync::Job<void> login(const QString &username, const QString &password); |
@@ -186,6 +258,7 @@ public: | |||
186 | private: | 258 | private: |
187 | QString getNamespace(const QString &name); | 259 | QString getNamespace(const QString &name); |
188 | QObject mGuard; | 260 | QObject mGuard; |
261 | SessionCache *mSessionCache; | ||
189 | }; | 262 | }; |
190 | 263 | ||
191 | } | 264 | } |