diff options
Diffstat (limited to 'dummyresource')
-rw-r--r-- | dummyresource/domainadaptor.cpp | 135 | ||||
-rw-r--r-- | dummyresource/domainadaptor.h | 6 | ||||
-rw-r--r-- | dummyresource/facade.cpp | 89 | ||||
-rw-r--r-- | dummyresource/facade.h | 23 | ||||
-rw-r--r-- | dummyresource/resourcefactory.cpp | 48 |
5 files changed, 78 insertions, 223 deletions
diff --git a/dummyresource/domainadaptor.cpp b/dummyresource/domainadaptor.cpp index 2182f9a..fa00bbc 100644 --- a/dummyresource/domainadaptor.cpp +++ b/dummyresource/domainadaptor.cpp | |||
@@ -9,142 +9,55 @@ | |||
9 | #include "entity_generated.h" | 9 | #include "entity_generated.h" |
10 | #include "metadata_generated.h" | 10 | #include "metadata_generated.h" |
11 | #include "domainadaptor.h" | 11 | #include "domainadaptor.h" |
12 | #include "log.h" | ||
12 | #include <common/entitybuffer.h> | 13 | #include <common/entitybuffer.h> |
13 | 14 | ||
14 | using namespace DummyCalendar; | 15 | using namespace DummyCalendar; |
15 | using namespace flatbuffers; | 16 | using namespace flatbuffers; |
16 | 17 | ||
17 | using namespace DummyCalendar; | ||
18 | using namespace flatbuffers; | ||
19 | |||
20 | //This will become a generic implementation that simply takes the resource buffer and local buffer pointer | ||
21 | class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor | ||
22 | { | ||
23 | public: | ||
24 | DummyEventAdaptor() | ||
25 | : BufferAdaptor() | ||
26 | { | ||
27 | |||
28 | } | ||
29 | |||
30 | void setProperty(const QString &key, const QVariant &value) | ||
31 | { | ||
32 | if (mResourceMapper && mResourceMapper->mWriteAccessors.contains(key)) { | ||
33 | // mResourceMapper->setProperty(key, value, mResourceBuffer); | ||
34 | } else { | ||
35 | // mLocalMapper.; | ||
36 | } | ||
37 | } | ||
38 | 18 | ||
39 | virtual QVariant getProperty(const QString &key) const | ||
40 | { | ||
41 | if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) { | ||
42 | return mResourceMapper->getProperty(key, mResourceBuffer); | ||
43 | } else if (mLocalBuffer && mLocalMapper->mReadAccessors.contains(key)) { | ||
44 | return mLocalMapper->getProperty(key, mLocalBuffer); | ||
45 | } | ||
46 | qWarning() << "no mapping available for key " << key; | ||
47 | return QVariant(); | ||
48 | } | ||
49 | |||
50 | virtual QStringList availableProperties() const | ||
51 | { | ||
52 | QStringList props; | ||
53 | props << mResourceMapper->mReadAccessors.keys(); | ||
54 | props << mLocalMapper->mReadAccessors.keys(); | ||
55 | return props; | ||
56 | } | ||
57 | |||
58 | Akonadi2::Domain::Buffer::Event const *mLocalBuffer; | ||
59 | DummyEvent const *mResourceBuffer; | ||
60 | |||
61 | QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> > mLocalMapper; | ||
62 | QSharedPointer<PropertyMapper<DummyEvent> > mResourceMapper; | ||
63 | }; | ||
64 | 19 | ||
65 | 20 | ||
66 | DummyEventAdaptorFactory::DummyEventAdaptorFactory() | 21 | DummyEventAdaptorFactory::DummyEventAdaptorFactory() |
67 | : DomainTypeAdaptorFactory() | 22 | : DomainTypeAdaptorFactory() |
68 | { | 23 | { |
69 | mResourceMapper = QSharedPointer<PropertyMapper<DummyEvent> >::create(); | 24 | //TODO turn this into initializeReadPropertyMapper as well? |
70 | mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { | 25 | mResourceMapper->addMapping("summary", [](DummyEvent const *buffer) -> QVariant { |
71 | if (buffer->summary()) { | ||
72 | return QString::fromStdString(buffer->summary()->c_str()); | ||
73 | } | ||
74 | return QVariant(); | ||
75 | }); | ||
76 | mLocalMapper = QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> >::create(); | ||
77 | mLocalMapper->mReadAccessors.insert("summary", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant { | ||
78 | if (buffer->summary()) { | 26 | if (buffer->summary()) { |
79 | return QString::fromStdString(buffer->summary()->c_str()); | 27 | return QString::fromStdString(buffer->summary()->c_str()); |
80 | } | 28 | } |
81 | return QVariant(); | 29 | return QVariant(); |
82 | }); | 30 | }); |
83 | mLocalMapper->mReadAccessors.insert("uid", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant { | ||
84 | if (buffer->uid()) { | ||
85 | return QString::fromStdString(buffer->uid()->c_str()); | ||
86 | } | ||
87 | return QVariant(); | ||
88 | }); | ||
89 | 31 | ||
32 | mResourceWriteMapper->addMapping("summary", [](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(DummyEventBuilder &)> { | ||
33 | auto offset = extractProperty<QString>(value, fbb); | ||
34 | return [offset](DummyEventBuilder &builder) { builder.add_summary(offset); }; | ||
35 | }); | ||
90 | } | 36 | } |
91 | 37 | ||
92 | //TODO pass EntityBuffer instead? | 38 | |
93 | QSharedPointer<Akonadi2::Domain::BufferAdaptor> DummyEventAdaptorFactory::createAdaptor(const Akonadi2::Entity &entity) | 39 | void DummyEventAdaptorFactory::createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb) |
94 | { | 40 | { |
95 | DummyEvent const *resourceBuffer = 0; | 41 | flatbuffers::FlatBufferBuilder localFbb; |
96 | if (auto resourceData = entity.resource()) { | 42 | if (mLocalWriteMapper) { |
97 | flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size()); | 43 | auto pos = createBufferPart<Akonadi2::ApplicationDomain::Buffer::EventBuilder, Akonadi2::ApplicationDomain::Buffer::Event>(event, localFbb, *mLocalWriteMapper); |
98 | if (VerifyDummyEventBuffer(verifyer)) { | 44 | Akonadi2::ApplicationDomain::Buffer::FinishEventBuffer(localFbb, pos); |
99 | resourceBuffer = GetDummyEvent(resourceData->Data()); | 45 | flatbuffers::Verifier verifier(localFbb.GetBufferPointer(), localFbb.GetSize()); |
46 | if (!verifier.VerifyBuffer<Akonadi2::ApplicationDomain::Buffer::Event>()) { | ||
47 | Warning() << "Created invalid local buffer"; | ||
100 | } | 48 | } |
101 | } | 49 | } |
102 | 50 | ||
103 | // Akonadi2::Metadata const *metadataBuffer = 0; | 51 | flatbuffers::FlatBufferBuilder resFbb; |
104 | // if (auto metadataData = entity.metadata()) { | 52 | if (mResourceWriteMapper) { |
105 | // flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); | 53 | auto pos = createBufferPart<DummyEventBuilder, DummyEvent>(event, resFbb, *mResourceWriteMapper); |
106 | // if (Akonadi2::VerifyMetadataBuffer(verifyer)) { | 54 | DummyCalendar::FinishDummyEventBuffer(resFbb, pos); |
107 | // metadataBuffer = Akonadi2::GetMetadata(metadataData->Data()); | 55 | flatbuffers::Verifier verifier(resFbb.GetBufferPointer(), resFbb.GetSize()); |
108 | // } | 56 | if (!verifier.VerifyBuffer<DummyEvent>()) { |
109 | // } | 57 | Warning() << "Created invalid resource buffer"; |
110 | |||
111 | Akonadi2::Domain::Buffer::Event const *localBuffer = 0; | ||
112 | if (auto localData = entity.local()) { | ||
113 | flatbuffers::Verifier verifyer(localData->Data(), localData->size()); | ||
114 | if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { | ||
115 | localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData->Data()); | ||
116 | } | 58 | } |
117 | } | 59 | } |
118 | 60 | ||
119 | auto adaptor = QSharedPointer<DummyEventAdaptor>::create(); | 61 | Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, 0, 0, resFbb.GetBufferPointer(), resFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); |
120 | adaptor->mLocalBuffer = localBuffer; | ||
121 | adaptor->mLocalMapper = mLocalMapper; | ||
122 | adaptor->mResourceBuffer = resourceBuffer; | ||
123 | adaptor->mResourceMapper = mResourceMapper; | ||
124 | return adaptor; | ||
125 | } | ||
126 | |||
127 | void DummyEventAdaptorFactory::createBuffer(const Akonadi2::Domain::Event &event, flatbuffers::FlatBufferBuilder &fbb) | ||
128 | { | ||
129 | flatbuffers::FlatBufferBuilder eventFbb; | ||
130 | eventFbb.Clear(); | ||
131 | { | ||
132 | auto summary = eventFbb.CreateString(event.getProperty("summary").toString().toStdString()); | ||
133 | DummyCalendar::DummyEventBuilder eventBuilder(eventFbb); | ||
134 | eventBuilder.add_summary(summary); | ||
135 | auto eventLocation = eventBuilder.Finish(); | ||
136 | DummyCalendar::FinishDummyEventBuffer(eventFbb, eventLocation); | ||
137 | } | ||
138 | |||
139 | flatbuffers::FlatBufferBuilder localFbb; | ||
140 | { | ||
141 | auto uid = localFbb.CreateString(event.getProperty("uid").toString().toStdString()); | ||
142 | auto localBuilder = Akonadi2::Domain::Buffer::EventBuilder(localFbb); | ||
143 | localBuilder.add_uid(uid); | ||
144 | auto location = localBuilder.Finish(); | ||
145 | Akonadi2::Domain::Buffer::FinishEventBuffer(localFbb, location); | ||
146 | } | ||
147 | |||
148 | Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); | ||
149 | } | 62 | } |
150 | 63 | ||
diff --git a/dummyresource/domainadaptor.h b/dummyresource/domainadaptor.h index 9474176..9d351e7 100644 --- a/dummyresource/domainadaptor.h +++ b/dummyresource/domainadaptor.h | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | #pragma once | 1 | #pragma once |
3 | 2 | ||
4 | #include "common/domainadaptor.h" | 3 | #include "common/domainadaptor.h" |
@@ -6,11 +5,10 @@ | |||
6 | #include "dummycalendar_generated.h" | 5 | #include "dummycalendar_generated.h" |
7 | #include "entity_generated.h" | 6 | #include "entity_generated.h" |
8 | 7 | ||
9 | class DummyEventAdaptorFactory : public DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent> | 8 | class DummyEventAdaptorFactory : public DomainTypeAdaptorFactory<Akonadi2::ApplicationDomain::Event, Akonadi2::ApplicationDomain::Buffer::Event, DummyCalendar::DummyEvent, Akonadi2::ApplicationDomain::Buffer::EventBuilder, DummyCalendar::DummyEventBuilder> |
10 | { | 9 | { |
11 | public: | 10 | public: |
12 | DummyEventAdaptorFactory(); | 11 | DummyEventAdaptorFactory(); |
13 | virtual ~DummyEventAdaptorFactory() {}; | 12 | virtual ~DummyEventAdaptorFactory() {}; |
14 | virtual QSharedPointer<Akonadi2::Domain::BufferAdaptor> createAdaptor(const Akonadi2::Entity &entity); | 13 | virtual void createBuffer(const Akonadi2::ApplicationDomain::Event &event, flatbuffers::FlatBufferBuilder &fbb); |
15 | virtual void createBuffer(const Akonadi2::Domain::Event &event, flatbuffers::FlatBufferBuilder &fbb); | ||
16 | }; | 14 | }; |
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index 949b4c4..1477fcf 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp | |||
@@ -28,7 +28,6 @@ | |||
28 | #include "event_generated.h" | 28 | #include "event_generated.h" |
29 | #include "entity_generated.h" | 29 | #include "entity_generated.h" |
30 | #include "metadata_generated.h" | 30 | #include "metadata_generated.h" |
31 | #include "createentity_generated.h" | ||
32 | #include "domainadaptor.h" | 31 | #include "domainadaptor.h" |
33 | #include <common/entitybuffer.h> | 32 | #include <common/entitybuffer.h> |
34 | #include <common/index.h> | 33 | #include <common/index.h> |
@@ -37,9 +36,9 @@ | |||
37 | using namespace DummyCalendar; | 36 | using namespace DummyCalendar; |
38 | using namespace flatbuffers; | 37 | using namespace flatbuffers; |
39 | 38 | ||
39 | |||
40 | DummyResourceFacade::DummyResourceFacade() | 40 | DummyResourceFacade::DummyResourceFacade() |
41 | : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), | 41 | : Akonadi2::GenericFacade<Akonadi2::ApplicationDomain::Event>("org.kde.dummy"), |
42 | mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")), | ||
43 | mFactory(new DummyEventAdaptorFactory) | 42 | mFactory(new DummyEventAdaptorFactory) |
44 | { | 43 | { |
45 | } | 44 | } |
@@ -48,38 +47,30 @@ DummyResourceFacade::~DummyResourceFacade() | |||
48 | { | 47 | { |
49 | } | 48 | } |
50 | 49 | ||
51 | Async::Job<void> DummyResourceFacade::create(const Akonadi2::Domain::Event &domainObject) | 50 | Async::Job<void> DummyResourceFacade::create(const Akonadi2::ApplicationDomain::Event &domainObject) |
52 | { | 51 | { |
53 | flatbuffers::FlatBufferBuilder entityFbb; | 52 | flatbuffers::FlatBufferBuilder entityFbb; |
54 | mFactory->createBuffer(domainObject, entityFbb); | 53 | mFactory->createBuffer(domainObject, entityFbb); |
55 | 54 | return sendCreateCommand("event", QByteArray::fromRawData(reinterpret_cast<const char*>(entityFbb.GetBufferPointer()), entityFbb.GetSize())); | |
56 | flatbuffers::FlatBufferBuilder fbb; | ||
57 | //This is the resource buffer type and not the domain type | ||
58 | auto type = fbb.CreateString("event"); | ||
59 | auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
60 | auto location = Akonadi2::Commands::CreateCreateEntity(fbb, type, delta); | ||
61 | Akonadi2::Commands::FinishCreateEntityBuffer(fbb, location); | ||
62 | mResourceAccess->open(); | ||
63 | return mResourceAccess->sendCommand(Akonadi2::Commands::CreateEntityCommand, fbb); | ||
64 | } | 55 | } |
65 | 56 | ||
66 | Async::Job<void> DummyResourceFacade::modify(const Akonadi2::Domain::Event &domainObject) | 57 | Async::Job<void> DummyResourceFacade::modify(const Akonadi2::ApplicationDomain::Event &domainObject) |
67 | { | 58 | { |
68 | //Create message buffer and send to resource | 59 | //Create message buffer and send to resource |
69 | return Async::null<void>(); | 60 | return Async::null<void>(); |
70 | } | 61 | } |
71 | 62 | ||
72 | Async::Job<void> DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject) | 63 | Async::Job<void> DummyResourceFacade::remove(const Akonadi2::ApplicationDomain::Event &domainObject) |
73 | { | 64 | { |
74 | //Create message buffer and send to resource | 65 | //Create message buffer and send to resource |
75 | return Async::null<void>(); | 66 | return Async::null<void>(); |
76 | } | 67 | } |
77 | 68 | ||
78 | static std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> prepareQuery(const Akonadi2::Query &query) | 69 | static std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> prepareQuery(const Akonadi2::Query &query) |
79 | { | 70 | { |
80 | //Compose some functions to make query matching fast. | 71 | //Compose some functions to make query matching fast. |
81 | //This way we can process the query once, and convert all values into something that can be compared quickly | 72 | //This way we can process the query once, and convert all values into something that can be compared quickly |
82 | std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery; | 73 | std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> preparedQuery; |
83 | if (!query.ids.isEmpty()) { | 74 | if (!query.ids.isEmpty()) { |
84 | //Match by id | 75 | //Match by id |
85 | //TODO: for id's a direct lookup would be way faster | 76 | //TODO: for id's a direct lookup would be way faster |
@@ -90,7 +81,7 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer, Akon | |||
90 | for (const auto &id : query.ids) { | 81 | for (const auto &id : query.ids) { |
91 | ids << id.toStdString(); | 82 | ids << id.toStdString(); |
92 | } | 83 | } |
93 | preparedQuery = [ids](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) { | 84 | preparedQuery = [ids](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { |
94 | if (ids.contains(key)) { | 85 | if (ids.contains(key)) { |
95 | return true; | 86 | return true; |
96 | } | 87 | } |
@@ -99,7 +90,7 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer, Akon | |||
99 | } else if (!query.propertyFilter.isEmpty()) { | 90 | } else if (!query.propertyFilter.isEmpty()) { |
100 | if (query.propertyFilter.contains("uid")) { | 91 | if (query.propertyFilter.contains("uid")) { |
101 | const QByteArray uid = query.propertyFilter.value("uid").toByteArray(); | 92 | const QByteArray uid = query.propertyFilter.value("uid").toByteArray(); |
102 | preparedQuery = [uid](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) { | 93 | preparedQuery = [uid](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { |
103 | if (local && local->uid() && (QByteArray::fromRawData(local->uid()->c_str(), local->uid()->size()) == uid)) { | 94 | if (local && local->uid() && (QByteArray::fromRawData(local->uid()->c_str(), local->uid()->size()) == uid)) { |
104 | return true; | 95 | return true; |
105 | } | 96 | } |
@@ -108,32 +99,14 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer, Akon | |||
108 | } | 99 | } |
109 | } else { | 100 | } else { |
110 | //Match everything | 101 | //Match everything |
111 | preparedQuery = [](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) { | 102 | preparedQuery = [](const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local) { |
112 | return true; | 103 | return true; |
113 | }; | 104 | }; |
114 | } | 105 | } |
115 | return preparedQuery; | 106 | return preparedQuery; |
116 | } | 107 | } |
117 | 108 | ||
118 | Async::Job<void> DummyResourceFacade::synchronizeResource(bool sync, bool processAll) | 109 | void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)> preparedQuery) |
119 | { | ||
120 | //TODO check if a sync is necessary | ||
121 | //TODO Only sync what was requested | ||
122 | //TODO timeout | ||
123 | |||
124 | if (sync || processAll) { | ||
125 | return Async::start<void>([=](Async::Future<void> &future) { | ||
126 | mResourceAccess->open(); | ||
127 | mResourceAccess->synchronizeResource(sync, processAll).then<void>([&future](Async::Future<void> &f) { | ||
128 | future.setFinished(); | ||
129 | f.setFinished(); | ||
130 | }).exec(); | ||
131 | }); | ||
132 | } | ||
133 | return Async::null<void>(); | ||
134 | } | ||
135 | |||
136 | void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery) | ||
137 | { | 110 | { |
138 | storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { | 111 | storage->scan(key, [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { |
139 | 112 | ||
@@ -145,31 +118,11 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c | |||
145 | //Extract buffers | 118 | //Extract buffers |
146 | Akonadi2::EntityBuffer buffer(dataValue, dataSize); | 119 | Akonadi2::EntityBuffer buffer(dataValue, dataSize); |
147 | 120 | ||
148 | DummyEvent const *resourceBuffer = 0; | 121 | const auto resourceBuffer = Akonadi2::EntityBuffer::readBuffer<DummyEvent>(buffer.entity().resource()); |
149 | if (auto resourceData = buffer.entity().resource()) { | 122 | const auto localBuffer = Akonadi2::EntityBuffer::readBuffer<Akonadi2::ApplicationDomain::Buffer::Event>(buffer.entity().local()); |
150 | flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size()); | 123 | const auto metadataBuffer = Akonadi2::EntityBuffer::readBuffer<Akonadi2::Metadata>(buffer.entity().metadata()); |
151 | if (VerifyDummyEventBuffer(verifyer)) { | ||
152 | resourceBuffer = GetDummyEvent(resourceData->Data()); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | Akonadi2::Domain::Buffer::Event const *localBuffer = 0; | ||
157 | if (auto localData = buffer.entity().local()) { | ||
158 | flatbuffers::Verifier verifyer(localData->Data(), localData->size()); | ||
159 | if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { | ||
160 | localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData->Data()); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | Akonadi2::Metadata const *metadataBuffer = 0; | ||
165 | if (auto metadataData = buffer.entity().metadata()) { | ||
166 | flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); | ||
167 | if (Akonadi2::VerifyMetadataBuffer(verifyer)) { | ||
168 | metadataBuffer = Akonadi2::GetMetadata(metadataData->Data()); | ||
169 | } | ||
170 | } | ||
171 | 124 | ||
172 | if (!resourceBuffer || !metadataBuffer) { | 125 | if ((!resourceBuffer && !localBuffer) || !metadataBuffer) { |
173 | qWarning() << "invalid buffer " << QByteArray::fromRawData(static_cast<char*>(keyValue), keySize); | 126 | qWarning() << "invalid buffer " << QByteArray::fromRawData(static_cast<char*>(keyValue), keySize); |
174 | return true; | 127 | return true; |
175 | } | 128 | } |
@@ -182,8 +135,9 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c | |||
182 | //Not i.e. for tags that are stored as flags in each entity of an imap store. | 135 | //Not i.e. for tags that are stored as flags in each entity of an imap store. |
183 | auto adaptor = mFactory->createAdaptor(buffer.entity()); | 136 | auto adaptor = mFactory->createAdaptor(buffer.entity()); |
184 | //TODO only copy requested properties | 137 | //TODO only copy requested properties |
185 | auto memoryAdaptor = QSharedPointer<Akonadi2::Domain::MemoryBufferAdaptor>::create(*adaptor); | 138 | auto memoryAdaptor = QSharedPointer<Akonadi2::ApplicationDomain::MemoryBufferAdaptor>::create(*adaptor); |
186 | auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor); | 139 | // here we could copy additional properties that don't have a 1:1 mapping, such as separately stored tags. |
140 | auto event = QSharedPointer<Akonadi2::ApplicationDomain::Event>::create("org.kde.dummy", QByteArray::fromRawData(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor); | ||
187 | resultCallback(event); | 141 | resultCallback(event); |
188 | } | 142 | } |
189 | return true; | 143 | return true; |
@@ -193,7 +147,7 @@ void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, c | |||
193 | }); | 147 | }); |
194 | } | 148 | } |
195 | 149 | ||
196 | Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) | 150 | Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback) |
197 | { | 151 | { |
198 | return synchronizeResource(query.syncOnDemand, query.processAll).then<void>([=](Async::Future<void> &future) { | 152 | return synchronizeResource(query.syncOnDemand, query.processAll).then<void>([=](Async::Future<void> &future) { |
199 | //Now that the sync is complete we can execute the query | 153 | //Now that the sync is complete we can execute the query |
@@ -201,6 +155,9 @@ Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const s | |||
201 | 155 | ||
202 | auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy"); | 156 | auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy"); |
203 | 157 | ||
158 | //TODO use transaction over full query and record store revision. We'll need it to update the query. | ||
159 | |||
160 | //Index lookups | ||
204 | QVector<QByteArray> keys; | 161 | QVector<QByteArray> keys; |
205 | if (query.propertyFilter.contains("uid")) { | 162 | if (query.propertyFilter.contains("uid")) { |
206 | static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly); | 163 | static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly); |
diff --git a/dummyresource/facade.h b/dummyresource/facade.h index 1f69161..37ed81d 100644 --- a/dummyresource/facade.h +++ b/dummyresource/facade.h | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #pragma once | 20 | #pragma once |
21 | 21 | ||
22 | #include "common/facade.h" | ||
23 | |||
22 | #include "common/clientapi.h" | 24 | #include "common/clientapi.h" |
23 | #include "common/storage.h" | 25 | #include "common/storage.h" |
24 | #include "resourcefactory.h" | 26 | #include "resourcefactory.h" |
@@ -27,24 +29,17 @@ | |||
27 | #include "dummycalendar_generated.h" | 29 | #include "dummycalendar_generated.h" |
28 | #include "common/domainadaptor.h" | 30 | #include "common/domainadaptor.h" |
29 | 31 | ||
30 | namespace Akonadi2 { | 32 | class DummyResourceFacade : public Akonadi2::GenericFacade<Akonadi2::ApplicationDomain::Event> |
31 | class ResourceAccess; | ||
32 | } | ||
33 | |||
34 | |||
35 | class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event> | ||
36 | { | 33 | { |
37 | public: | 34 | public: |
38 | DummyResourceFacade(); | 35 | DummyResourceFacade(); |
39 | virtual ~DummyResourceFacade(); | 36 | virtual ~DummyResourceFacade(); |
40 | virtual Async::Job<void> create(const Akonadi2::Domain::Event &domainObject); | 37 | virtual Async::Job<void> create(const Akonadi2::ApplicationDomain::Event &domainObject); |
41 | virtual Async::Job<void> modify(const Akonadi2::Domain::Event &domainObject); | 38 | virtual Async::Job<void> modify(const Akonadi2::ApplicationDomain::Event &domainObject); |
42 | virtual Async::Job<void> remove(const Akonadi2::Domain::Event &domainObject); | 39 | virtual Async::Job<void> remove(const Akonadi2::ApplicationDomain::Event &domainObject); |
43 | virtual Async::Job<void> load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback); | 40 | virtual Async::Job<void> load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback); |
44 | 41 | ||
45 | private: | 42 | private: |
46 | void readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyCalendar::DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)>); | 43 | void readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyCalendar::DummyEvent const *buffer, Akonadi2::ApplicationDomain::Buffer::Event const *local)>); |
47 | Async::Job<void> synchronizeResource(bool sync, bool processAll); | 44 | QSharedPointer<DomainTypeAdaptorFactory<Akonadi2::ApplicationDomain::Event, Akonadi2::ApplicationDomain::Buffer::Event, DummyCalendar::DummyEvent, Akonadi2::ApplicationDomain::Buffer::EventBuilder, DummyCalendar::DummyEventBuilder> > mFactory; |
48 | QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess; | ||
49 | QSharedPointer<DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent> > mFactory; | ||
50 | }; | 45 | }; |
diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index dda34ef..8f0a2bd 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp | |||
@@ -191,7 +191,7 @@ private slots: | |||
191 | return; | 191 | return; |
192 | } | 192 | } |
193 | auto queuedCommand = Akonadi2::GetQueuedCommand(ptr); | 193 | auto queuedCommand = Akonadi2::GetQueuedCommand(ptr); |
194 | qDebug() << "Dequeued: " << queuedCommand->commandId(); | 194 | Trace() << "Dequeued: " << queuedCommand->commandId(); |
195 | //TODO JOBAPI: job lifetime management | 195 | //TODO JOBAPI: job lifetime management |
196 | //Right now we're just leaking jobs. In this case we'd like jobs that are heap allocated and delete | 196 | //Right now we're just leaking jobs. In this case we'd like jobs that are heap allocated and delete |
197 | //themselves once done. In other cases we'd like jobs that only live as long as their handle though. | 197 | //themselves once done. In other cases we'd like jobs that only live as long as their handle though. |
@@ -256,29 +256,18 @@ void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline) | |||
256 | //Eventually the order should be self configuring, for now it's hardcoded. | 256 | //Eventually the order should be self configuring, for now it's hardcoded. |
257 | auto eventIndexer = new SimpleProcessor("summaryprocessor", [eventFactory](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity) { | 257 | auto eventIndexer = new SimpleProcessor("summaryprocessor", [eventFactory](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity) { |
258 | auto adaptor = eventFactory->createAdaptor(entity); | 258 | auto adaptor = eventFactory->createAdaptor(entity); |
259 | // qDebug() << "Summary preprocessor: " << adaptor->getProperty("summary").toString(); | 259 | // Log() << "Summary preprocessor: " << adaptor->getProperty("summary").toString(); |
260 | }); | 260 | }); |
261 | 261 | ||
262 | auto uidIndexer = new SimpleProcessor("uidIndexer", [eventFactory](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity) { | 262 | auto uidIndexer = new SimpleProcessor("uidIndexer", [eventFactory](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity) { |
263 | static Index uidIndex(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/akonadi2/storage", "org.kde.dummy.index.uid", Akonadi2::Storage::ReadWrite); | 263 | static Index uidIndex(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/akonadi2/storage", "org.kde.dummy.index.uid", Akonadi2::Storage::ReadWrite); |
264 | 264 | ||
265 | //TODO: Benchmark if this is performance wise acceptable, or if we have to access the buffer directly | ||
265 | auto adaptor = eventFactory->createAdaptor(entity); | 266 | auto adaptor = eventFactory->createAdaptor(entity); |
266 | const auto uid = adaptor->getProperty("uid"); | 267 | const auto uid = adaptor->getProperty("uid"); |
267 | if (uid.isValid()) { | 268 | if (uid.isValid()) { |
268 | uidIndex.add(uid.toByteArray(), state.key()); | 269 | uidIndex.add(uid.toByteArray(), state.key()); |
269 | } | 270 | } |
270 | |||
271 | //TODO would this be worthwhile for performance reasons? | ||
272 | // flatbuffers::Verifier verifyer(entity.local()->Data(), entity.local()->size()); | ||
273 | // if (!Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { | ||
274 | // qWarning() << "invalid local buffer"; | ||
275 | // return; | ||
276 | // } | ||
277 | // auto localEvent = Akonadi2::Domain::Buffer::GetEvent(entity.local()->Data()); | ||
278 | // if (localEvent && localEvent->uid()) { | ||
279 | // qDebug() << "got uid: " << QByteArray::fromRawData(reinterpret_cast<const char *>(localEvent->uid()->Data()), localEvent->uid()->size()); | ||
280 | // uidIndex.add(QByteArray::fromRawData(reinterpret_cast<const char *>(localEvent->uid()->Data()), localEvent->uid()->size()), state.key()); | ||
281 | // } | ||
282 | }); | 271 | }); |
283 | 272 | ||
284 | //event is the entitytype and not the domain type | 273 | //event is the entitytype and not the domain type |
@@ -289,7 +278,7 @@ void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline) | |||
289 | 278 | ||
290 | void DummyResource::onProcessorError(int errorCode, const QString &errorMessage) | 279 | void DummyResource::onProcessorError(int errorCode, const QString &errorMessage) |
291 | { | 280 | { |
292 | qWarning() << "Received error from Processor: " << errorCode << errorMessage; | 281 | Warning() << "Received error from Processor: " << errorCode << errorMessage; |
293 | mError = errorCode; | 282 | mError = errorCode; |
294 | } | 283 | } |
295 | 284 | ||
@@ -325,11 +314,8 @@ void findByRemoteId(QSharedPointer<Akonadi2::Storage> storage, const QString &ri | |||
325 | void DummyResource::enqueueCommand(MessageQueue &mq, int commandId, const QByteArray &data) | 314 | void DummyResource::enqueueCommand(MessageQueue &mq, int commandId, const QByteArray &data) |
326 | { | 315 | { |
327 | m_fbb.Clear(); | 316 | m_fbb.Clear(); |
328 | auto commandData = m_fbb.CreateVector(reinterpret_cast<uint8_t const *>(data.data()), data.size()); | 317 | auto commandData = Akonadi2::EntityBuffer::appendAsVector(m_fbb, data.constData(), data.size()); |
329 | auto builder = Akonadi2::QueuedCommandBuilder(m_fbb); | 318 | auto buffer = Akonadi2::CreateQueuedCommand(m_fbb, commandId, commandData); |
330 | builder.add_commandId(commandId); | ||
331 | builder.add_command(commandData); | ||
332 | auto buffer = builder.Finish(); | ||
333 | Akonadi2::FinishQueuedCommandBuffer(m_fbb, buffer); | 319 | Akonadi2::FinishQueuedCommandBuffer(m_fbb, buffer); |
334 | mq.enqueue(m_fbb.GetBufferPointer(), m_fbb.GetSize()); | 320 | mq.enqueue(m_fbb.GetBufferPointer(), m_fbb.GetSize()); |
335 | } | 321 | } |
@@ -357,7 +343,7 @@ Async::Job<void> DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeli | |||
357 | auto rid = m_fbb.CreateString(it.key().toStdString().c_str()); | 343 | auto rid = m_fbb.CreateString(it.key().toStdString().c_str()); |
358 | auto description = m_fbb.CreateString(it.key().toStdString().c_str()); | 344 | auto description = m_fbb.CreateString(it.key().toStdString().c_str()); |
359 | static uint8_t rawData[100]; | 345 | static uint8_t rawData[100]; |
360 | auto attachment = m_fbb.CreateVector(rawData, 100); | 346 | auto attachment = Akonadi2::EntityBuffer::appendAsVector(m_fbb, rawData, 100); |
361 | 347 | ||
362 | auto builder = DummyCalendar::DummyEventBuilder(m_fbb); | 348 | auto builder = DummyCalendar::DummyEventBuilder(m_fbb); |
363 | builder.add_summary(summary); | 349 | builder.add_summary(summary); |
@@ -372,7 +358,7 @@ Async::Job<void> DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeli | |||
372 | flatbuffers::FlatBufferBuilder fbb; | 358 | flatbuffers::FlatBufferBuilder fbb; |
373 | //This is the resource type and not the domain type | 359 | //This is the resource type and not the domain type |
374 | auto type = fbb.CreateString("event"); | 360 | auto type = fbb.CreateString("event"); |
375 | auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); | 361 | auto delta = Akonadi2::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); |
376 | auto location = Akonadi2::Commands::CreateCreateEntity(fbb, type, delta); | 362 | auto location = Akonadi2::Commands::CreateCreateEntity(fbb, type, delta); |
377 | Akonadi2::Commands::FinishCreateEntityBuffer(fbb, location); | 363 | Akonadi2::Commands::FinishCreateEntityBuffer(fbb, location); |
378 | 364 | ||
@@ -388,16 +374,22 @@ Async::Job<void> DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeli | |||
388 | 374 | ||
389 | Async::Job<void> DummyResource::processAllMessages() | 375 | Async::Job<void> DummyResource::processAllMessages() |
390 | { | 376 | { |
377 | //We have to wait for all items to be processed to ensure the synced items are available when a query gets executed. | ||
378 | //TODO: report errors while processing sync? | ||
379 | //TODO JOBAPI: A helper that waits for n events and then continues? | ||
391 | return Async::start<void>([this](Async::Future<void> &f) { | 380 | return Async::start<void>([this](Async::Future<void> &f) { |
392 | //We have to wait for all items to be processed to ensure the synced items are available when a query gets executed. | ||
393 | //TODO: report errors while processing sync? | ||
394 | //TODO: also check user-queue? | ||
395 | if (mSynchronizerQueue.isEmpty()) { | 381 | if (mSynchronizerQueue.isEmpty()) { |
396 | qDebug() << "synchronizer queue is empty"; | ||
397 | f.setFinished(); | 382 | f.setFinished(); |
398 | } else { | 383 | } else { |
399 | QObject::connect(&mSynchronizerQueue, &MessageQueue::drained, [&f]() { | 384 | QObject::connect(&mSynchronizerQueue, &MessageQueue::drained, [&f]() { |
400 | qDebug() << "synchronizer queue drained"; | 385 | f.setFinished(); |
386 | }); | ||
387 | } | ||
388 | }).then<void>([this](Async::Future<void> &f) { | ||
389 | if (mUserQueue.isEmpty()) { | ||
390 | f.setFinished(); | ||
391 | } else { | ||
392 | QObject::connect(&mUserQueue, &MessageQueue::drained, [&f]() { | ||
401 | f.setFinished(); | 393 | f.setFinished(); |
402 | }); | 394 | }); |
403 | } | 395 | } |
@@ -425,7 +417,7 @@ Akonadi2::Resource *DummyResourceFactory::createResource() | |||
425 | 417 | ||
426 | void DummyResourceFactory::registerFacades(Akonadi2::FacadeFactory &factory) | 418 | void DummyResourceFactory::registerFacades(Akonadi2::FacadeFactory &factory) |
427 | { | 419 | { |
428 | factory.registerFacade<Akonadi2::Domain::Event, DummyResourceFacade>(PLUGIN_NAME); | 420 | factory.registerFacade<Akonadi2::ApplicationDomain::Event, DummyResourceFacade>(PLUGIN_NAME); |
429 | } | 421 | } |
430 | 422 | ||
431 | #include "resourcefactory.moc" | 423 | #include "resourcefactory.moc" |