1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/*
* Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "facade.h"
#include <QDebug>
#include <functional>
#include "client/resourceaccess.h"
#include "dummycalendar_generated.h"
using namespace DummyCalendar;
using namespace flatbuffers;
DummyResourceFacade::DummyResourceFacade()
: Akonadi2::StoreFacade<Akonadi2::Domain::Event>(),
mResourceAccess(/* new ResourceAccess("dummyresource") */)
{
// connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged);
}
DummyResourceFacade::~DummyResourceFacade()
{
}
void DummyResourceFacade::create(const Akonadi2::Domain::Event &domainObject)
{
//Create message buffer and send to resource
}
void DummyResourceFacade::modify(const Akonadi2::Domain::Event &domainObject)
{
//Create message buffer and send to resource
}
void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject)
{
//Create message buffer and send to resource
}
//Key.value property map using enum or strings with qvariant, or rather typesafe API?
//typesafe is a shitload more work that we can avoid
//
//The Event base implementaiton could take a pointer to a single property mapper,
//and a void pointer to the mmapped region. => event is copyable and stack allocatable and we avoid large amounts of heap allocated objects
//-The mapper should in this case live in the other thread
//-default property mapper implementation can answer "is property X supported?"
//-how do we free/munmap the data if we don't know when no one references it any longer? => no munmap needed, but read transaction to keep pointer alive
//-we could bind the lifetime to the query
//=> perhaps do heap allocate and use smart pointer?
class DummyEventAdaptor : public Akonadi2::Domain::Event
{
public:
DummyEventAdaptor(const QString &resource, const QString &identifier, qint64 revision)
:Akonadi2::Domain::Event(resource, identifier, revision)
{
}
//TODO
// void setProperty(const QString &key, const QVariant &value)
// {
// //Record changes to send to resource?
// //The buffer is readonly
// }
virtual QVariant getProperty(const QString &key) const
{
if (key == "summary") {
//FIXME how do we check availability for on-demand request?
return QString::fromStdString(buffer->summary()->c_str());
}
return QVariant();
}
//Data is read-only
DummyEvent const *buffer;
//Keep query alive so values remain valid
QSharedPointer<Akonadi2::Storage> storage;
};
void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback)
{
qDebug() << "load called";
auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "dummyresource");
//Compose some functions to make query matching fast.
//This way we can process the query once, and convert all values into something that can be compared quickly
std::function<bool(const std::string &key, DummyEvent const *buffer)> preparedQuery;
if (!query.ids.isEmpty()) {
//Match by id
//TODO: for id's a direct lookup would be way faster
//We convert the id's to std::string so we don't have to convert each key during the scan. (This runs only once, and the query will be run for every key)
//Probably a premature optimization, but perhaps a useful technique to be investigated.
QVector<std::string> ids;
for (const auto &id : query.ids) {
ids << id.toStdString();
}
preparedQuery = [ids](const std::string &key, DummyEvent const *buffer) {
if (ids.contains(key)) {
return true;
}
return false;
};
} else {
//Match everything
preparedQuery = [](const std::string &key, DummyEvent const *buffer) {
return true;
};
}
//Because we have no indexes yet, we always do a full scan
storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
//TODO read second buffer as well
auto eventBuffer = GetDummyEvent(dataValue);
if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), eventBuffer)) {
//TODO read the revision from the generic portion of the buffer
auto event = QSharedPointer<DummyEventAdaptor>::create("dummyresource", QString::fromUtf8(static_cast<char*>(keyValue), keySize), 0);
event->buffer = eventBuffer;
event->storage = storage;
resultCallback(event);
}
return true;
});
}
//TODO call in plugin loader
// Akonadi2::FacadeFactory::instance().registerFacade<Akonadi2::Domain::Event, DummyResourceFacade>("dummyresource", [facade](){ return new DummyResourceFacade(facade); });
|