From 9b2257d680a5e4fa2fda8cf3302f25054a06710e Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Sun, 28 Dec 2014 14:44:50 +0100 Subject: Buffers wrapped into entity buffer, async command progress tracking. --- dummyresource/facade.cpp | 48 +++++++++++++++++--- dummyresource/resourcefactory.cpp | 94 +++++++++++++++++++++++---------------- dummyresource/resourcefactory.h | 3 +- 3 files changed, 99 insertions(+), 46 deletions(-) (limited to 'dummyresource') diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index 458aba6..d3974e9 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp @@ -26,8 +26,9 @@ #include "common/commands.h" #include "dummycalendar_generated.h" #include "event_generated.h" -#include "entitybuffer_generated.h" +#include "entity_generated.h" #include "metadata_generated.h" +#include using namespace DummyCalendar; using namespace flatbuffers; @@ -199,14 +200,47 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function storage->startTransaction(Akonadi2::Storage::ReadOnly); //Because we have no indexes yet, we always do a full scan storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { - qDebug() << QString::fromStdString(std::string(static_cast(keyValue), keySize)); - auto buffer = Akonadi2::GetEntityBuffer(dataValue); - auto resourceBuffer = GetDummyEvent(buffer->resource()); - auto metadataBuffer = Akonadi2::GetMetadata(buffer->resource()); - auto localBuffer = Akonadi2::Domain::Buffer::GetEvent(buffer->local()); + + //Skip internals + if (QByteArray::fromRawData(static_cast(keyValue), keySize).startsWith("__internal")) { + return true; + } + + //Extract buffers + Akonadi2::EntityBuffer buffer(dataValue, dataSize); + + DummyEvent const *resourceBuffer = 0; + if (auto resourceData = buffer.resourceBuffer()) { + flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size()); + if (VerifyDummyEventBuffer(verifyer)) { + resourceBuffer = GetDummyEvent(resourceData); + } + } + + Akonadi2::Metadata const *metadataBuffer = 0; + if (auto metadataData = buffer.metadataBuffer()) { + flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); + if (Akonadi2::VerifyMetadataBuffer(verifyer)) { + metadataBuffer = Akonadi2::GetMetadata(metadataData); + } + } + + Akonadi2::Domain::Buffer::Event const *localBuffer = 0; + if (auto localData = buffer.localBuffer()) { + flatbuffers::Verifier verifyer(localData->Data(), localData->size()); + if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { + localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData); + } + } + + if (!resourceBuffer || !metadataBuffer) { + qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast(keyValue), keySize)); + return true; + } + //We probably only want to create all buffers after the scan if (preparedQuery && preparedQuery(std::string(static_cast(keyValue), keySize), resourceBuffer)) { - qint64 revision = metadataBuffer->revision(); + qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; auto adaptor = QSharedPointer::create(); adaptor->mLocalBuffer = localBuffer; adaptor->mResourceBuffer = resourceBuffer; diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index 6b93985..c9e4d7a 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp @@ -19,7 +19,9 @@ #include "resourcefactory.h" #include "facade.h" +#include "entitybuffer.h" #include "dummycalendar_generated.h" +#include "metadata_generated.h" #include static std::string createEvent() @@ -64,51 +66,67 @@ void findByRemoteId(QSharedPointer storage, const QString &ri //TODO lookup in rid index instead of doing a full scan const std::string ridString = rid.toStdString(); storage->scan("", [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { - auto eventBuffer = DummyCalendar::GetDummyEvent(dataValue); - if (std::string(eventBuffer->remoteId()->c_str(), eventBuffer->remoteId()->size()) == ridString) { - callback(keyValue, keySize, dataValue, dataSize); + if (QByteArray::fromRawData(static_cast(keyValue), keySize).startsWith("__internal")) { + return true; } + + Akonadi2::EntityBuffer::extractResourceBuffer(dataValue, dataSize, [&](const flatbuffers::Vector *buffer) { + flatbuffers::Verifier verifier(buffer->Data(), buffer->size()); + if (DummyCalendar::VerifyDummyEventBuffer(verifier)) { + DummyCalendar::DummyEvent const *resourceBuffer = DummyCalendar::GetDummyEvent(buffer->Data()); + if (resourceBuffer && resourceBuffer->remoteId()) { + if (std::string(resourceBuffer->remoteId()->c_str(), resourceBuffer->remoteId()->size()) == ridString) { + callback(keyValue, keySize, dataValue, dataSize); + } + } + } + }); return true; }); } -void DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline) +Async::Job DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline) { - //TODO use a read-only transaction during the complete sync to sync against a defined revision - - qDebug() << "synchronize with source"; - - auto storage = QSharedPointer::create(Akonadi2::Store::storageLocation(), "org.kde.dummy"); - for (auto it = s_dataSource.constBegin(); it != s_dataSource.constEnd(); it++) { - bool isNew = true; - if (storage->exists()) { - findByRemoteId(storage, it.key(), [&](void *keyValue, int keySize, void *dataValue, int dataSize) { - isNew = false; - }); - } - - if (isNew) { - //TODO: perhaps it would be more convenient to populate the domain types? - //Resource specific parts are not accessible that way, but then we would only have to implement the property mapping in one place - const QByteArray data = it.value().toUtf8(); - auto eventBuffer = DummyCalendar::GetDummyEvent(data.data()); - - //Map the source format to the buffer format (which happens to be an exact copy here) - auto builder = DummyCalendar::DummyEventBuilder(m_fbb); - builder.add_summary(m_fbb.CreateString(eventBuffer->summary()->c_str())); - auto buffer = builder.Finish(); - DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); - - //TODO toRFC4122 would probably be more efficient, but results in non-printable keys. - const auto key = QUuid::createUuid().toString().toUtf8(); - //TODO can we really just start populating the buffer and pass the buffer builder? - qDebug() << "new event"; - pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); - } else { //modification - //TODO diff and create modification if necessary + return Async::start([this, pipeline](Async::Future &f) { + //TODO use a read-only transaction during the complete sync to sync against a defined revision + auto storage = QSharedPointer::create(Akonadi2::Store::storageLocation(), "org.kde.dummy"); + for (auto it = s_dataSource.constBegin(); it != s_dataSource.constEnd(); it++) { + bool isNew = true; + if (storage->exists()) { + findByRemoteId(storage, it.key(), [&](void *keyValue, int keySize, void *dataValue, int dataSize) { + isNew = false; + }); + } + if (isNew) { + m_fbb.Clear(); + + const QByteArray data = it.value().toUtf8(); + auto eventBuffer = DummyCalendar::GetDummyEvent(data.data()); + + //Map the source format to the buffer format (which happens to be an exact copy here) + auto summary = m_fbb.CreateString(eventBuffer->summary()->c_str()); + auto rid = m_fbb.CreateString(it.key().toStdString().c_str()); + auto description = m_fbb.CreateString(it.key().toStdString().c_str()); + static uint8_t rawData[100]; + auto attachment = m_fbb.CreateVector(rawData, 100); + + auto builder = DummyCalendar::DummyEventBuilder(m_fbb); + builder.add_summary(summary); + builder.add_remoteId(rid); + builder.add_description(description); + builder.add_attachment(attachment); + auto buffer = builder.Finish(); + DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); + //TODO toRFC4122 would probably be more efficient, but results in non-printable keys. + const auto key = QUuid::createUuid().toString().toUtf8(); + pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); + } else { //modification + //TODO diff and create modification if necessary + } } - } - //TODO find items to remove + //TODO find items to remove + f.setFinished(); + }); } void DummyResource::processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline) diff --git a/dummyresource/resourcefactory.h b/dummyresource/resourcefactory.h index 807a654..dba674f 100644 --- a/dummyresource/resourcefactory.h +++ b/dummyresource/resourcefactory.h @@ -20,6 +20,7 @@ #pragma once #include "common/resource.h" +#include "async/src/async.h" #include @@ -30,7 +31,7 @@ class DummyResource : public Akonadi2::Resource { public: DummyResource(); - void synchronizeWithSource(Akonadi2::Pipeline *pipeline); + Async::Job synchronizeWithSource(Akonadi2::Pipeline *pipeline); void processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline); private: -- cgit v1.2.3