summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2021-06-05 23:10:24 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2021-06-06 21:48:46 +0200
commit6c58f1e095f7dbe1e7e1654c1807a76276a2f3f2 (patch)
treea4e083c6dca3e6567a0d7983c7c316b85316bf4c /src
parentd563500c915de2f0a652513af03f101c99715db3 (diff)
Contact list in shared state
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/contact.cpp153
-rw-r--r--src/contact.h42
-rw-r--r--src/identity.cpp12
-rw-r--r--src/identity.h3
5 files changed, 209 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8f65555..0fd7125 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories(
add_library(erebos
attach
channel
+ contact
frp
identity
message
diff --git a/src/contact.cpp b/src/contact.cpp
new file mode 100644
index 0000000..edc33ea
--- /dev/null
+++ b/src/contact.cpp
@@ -0,0 +1,153 @@
+#include "contact.h"
+
+#include "identity.h"
+
+using namespace erebos;
+
+using std::move;
+
+DEFINE_SHARED_TYPE(List<Contact>,
+ "34fbb61e-6022-405f-b1b3-a5a1abecd25e",
+ &Contact::loadList,
+ [](const List<Contact> & list) {
+ if (list.empty())
+ return vector<Ref>();
+ return list.front().refs();
+ })
+
+
+List<Contact> Contact::prepend(const Storage & st, Identity id, List<Contact> list)
+{
+ auto cd = st.store(ContactData {
+ .prev = list.empty() ? vector<Stored<ContactData>>() : list.front().p->data,
+ .identity = id.data(),
+ .name = nullopt,
+ });
+ return list.push_front(
+ Contact(shared_ptr<Priv>(new Priv {
+ .data = { cd },
+ .identity = move(id),
+ }))
+ );
+}
+
+Identity Contact::identity() const
+{
+ return p->identity;
+}
+
+optional<string> Contact::name() const
+{
+ p->init();
+ return p->name;
+}
+
+bool Contact::operator==(const Contact & other) const
+{
+ return p->data == other.p->data;
+}
+
+bool Contact::operator!=(const Contact & other) const
+{
+ return p->data != other.p->data;
+}
+
+List<Contact> Contact::loadList(const vector<Ref> & refs)
+{
+ vector<Stored<ContactData>> cdata;
+ cdata.reserve(refs.size());
+
+ for (const auto & r : refs)
+ cdata.push_back(Stored<ContactData>::load(r));
+ return Priv::loadList(move(cdata), {});
+}
+
+List<Contact> Contact::Priv::loadList(vector<Stored<ContactData>> && cdata, vector<Identity> && seen)
+{
+ if (cdata.empty())
+ return {};
+
+ filterAncestors(cdata);
+
+ for (size_t i = 0; i < cdata.size(); i++) {
+ auto id = Identity::load(cdata[i]->identity);
+ if (!id)
+ continue;
+
+ bool skip = false;
+ for (const auto & sid : seen) {
+ if (id->sameAs(sid)) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+
+ vector<Stored<ContactData>> next;
+ next.reserve(cdata.size() - i - 1 + cdata[i]->prev.size());
+ for (size_t j = i + 1; j < cdata.size(); j++)
+ next.push_back(cdata[j]);
+ for (const auto & x : cdata[i]->prev)
+ next.push_back(x);
+
+ seen.push_back(*id);
+ auto p = shared_ptr<Priv>(new Priv { .data = move(cdata), .identity = move(*id) });
+ return List(Contact(p), loadList(move(next), move(seen)));
+ }
+
+ return {};
+}
+
+vector<Ref> Contact::refs() const
+{
+ vector<Ref> res;
+ res.reserve(p->data.size());
+ for (const auto & x : p->data)
+ res.push_back(x.ref());
+ return res;
+}
+
+void Contact::Priv::init()
+{
+ std::call_once(initFlag, [this]() {
+ name = identity.name();
+ });
+}
+
+ContactData ContactData::load(const Ref & ref)
+{
+ auto rec = ref->asRecord();
+ if (!rec)
+ return ContactData();
+
+ vector<Stored<ContactData>> prev;
+ for (const auto & x : rec->items("PREV"))
+ if (const auto & p = x.as<ContactData>())
+ prev.push_back(*p);
+
+ vector<Stored<Signed<IdentityData>>> identity;
+ for (const auto & x : rec->items("identity"))
+ if (const auto & i = x.asRef())
+ identity.push_back(*i);
+
+ return ContactData {
+ .prev = std::move(prev),
+ .identity = std::move(identity),
+ .name = rec->item("name").asText(),
+ };
+}
+
+Ref ContactData::store(const Storage & st) const
+{
+ vector<Record::Item> items;
+
+ for (const auto & prev : prev)
+ items.emplace_back("PREV", prev.ref());
+ for (const auto & idt : identity)
+ items.emplace_back("identity", idt);
+ if (name)
+ items.emplace_back("name", *name);
+
+ return st.storeObject(Record(std::move(items)));
+}
diff --git a/src/contact.h b/src/contact.h
new file mode 100644
index 0000000..31deceb
--- /dev/null
+++ b/src/contact.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <erebos/contact.h>
+
+#include <mutex>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace erebos {
+
+using std::optional;
+using std::string;
+using std::vector;
+
+struct ContactData;
+struct IdentityData;
+
+struct Contact::Priv
+{
+ vector<Stored<ContactData>> data;
+ Identity identity;
+
+ void init();
+ std::once_flag initFlag {};
+
+ optional<string> name {};
+
+ static List<Contact> loadList(vector<Stored<ContactData>> &&, vector<Identity> &&);
+};
+
+struct ContactData
+{
+ static ContactData load(const Ref &);
+ Ref store(const Storage &) const;
+
+ vector<Stored<ContactData>> prev;
+ vector<Stored<Signed<IdentityData>>> identity;
+ optional<string> name;
+};
+
+}
diff --git a/src/identity.cpp b/src/identity.cpp
index f55f6dd..0d35122 100644
--- a/src/identity.cpp
+++ b/src/identity.cpp
@@ -6,6 +6,8 @@
#include <set>
#include <stdexcept>
+#include <iostream>
+
using namespace erebos;
using std::async;
@@ -38,6 +40,11 @@ optional<Identity> Identity::load(const vector<Ref> & refs)
for (const auto & ref : refs)
data.push_back(Stored<Signed<IdentityData>>::load(ref));
+ return load(data);
+}
+
+optional<Identity> Identity::load(const vector<Stored<Signed<IdentityData>>> & data)
+{
if (auto ptr = Priv::validate(data))
return Identity(ptr);
return nullopt;
@@ -61,6 +68,11 @@ vector<Ref> Identity::store(const Storage & st) const
return res;
}
+const vector<Stored<Signed<IdentityData>>> & Identity::data() const
+{
+ return p->data;
+}
+
optional<string> Identity::name() const
{
return p->name.get();
diff --git a/src/identity.h b/src/identity.h
index 1dfc193..98db80a 100644
--- a/src/identity.h
+++ b/src/identity.h
@@ -10,9 +10,8 @@ using std::vector;
namespace erebos {
-class IdentityData
+struct IdentityData
{
-public:
static IdentityData load(const Ref &);
Ref store(const Storage & st) const;