/* * Copyright (C) 2016 Christian Mollekopf * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "sourcewriteback.h" #include "definitions.h" #include "log.h" #include "bufferutils.h" #include "entitybuffer.h" #include "entity_generated.h" #define ENTITY_TYPE_MAIL "mail" #define ENTITY_TYPE_FOLDER "folder" SINK_DEBUG_AREA("sourcewriteback") using namespace Sink; SourceWriteBack::SourceWriteBack(const ResourceContext &context) : ChangeReplay(context), mResourceContext(context), mSyncStorage(Sink::storageLocation(), context.instanceId() + ".synchronization", Sink::Storage::DataStore::ReadWrite), mEntityStore(QSharedPointer::create(mResourceContext)) { } Storage::EntityStore &SourceWriteBack::store() { return *mEntityStore; } RemoteIdMap &SourceWriteBack::syncStore() { if (!mSyncStore) { mSyncStore = QSharedPointer::create(mSyncTransaction); } return *mSyncStore; } bool SourceWriteBack::canReplay(const QByteArray &type, const QByteArray &key, const QByteArray &value) { Sink::EntityBuffer buffer(value); const Sink::Entity &entity = buffer.entity(); const auto metadataBuffer = Sink::EntityBuffer::readBuffer(entity.metadata()); Q_ASSERT(metadataBuffer); if (!metadataBuffer->replayToSource()) { SinkTrace() << "Change is coming from the source"; } return metadataBuffer->replayToSource(); } KAsync::Job SourceWriteBack::replay(const QByteArray &type, const QByteArray &key, const QByteArray &value) { SinkTrace() << "Replaying" << type << key; Sink::EntityBuffer buffer(value); const Sink::Entity &entity = buffer.entity(); const auto metadataBuffer = Sink::EntityBuffer::readBuffer(entity.metadata()); Q_ASSERT(metadataBuffer); Q_ASSERT(!mSyncStore); Q_ASSERT(!mSyncTransaction); mEntityStore->startTransaction(Storage::DataStore::ReadOnly); mSyncTransaction = mSyncStorage.createTransaction(Sink::Storage::DataStore::ReadWrite); // const qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation; const auto uid = Sink::Storage::DataStore::uidFromKey(key); const auto modifiedProperties = metadataBuffer->modifiedProperties() ? BufferUtils::fromVector(*metadataBuffer->modifiedProperties()) : QByteArrayList(); QByteArray oldRemoteId; if (operation != Sink::Operation_Creation) { oldRemoteId = syncStore().resolveLocalId(type, uid); if (oldRemoteId.isEmpty()) { SinkWarning() << "Couldn't find the remote id for: " << type << uid; return KAsync::error(1, "Couldn't find the remote id."); } } SinkTrace() << "Replaying " << key << type << uid << oldRemoteId; KAsync::Job job = KAsync::null(); if (type == ENTITY_TYPE_FOLDER) { auto folder = store().readEntity(key); job = replay(folder, operation, oldRemoteId, modifiedProperties); } else if (type == ENTITY_TYPE_MAIL) { auto mail = store().readEntity(key); job = replay(mail, operation, oldRemoteId, modifiedProperties); } return job.syncThen([this, operation, type, uid, oldRemoteId](const QByteArray &remoteId) { if (operation == Sink::Operation_Creation) { SinkTrace() << "Replayed creation with remote id: " << remoteId; if (remoteId.isEmpty()) { SinkWarning() << "Returned an empty remoteId from the creation"; } else { syncStore().recordRemoteId(type, uid, remoteId); } } else if (operation == Sink::Operation_Modification) { SinkTrace() << "Replayed modification with remote id: " << remoteId; if (remoteId.isEmpty()) { SinkWarning() << "Returned an empty remoteId from the creation"; } else { syncStore().updateRemoteId(type, uid, remoteId); } } else if (operation == Sink::Operation_Removal) { SinkTrace() << "Replayed removal with remote id: " << oldRemoteId; syncStore().removeRemoteId(type, uid, oldRemoteId); } else { SinkError() << "Unkown operation" << operation; } }) .syncThen([this](const KAsync::Error &error) { if (error) { SinkWarning() << "Failed to replay change: " << error.errorMessage; } mSyncStore.clear(); mSyncTransaction.commit(); mEntityStore->abortTransaction(); }); } KAsync::Job SourceWriteBack::replay(const ApplicationDomain::Mail &, Sink::Operation, const QByteArray &, const QList &) { return KAsync::null(); } KAsync::Job SourceWriteBack::replay(const ApplicationDomain::Folder &, Sink::Operation, const QByteArray &, const QList &) { return KAsync::null(); }