File indexing completed on 2024-11-10 04:40:31

0001 /*
0002  * SPDX-FileCopyrightText: 2009 Volker Krause <vkrause@kde.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include "resourcesynchronizationjob.h"
0008 #include "agentinstance.h"
0009 #include "agentmanager.h"
0010 #include "akonadicore_debug.h"
0011 #include "kjobprivatebase_p.h"
0012 #include "resourceinterface.h"
0013 #include "servermanager.h"
0014 #include <QDBusConnection>
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QDBusInterface>
0019 #include <QTimer>
0020 
0021 namespace Akonadi
0022 {
0023 class ResourceSynchronizationJobPrivate : public KJobPrivateBase
0024 {
0025     Q_OBJECT
0026 
0027 public:
0028     explicit ResourceSynchronizationJobPrivate(ResourceSynchronizationJob *parent)
0029         : q(parent)
0030     {
0031         connect(&safetyTimer, &QTimer::timeout, this, &ResourceSynchronizationJobPrivate::slotTimeout);
0032         safetyTimer.setInterval(std::chrono::seconds{30});
0033         safetyTimer.setSingleShot(true);
0034     }
0035 
0036     void doStart() override;
0037 
0038     ResourceSynchronizationJob *const q;
0039     AgentInstance instance;
0040     std::unique_ptr<org::freedesktop::Akonadi::Resource> interface;
0041     QTimer safetyTimer;
0042     int timeoutCount = 60;
0043     bool collectionTreeOnly = false;
0044     int timeoutCountLimit = 0;
0045 
0046     void slotSynchronized();
0047     void slotTimeout();
0048 };
0049 
0050 ResourceSynchronizationJob::ResourceSynchronizationJob(const AgentInstance &instance, QObject *parent)
0051     : KJob(parent)
0052     , d(new ResourceSynchronizationJobPrivate(this))
0053 {
0054     d->instance = instance;
0055 }
0056 
0057 ResourceSynchronizationJob::~ResourceSynchronizationJob() = default;
0058 
0059 void ResourceSynchronizationJob::start()
0060 {
0061     d->start();
0062 }
0063 
0064 void ResourceSynchronizationJob::setTimeoutCountLimit(int count)
0065 {
0066     d->timeoutCountLimit = count;
0067 }
0068 
0069 int ResourceSynchronizationJob::timeoutCountLimit() const
0070 {
0071     return d->timeoutCountLimit;
0072 }
0073 
0074 bool ResourceSynchronizationJob::collectionTreeOnly() const
0075 {
0076     return d->collectionTreeOnly;
0077 }
0078 
0079 void ResourceSynchronizationJob::setCollectionTreeOnly(bool b)
0080 {
0081     d->collectionTreeOnly = b;
0082 }
0083 
0084 void ResourceSynchronizationJobPrivate::doStart()
0085 {
0086     if (!instance.isValid()) {
0087         q->setError(KJob::UserDefinedError);
0088         q->setErrorText(i18n("Invalid resource instance."));
0089         q->emitResult();
0090         return;
0091     }
0092 
0093     using ResourceIface = org::freedesktop::Akonadi::Resource;
0094     interface = std::make_unique<ResourceIface>(ServerManager::agentServiceName(ServerManager::Resource, instance.identifier()),
0095                                                 QStringLiteral("/"),
0096                                                 QDBusConnection::sessionBus());
0097     if (collectionTreeOnly) {
0098         connect(interface.get(), &ResourceIface::collectionTreeSynchronized, this, &ResourceSynchronizationJobPrivate::slotSynchronized);
0099     } else {
0100         connect(interface.get(), &ResourceIface::synchronized, this, &ResourceSynchronizationJobPrivate::slotSynchronized);
0101     }
0102 
0103     if (interface->isValid()) {
0104         if (collectionTreeOnly) {
0105             instance.synchronizeCollectionTree();
0106         } else {
0107             instance.synchronize();
0108         }
0109 
0110         safetyTimer.start();
0111     } else {
0112         q->setError(KJob::UserDefinedError);
0113         q->setErrorText(i18n("Unable to obtain D-Bus interface for resource '%1'", instance.identifier()));
0114         q->emitResult();
0115         return;
0116     }
0117 }
0118 
0119 void ResourceSynchronizationJobPrivate::slotSynchronized()
0120 {
0121     using ResourceIface = org::freedesktop::Akonadi::Resource;
0122     if (collectionTreeOnly) {
0123         disconnect(interface.get(), &ResourceIface::collectionTreeSynchronized, this, &ResourceSynchronizationJobPrivate::slotSynchronized);
0124     } else {
0125         disconnect(interface.get(), &ResourceIface::synchronized, this, &ResourceSynchronizationJobPrivate::slotSynchronized);
0126     }
0127     safetyTimer.stop();
0128     q->emitResult();
0129 }
0130 
0131 void ResourceSynchronizationJobPrivate::slotTimeout()
0132 {
0133     instance = AgentManager::self()->instance(instance.identifier());
0134     timeoutCount++;
0135 
0136     if (timeoutCount > timeoutCountLimit) {
0137         safetyTimer.stop();
0138         q->setError(KJob::UserDefinedError);
0139         q->setErrorText(i18n("Resource synchronization timed out."));
0140         q->emitResult();
0141         return;
0142     }
0143 
0144     if (instance.status() == AgentInstance::Idle) {
0145         // try again, we might have lost the synchronized()/synchronizedCollectionTree() signal
0146         qCDebug(AKONADICORE_LOG) << "trying again to sync resource" << instance.identifier();
0147         if (collectionTreeOnly) {
0148             instance.synchronizeCollectionTree();
0149         } else {
0150             instance.synchronize();
0151         }
0152     }
0153 }
0154 
0155 AgentInstance ResourceSynchronizationJob::resource() const
0156 {
0157     return d->instance;
0158 }
0159 
0160 } // namespace Akonadi
0161 
0162 #include "resourcesynchronizationjob.moc"
0163 
0164 #include "moc_resourcesynchronizationjob.cpp"