#include "contact.h" #include "identity.h" #include using namespace erebos; using std::array; using std::move; DEFINE_SHARED_TYPE(Set, "34fbb61e-6022-405f-b1b3-a5a1abecd25e", &Set::load, [](const Set & set) { return set.store(); }) static const UUID serviceUUID("d9c37368-0da1-4280-93e9-d9bd9a198084"); Contact::Contact(vector> data): p(shared_ptr(new Priv { .data = data, })) { } optional Contact::identity() const { p->init(); return p->identity; } optional 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(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> Contact::data() const { return p->data; } Digest Contact::leastRoot() const { if (p->data.empty()) return Digest(array {}); vector 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 idata; for (const auto & c : findPropertyComponents(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(data, "name")) name = (*opt)->name; }); } ContactData ContactData::load(const Ref & ref) { auto rec = ref->asRecord(); if (!rec) return ContactData(); vector identity; for (const auto & r : rec->items("identity").asRef()) identity.push_back(StoredIdentityPart::load(r)); return ContactData { .prev = rec->items("PREV").as(), .identity = move(identity), .name = rec->item("name").asText(), }; } Ref ContactData::store(const Storage & st) const { vector 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 ContactService::handlePairingComplete(const Peer & peer) { server.localHead().update([&] (const Stored & local) { auto cdata = local.ref().storage().store(ContactData { .prev = {}, .identity = peer.identity()->finalOwner().extData(), .name = std::nullopt, }); Contact contact(shared_ptr(new Contact::Priv { .data = { cdata }, })); auto contacts = local->shared>(); return local.ref().storage().store(local->shared>( contacts.add(local.ref().storage(), contact))); }); return peer.tempStorage().store(ContactAccepted {}); } void ContactService::handlePairingResult(Context & ctx, Stored) { auto cdata = ctx.local().ref().storage().store(ContactData { .prev = {}, .identity = ctx.peer().identity()->finalOwner().extData(), .name = std::nullopt, }); Contact contact(shared_ptr(new Contact::Priv { .data = { cdata }, })); auto contacts = ctx.local()->shared>(); ctx.local(ctx.local()->shared>( contacts.add(ctx.local().ref().storage(), contact))); } ContactAccepted ContactAccepted::load(const Ref &) { return ContactAccepted {}; } Ref ContactAccepted::store(const Storage & st) const { vector items; items.emplace_back("accept", ""); return st.storeObject(Record(std::move(items))); }