From a41d7ee237918584ea45405d20dee4f680fe7071 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Wed, 8 Feb 2017 14:09:43 +0100 Subject: Added session cache. So we can avoid logging in for every command. --- examples/imapresource/imapresource.cpp | 9 ++-- examples/imapresource/imapserverproxy.cpp | 83 ++++++++++++++--------------- examples/imapresource/imapserverproxy.h | 87 ++++++++++++++++++++++++++++--- 3 files changed, 125 insertions(+), 54 deletions(-) (limited to 'examples/imapresource') 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) class ImapSynchronizer : public Sink::Synchronizer { + Q_OBJECT public: ImapSynchronizer(const ResourceContext &resourceContext) : Sink::Synchronizer(resourceContext) @@ -432,7 +433,7 @@ public: KAsync::Job synchronizeWithSource(const Sink::QueryBase &query) Q_DECL_OVERRIDE { - auto imap = QSharedPointer::create(mServer, mPort); + auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); if (query.type() == ApplicationDomain::getTypeName()) { return login(imap) .then([=] { @@ -528,7 +529,7 @@ public: KAsync::Job replay(const ApplicationDomain::Mail &mail, Sink::Operation operation, const QByteArray &oldRemoteId, const QList &changedProperties) Q_DECL_OVERRIDE { - auto imap = QSharedPointer::create(mServer, mPort); + auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); auto login = imap->login(mUser, mPassword); KAsync::Job job = KAsync::null(); if (operation == Sink::Operation_Creation) { @@ -607,7 +608,7 @@ public: KAsync::Job replay(const ApplicationDomain::Folder &folder, Sink::Operation operation, const QByteArray &oldRemoteId, const QList &changedProperties) Q_DECL_OVERRIDE { - auto imap = QSharedPointer::create(mServer, mPort); + auto imap = QSharedPointer::create(mServer, mPort, &mSessionCache); auto login = imap->login(mUser, mPassword); if (operation == Sink::Operation_Creation) { QString parentFolder; @@ -684,6 +685,7 @@ public: QString mUser; QString mPassword; QByteArray mResourceInstanceIdentifier; + Imap::SessionCache mSessionCache; }; class ImapInspector : public Sink::Inspector { @@ -908,3 +910,4 @@ void ImapResourceFactory::removeDataFromDisk(const QByteArray &instanceIdentifie ImapResource::removeFromDisk(instanceIdentifier); } +#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 runJob(KJob *job) }); } -ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port) : mSession(new KIMAP2::Session(serverUrl, qint16(port))) +ImapServerProxy::ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache) : mSession(new KIMAP2::Session(serverUrl, qint16(port))), mSessionCache(sessionCache) { QObject::connect(mSession, &KIMAP2::Session::sslErrors, [this](const QList &errors) { - SinkLog() << "Got ssl error: " << errors; + SinkLog() << "Received ssl error: " << errors; mSession->ignoreErrors(errors); }); if (Sink::Test::testModeEnabled()) { mSession->setTimeout(1); } else { - mSession->setTimeout(20); + mSession->setTimeout(40); } } KAsync::Job ImapServerProxy::login(const QString &username, const QString &password) { + if (mSessionCache) { + auto session = mSessionCache->getSession(); + if (session.isValid()) { + mSession = session.mSession; + mCapabilities = session.mCapabilities; + mNamespaces = session.mNamespaces; + } + } + Q_ASSERT(mSession); + if (mSession->state() == KIMAP2::Session::Authenticated || mSession->state() == KIMAP2::Session::Selected) { + SinkLog() << "Reusing existing session."; + return KAsync::null(); + } auto loginJob = new KIMAP2::LoginJob(mSession); loginJob->setUserName(username); loginJob->setPassword(password); @@ -140,28 +153,25 @@ KAsync::Job ImapServerProxy::login(const QString &username, const QString } } }).then(runJob(namespaceJob)).then([this, namespaceJob] { - for (const auto &ns :namespaceJob->personalNamespaces()) { - mPersonalNamespaces << ns.name; - mPersonalNamespaceSeparator = ns.separator; - } - for (const auto &ns :namespaceJob->sharedNamespaces()) { - mSharedNamespaces << ns.name; - mSharedNamespaceSeparator = ns.separator; - } - for (const auto &ns :namespaceJob->userNamespaces()) { - mUserNamespaces << ns.name; - mUserNamespaceSeparator = ns.separator; - } - SinkTrace() << "Found personal namespaces: " << mPersonalNamespaces << mPersonalNamespaceSeparator; - SinkTrace() << "Found shared namespaces: " << mSharedNamespaces << mSharedNamespaceSeparator; - SinkTrace() << "Found user namespaces: " << mUserNamespaces << mUserNamespaceSeparator; + mNamespaces.personal = namespaceJob->personalNamespaces(); + mNamespaces.shared = namespaceJob->sharedNamespaces(); + mNamespaces.user = namespaceJob->userNamespaces(); + // SinkTrace() << "Found personal namespaces: " << mNamespaces.personal; + // SinkTrace() << "Found shared namespaces: " << mNamespaces.shared; + // SinkTrace() << "Found user namespaces: " << mNamespaces.user; }); } KAsync::Job ImapServerProxy::logout() { - auto logoutJob = new KIMAP2::LogoutJob(mSession); - return runJob(logoutJob); + if (mSessionCache) { + auto session = CachedSession{mSession, mCapabilities, mNamespaces}; + if (session.isConnected()) { + mSessionCache->recycleSession(session); + return KAsync::null(); + } + } + return runJob(new KIMAP2::LogoutJob(mSession)); } KAsync::Job ImapServerProxy::select(const QString &mailbox) @@ -376,12 +386,13 @@ KAsync::Job ImapServerProxy::move(const QString &mailbox, const KIMAP2::Im KAsync::Job ImapServerProxy::createSubfolder(const QString &parentMailbox, const QString &folderName) { return KAsync::start([this, parentMailbox, folderName]() { - Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); QString folder; if (parentMailbox.isEmpty()) { - folder = mPersonalNamespaces.isEmpty() ? "" : mPersonalNamespaces.toList().first() + folderName; + auto ns = mNamespaces.getDefaultNamespace(); + folder = ns.name + folderName; } else { - folder = parentMailbox + mPersonalNamespaceSeparator + folderName; + auto ns = mNamespaces.getNamespace(parentMailbox); + folder = parentMailbox + ns.separator + folderName; } SinkTrace() << "Creating subfolder: " << folder; return create(folder) @@ -394,10 +405,10 @@ KAsync::Job ImapServerProxy::createSubfolder(const QString &parentMailb KAsync::Job ImapServerProxy::renameSubfolder(const QString &oldMailbox, const QString &newName) { return KAsync::start([this, oldMailbox, newName] { - Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); - auto parts = oldMailbox.split(mPersonalNamespaceSeparator); + auto ns = mNamespaces.getNamespace(oldMailbox); + auto parts = oldMailbox.split(ns.separator); parts.removeLast(); - QString folder = parts.join(mPersonalNamespaceSeparator) + mPersonalNamespaceSeparator + newName; + QString folder = parts.join(ns.separator) + ns.separator + newName; SinkTrace() << "Renaming subfolder: " << oldMailbox << folder; return rename(oldMailbox, folder) .then([=]() { @@ -408,22 +419,8 @@ KAsync::Job ImapServerProxy::renameSubfolder(const QString &oldMailbox, QString ImapServerProxy::getNamespace(const QString &name) { - for (const auto &ns : mPersonalNamespaces) { - if (name.startsWith(ns)) { - return ns; - } - } - for (const auto &ns : mSharedNamespaces) { - if (name.startsWith(ns)) { - return ns; - } - } - for (const auto &ns : mUserNamespaces) { - if (name.startsWith(ns)) { - return ns; - } - } - return QString{}; + auto ns = mNamespaces.getNamespace(name); + return ns.name; } KAsync::Job ImapServerProxy::fetchFolders(std::function callback) @@ -474,7 +471,6 @@ KAsync::Job ImapServerProxy::fetchMessages(const Folder &folder, qint64 ui { auto time = QSharedPointer::create(); time->start(); - Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); return select(mailboxFromFolder(folder)).then([this, callback, folder, time, progress, uidNext](const SelectResult &selectResult) -> KAsync::Job { SinkTrace() << "UIDNEXT " << folder.path() << selectResult.uidNext << uidNext; if (selectResult.uidNext == (uidNext + 1)) { @@ -498,7 +494,6 @@ KAsync::Job ImapServerProxy::fetchMessages(const Folder &folder, const QVe { auto time = QSharedPointer::create(); time->start(); - Q_ASSERT(!mPersonalNamespaceSeparator.isNull()); return select(mailboxFromFolder(folder)).then([this, callback, folder, time, progress, uidsToFetch, headersOnly](const SelectResult &selectResult) -> KAsync::Job { 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 { quint64 highestModSequence; }; +class Namespaces { +public: + QList personal; + QList shared; + QList user; + + KIMAP2::MailBoxDescriptor getDefaultNamespace() + { + return personal.isEmpty() ? KIMAP2::MailBoxDescriptor{} : personal.first(); + } + + KIMAP2::MailBoxDescriptor getNamespace(const QString &mailbox) + { + for (const auto &ns : personal) { + if (mailbox.startsWith(ns.name)) { + return ns; + } + } + for (const auto &ns : shared) { + if (mailbox.startsWith(ns.name)) { + return ns; + } + } + for (const auto &ns : user) { + if (mailbox.startsWith(ns.name)) { + return ns; + } + } + return KIMAP2::MailBoxDescriptor{}; + } +}; + +class CachedSession { +public: + + CachedSession() = default; + CachedSession(KIMAP2::Session *session, const QStringList &cap, const Namespaces &ns) : mSession(session), mCapabilities(cap), mNamespaces(ns) + { + } + + bool isConnected() + { + return (mSession->state() == KIMAP2::Session::State::Authenticated || mSession->state() == KIMAP2::Session::State::Selected) ; + } + + bool isValid() + { + return mSession; + } + + KIMAP2::Session *mSession = nullptr; + QStringList mCapabilities; + Namespaces mNamespaces; +}; + +class SessionCache : public QObject { + Q_OBJECT +public: + void recycleSession(const CachedSession &session) + { + mSessions << session; + } + + CachedSession getSession() + { + while (!mSessions.isEmpty()) { + auto session = mSessions.takeLast(); + if (session.isConnected()) { + return session; + } + } + return CachedSession{}; + } +private: + QList mSessions; +}; + class ImapServerProxy { KIMAP2::Session *mSession; QStringList mCapabilities; + Namespaces mNamespaces; - QSet mPersonalNamespaces; - QChar mPersonalNamespaceSeparator; - QSet mSharedNamespaces; - QChar mSharedNamespaceSeparator; - QSet mUserNamespaces; - QChar mUserNamespaceSeparator; public: - ImapServerProxy(const QString &serverUrl, int port); + ImapServerProxy(const QString &serverUrl, int port, SessionCache *sessionCache = nullptr); //Standard IMAP calls KAsync::Job login(const QString &username, const QString &password); @@ -186,6 +258,7 @@ public: private: QString getNamespace(const QString &name); QObject mGuard; + SessionCache *mSessionCache; }; } -- cgit v1.2.3