summaryrefslogtreecommitdiffstats
path: root/dummyresource
diff options
context:
space:
mode:
Diffstat (limited to 'dummyresource')
-rw-r--r--dummyresource/dummycalendar.fbs1
-rw-r--r--dummyresource/facade.cpp63
-rw-r--r--dummyresource/facade.h9
-rw-r--r--dummyresource/resourcefactory.cpp87
4 files changed, 131 insertions, 29 deletions
diff --git a/dummyresource/dummycalendar.fbs b/dummyresource/dummycalendar.fbs
index 5a217b5..643c9b2 100644
--- a/dummyresource/dummycalendar.fbs
+++ b/dummyresource/dummycalendar.fbs
@@ -6,6 +6,7 @@ table DummyEvent {
6 summary:string; 6 summary:string;
7 description:string; 7 description:string;
8 attachment:[ubyte]; 8 attachment:[ubyte];
9 remoteId:string;
9} 10}
10 11
11root_type DummyEvent; 12root_type DummyEvent;
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp
index 0d47010..c2871bb 100644
--- a/dummyresource/facade.cpp
+++ b/dummyresource/facade.cpp
@@ -23,6 +23,7 @@
23#include <functional> 23#include <functional>
24 24
25#include "common/resourceaccess.h" 25#include "common/resourceaccess.h"
26#include "common/commands.h"
26#include "dummycalendar_generated.h" 27#include "dummycalendar_generated.h"
27 28
28using namespace DummyCalendar; 29using namespace DummyCalendar;
@@ -30,7 +31,7 @@ using namespace flatbuffers;
30 31
31DummyResourceFacade::DummyResourceFacade() 32DummyResourceFacade::DummyResourceFacade()
32 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), 33 : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(),
33 mResourceAccess(/* new ResourceAccess("dummyresource") */) 34 mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy"))
34{ 35{
35 // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged); 36 // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged);
36} 37}
@@ -95,11 +96,8 @@ public:
95 QSharedPointer<Akonadi2::Storage> storage; 96 QSharedPointer<Akonadi2::Storage> storage;
96}; 97};
97 98
98void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) 99static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query)
99{ 100{
100 qDebug() << "load called";
101 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "dummyresource");
102
103 //Compose some functions to make query matching fast. 101 //Compose some functions to make query matching fast.
104 //This way we can process the query once, and convert all values into something that can be compared quickly 102 //This way we can process the query once, and convert all values into something that can be compared quickly
105 std::function<bool(const std::string &key, DummyEvent const *buffer)> preparedQuery; 103 std::function<bool(const std::string &key, DummyEvent const *buffer)> preparedQuery;
@@ -125,21 +123,48 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function
125 return true; 123 return true;
126 }; 124 };
127 } 125 }
126 return preparedQuery;
127}
128 128
129 //Because we have no indexes yet, we always do a full scan 129void DummyResourceFacade::synchronizeResource(const std::function<void()> &continuation)
130 storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { 130{
131 //TODO read second buffer as well 131 //TODO check if a sync is necessary
132 auto eventBuffer = GetDummyEvent(dataValue); 132 //TODO Only sync what was requested
133 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), eventBuffer)) { 133 //TODO timeout
134 //TODO read the revision from the generic portion of the buffer 134 mResourceAccess->open();
135 auto event = QSharedPointer<DummyEventAdaptor>::create("dummyresource", QString::fromUtf8(static_cast<char*>(keyValue), keySize), 0); 135 mResourceAccess->synchronizeResource(continuation);
136 event->buffer = eventBuffer; 136}
137 event->storage = storage; 137
138 resultCallback(event); 138void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, const std::function<void()> &completeCallback)
139 } 139{
140 return true; 140 qDebug() << "load called";
141
142 synchronizeResource([=]() {
143 //Now that the sync is complete we can execute the query
144 const auto preparedQuery = prepareQuery(query);
145
146 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
147
148 qDebug() << "executing query";
149 //We start a transaction explicitly that we'll leave open so the values can be read.
150 //The transaction will be closed automatically once the storage object is destroyed.
151 storage->startTransaction(Akonadi2::Storage::ReadOnly);
152 //Because we have no indexes yet, we always do a full scan
153 storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
154 //TODO read the three buffers
155 qDebug() << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize));
156 auto eventBuffer = GetDummyEvent(dataValue);
157 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), eventBuffer)) {
158 //TODO set proper revision
159 qint64 revision = 0;
160 auto event = QSharedPointer<DummyEventAdaptor>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision);
161 event->buffer = eventBuffer;
162 event->storage = storage;
163 resultCallback(event);
164 }
165 return true;
166 });
167 completeCallback();
141 }); 168 });
142} 169}
143 170
144//TODO call in plugin loader
145// Akonadi2::FacadeFactory::instance().registerFacade<Akonadi2::Domain::Event, DummyResourceFacade>("dummyresource", [facade](){ return new DummyResourceFacade(facade); });
diff --git a/dummyresource/facade.h b/dummyresource/facade.h
index f179c06..c76e62c 100644
--- a/dummyresource/facade.h
+++ b/dummyresource/facade.h
@@ -22,7 +22,9 @@
22#include "common/clientapi.h" 22#include "common/clientapi.h"
23#include "common/storage.h" 23#include "common/storage.h"
24 24
25class ResourceAccess; 25namespace Akonadi2 {
26 class ResourceAccess;
27}
26 28
27class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event> 29class DummyResourceFacade : public Akonadi2::StoreFacade<Akonadi2::Domain::Event>
28{ 30{
@@ -32,8 +34,9 @@ public:
32 virtual void create(const Akonadi2::Domain::Event &domainObject); 34 virtual void create(const Akonadi2::Domain::Event &domainObject);
33 virtual void modify(const Akonadi2::Domain::Event &domainObject); 35 virtual void modify(const Akonadi2::Domain::Event &domainObject);
34 virtual void remove(const Akonadi2::Domain::Event &domainObject); 36 virtual void remove(const Akonadi2::Domain::Event &domainObject);
35 virtual void load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback); 37 virtual void load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, const std::function<void()> &completeCallback);
36 38
37private: 39private:
38 QSharedPointer<ResourceAccess> mResourceAccess; 40 void synchronizeResource(const std::function<void()> &continuation);
41 QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess;
39}; 42};
diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp
index bd85b4f..2c43981 100644
--- a/dummyresource/resourcefactory.cpp
+++ b/dummyresource/resourcefactory.cpp
@@ -20,22 +20,95 @@
20#include "resourcefactory.h" 20#include "resourcefactory.h"
21#include "facade.h" 21#include "facade.h"
22#include "dummycalendar_generated.h" 22#include "dummycalendar_generated.h"
23#include <QUuid>
24
25static std::string createEvent()
26{
27 static const size_t attachmentSize = 1024*2; // 2KB
28 static uint8_t rawData[attachmentSize];
29 static flatbuffers::FlatBufferBuilder fbb;
30 fbb.Clear();
31 {
32 auto summary = fbb.CreateString("summary");
33 auto data = fbb.CreateUninitializedVector<uint8_t>(attachmentSize);
34 DummyCalendar::DummyEventBuilder eventBuilder(fbb);
35 eventBuilder.add_summary(summary);
36 eventBuilder.add_attachment(data);
37 auto eventLocation = eventBuilder.Finish();
38 DummyCalendar::FinishDummyEventBuffer(fbb, eventLocation);
39 memcpy((void*)DummyCalendar::GetDummyEvent(fbb.GetBufferPointer())->attachment()->Data(), rawData, attachmentSize);
40 }
41
42 return std::string(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
43}
44
45QMap<QString, QString> populate()
46{
47 QMap<QString, QString> content;
48 for (int i = 0; i < 2; i++) {
49 auto event = createEvent();
50 content.insert(QString("key%1").arg(i), QString::fromStdString(event));
51 }
52 return content;
53}
54
55static QMap<QString, QString> s_dataSource = populate();
23 56
24DummyResource::DummyResource() 57DummyResource::DummyResource()
25 : Akonadi2::Resource() 58 : Akonadi2::Resource()
26{ 59{
60}
27 61
62void findByRemoteId(QSharedPointer<Akonadi2::Storage> storage, const QString &rid, std::function<void(void *keyValue, int keySize, void *dataValue, int dataSize)> callback)
63{
64 //TODO lookup in rid index instead of doing a full scan
65 const std::string ridString = rid.toStdString();
66 storage->scan("", [&](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
67 auto eventBuffer = DummyCalendar::GetDummyEvent(dataValue);
68 if (std::string(eventBuffer->remoteId()->c_str(), eventBuffer->remoteId()->size()) == ridString) {
69 callback(keyValue, keySize, dataValue, dataSize);
70 }
71 return true;
72 });
28} 73}
29 74
30void DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline) 75void DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline)
31{ 76{
32 // TODO actually populate the storage with new items 77 //TODO use a read-only transaction during the complete sync to sync against a defined revision
33 auto builder = DummyCalendar::DummyEventBuilder(m_fbb); 78
34 builder .add_summary(m_fbb.CreateString("summary summary!")); 79 qDebug() << "synchronize with source";
35 auto buffer = builder.Finish(); 80
36 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); 81 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
37 pipeline->newEntity("fakekey", m_fbb); 82 for (auto it = s_dataSource.constBegin(); it != s_dataSource.constEnd(); it++) {
38 m_fbb.Clear(); 83 bool isNew = true;
84 if (storage->exists()) {
85 findByRemoteId(storage, it.key(), [&](void *keyValue, int keySize, void *dataValue, int dataSize) {
86 isNew = false;
87 });
88 }
89
90 if (isNew) {
91 //TODO: perhaps it would be more convenient to populate the domain types?
92 //Resource specific parts are not accessible that way, but then we would only have to implement the property mapping in one place
93 const QByteArray data = it.value().toUtf8();
94 auto eventBuffer = DummyCalendar::GetDummyEvent(data.data());
95
96 //Map the source format to the buffer format (which happens to be an exact copy here)
97 auto builder = DummyCalendar::DummyEventBuilder(m_fbb);
98 builder.add_summary(m_fbb.CreateString(eventBuffer->summary()->c_str()));
99 auto buffer = builder.Finish();
100 DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer);
101
102 //TODO toRFC4122 would probably be more efficient, but results in non-printable keys.
103 const auto key = QUuid::createUuid().toString().toUtf8();
104 //TODO can we really just start populating the buffer and pass the buffer builder?
105 qDebug() << "new event";
106 pipeline->newEntity(key, m_fbb);
107 } else { //modification
108 //TODO diff and create modification if necessary
109 }
110 }
111 //TODO find items to remove
39} 112}
40 113
41void DummyResource::processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline) 114void DummyResource::processCommand(int commandId, const QByteArray &data, uint size, Akonadi2::Pipeline *pipeline)