diff options
Diffstat (limited to 'src/contact.cpp')
-rw-r--r-- | src/contact.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/contact.cpp b/src/contact.cpp new file mode 100644 index 0000000..9ab5699 --- /dev/null +++ b/src/contact.cpp @@ -0,0 +1,207 @@ +#include "contact.h" + +#include "identity.h" + +#include <array> + +using namespace erebos; + +using std::array; +using std::move; + +DEFINE_SHARED_TYPE(Set<Contact>, + "34fbb61e-6022-405f-b1b3-a5a1abecd25e", + &Set<Contact>::load, + [](const Set<Contact> & set) { + return set.store(); + }) + +static const UUID serviceUUID("d9c37368-0da1-4280-93e9-d9bd9a198084"); + +Contact::Contact(vector<Stored<ContactData>> data): + p(shared_ptr<Priv>(new Priv { + .data = data, + })) +{ +} + +optional<Identity> Contact::identity() const +{ + p->init(); + return p->identity; +} + +optional<string> Contact::customName() const +{ + p->init(); + return p->name; +} + +Contact Contact::customName(const Storage & st, const string & name) const +{ + auto cdata = st.store(ContactData { + .prev = p->data, + .identity = {}, + .name = name, + }); + + return Contact(shared_ptr<Contact::Priv>(new Contact::Priv { + .data = { cdata }, + })); +} + +string Contact::name() const +{ + if (auto cust = customName()) + return *cust; + if (auto id = p->identity) + if (auto idname = id->name()) + return *idname; + return ""; +} + +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; +} + +vector<Stored<ContactData>> Contact::data() const +{ + return p->data; +} + +Digest Contact::leastRoot() const +{ + if (p->data.empty()) + return Digest(array<uint8_t, Digest::size> {}); + + vector<Digest> roots; + for (const auto & d : p->data) + for (const auto & r : d.ref().roots()) + roots.push_back(r); + roots.erase(std::unique(roots.begin(), roots.end()), roots.end()); + return roots[0]; +} + +void Contact::Priv::init() +{ + std::call_once(initFlag, [this]() { + vector<StoredIdentityPart> idata; + for (const auto & c : findPropertyComponents<Contact>(data, "identity")) + for (const auto & i : c->identity) + idata.push_back(i); + + identity = Identity::load(idata); + if (identity) + name = identity->name(); + + if (auto opt = findPropertyComponent<Contact>(data, "name")) + name = (*opt)->name; + }); +} + +ContactData ContactData::load(const Ref & ref) +{ + auto rec = ref->asRecord(); + if (!rec) + return ContactData(); + + vector<StoredIdentityPart> identity; + for (const auto & r : rec->items("identity").asRef()) + identity.push_back(StoredIdentityPart::load(r)); + + return ContactData { + .prev = rec->items("PREV").as<ContactData>(), + .identity = 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.ref()); + if (name) + items.emplace_back("name", *name); + + return st.storeObject(Record(std::move(items))); +} + +ContactService::ContactService(Config && config, const Server & s): + PairingService(move(config)), + server(s) +{ +} + +ContactService::~ContactService() = default; + +UUID ContactService::uuid() const +{ + return serviceUUID; +} + +void ContactService::request(const Peer & peer) +{ + requestPairing(serviceUUID, peer); +} + +Stored<ContactAccepted> ContactService::handlePairingComplete(const Peer & peer) +{ + server.localHead().update([&] (const Stored<LocalState> & local) { + auto cdata = local.ref().storage().store(ContactData { + .prev = {}, + .identity = peer.identity()->finalOwner().extData(), + .name = std::nullopt, + }); + + Contact contact(shared_ptr<Contact::Priv>(new Contact::Priv { + .data = { cdata }, + })); + + auto contacts = local->shared<Set<Contact>>(); + + return local.ref().storage().store(local->shared<Set<Contact>>( + contacts.add(local.ref().storage(), contact))); + }); + + return peer.tempStorage().store(ContactAccepted {}); +} + +void ContactService::handlePairingResult(Context & ctx, Stored<ContactAccepted>) +{ + auto cdata = ctx.local().ref().storage().store(ContactData { + .prev = {}, + .identity = ctx.peer().identity()->finalOwner().extData(), + .name = std::nullopt, + }); + + Contact contact(shared_ptr<Contact::Priv>(new Contact::Priv { + .data = { cdata }, + })); + + auto contacts = ctx.local()->shared<Set<Contact>>(); + + ctx.local(ctx.local()->shared<Set<Contact>>( + contacts.add(ctx.local().ref().storage(), contact))); +} + +ContactAccepted ContactAccepted::load(const Ref &) +{ + return ContactAccepted {}; +} + +Ref ContactAccepted::store(const Storage & st) const +{ + vector<Record::Item> items; + items.emplace_back("accept", ""); + return st.storeObject(Record(std::move(items))); +} |