more sync code

This commit is contained in:
Green Sky 2023-12-31 14:25:56 +01:00
parent 619ac3ad16
commit e9e5ad88a1
No known key found for this signature in database
11 changed files with 208 additions and 65 deletions

View File

@ -31,24 +31,29 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
} }
//ConfigModelI* conf = nullptr; //ConfigModelI* conf = nullptr;
Contact3Registry* cr = nullptr;
{ // make sure required types are loaded { // make sure required types are loaded
//conf = RESOLVE_INSTANCE(ConfigModelI); //conf = RESOLVE_INSTANCE(ConfigModelI);
cr = RESOLVE_INSTANCE(Contact3Registry);
//if (conf == nullptr) { //if (conf == nullptr) {
//std::cerr << "PLUGIN CRDTN missing ConfigModelI\n"; //std::cerr << "PLUGIN CRDTN missing ConfigModelI\n";
//return 2; //return 2;
//} //}
if (cr == nullptr) {
std::cerr << "PLUGIN CRDTNTS missing Contact3Registry\n";
return 2;
}
} }
// static store, could be anywhere tho // static store, could be anywhere tho
// construct with fetched dependencies // construct with fetched dependencies
g_crdtn = std::make_unique<CRDTNotes>(/**conf*/); g_crdtn = std::make_unique<CRDTNotes>();
g_crdtns = std::make_unique<CRDTNotesSync>(/**conf*/); g_crdtns = std::make_unique<CRDTNotesSync>(*g_crdtn, *cr);
// register types // register types
PROVIDE_INSTANCE(CRDTNotes, "CRDTNotes", g_crdtn.get());
PROVIDE_INSTANCE(CRDTNotesSync, "CRDTNotes", g_crdtns.get()); PROVIDE_INSTANCE(CRDTNotesSync, "CRDTNotes", g_crdtns.get());
PROVIDE_INSTANCE(CRDTNotesEventI, "CRDTNotes", g_crdtns.get()); PROVIDE_INSTANCE(CRDTNotesEventI, "CRDTNotes", g_crdtns.get());
@ -59,12 +64,13 @@ SOLANA_PLUGIN_EXPORT void solana_plugin_stop(void) {
std::cout << "PLUGIN CRDTN STOP()\n"; std::cout << "PLUGIN CRDTN STOP()\n";
g_crdtn.reset(); g_crdtn.reset();
g_crdtns.reset();
} }
SOLANA_PLUGIN_EXPORT void solana_plugin_tick(float delta) { SOLANA_PLUGIN_EXPORT void solana_plugin_tick(float delta) {
(void)delta; (void)delta;
//std::cout << "PLUGIN CRDTN TICK()\n"; //std::cout << "PLUGIN CRDTN TICK()\n";
//g_crdtn->iterate(); g_crdtns->iterate(delta);
} }
} // extern C } // extern C

View File

@ -30,13 +30,13 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
} }
//ConfigModelI* conf = nullptr; //ConfigModelI* conf = nullptr;
CRDTNotes* crdtn = nullptr; CRDTNotesSync* crdtns = nullptr;
Contact3Registry* cr = nullptr; Contact3Registry* cr = nullptr;
ImGuiContext* imguic = nullptr; ImGuiContext* imguic = nullptr;
{ // make sure required types are loaded { // make sure required types are loaded
//conf = RESOLVE_INSTANCE(ConfigModelI); //conf = RESOLVE_INSTANCE(ConfigModelI);
crdtn = RESOLVE_INSTANCE(CRDTNotes); crdtns = RESOLVE_INSTANCE(CRDTNotesSync);
cr = RESOLVE_INSTANCE(Contact3Registry); cr = RESOLVE_INSTANCE(Contact3Registry);
imguic = RESOLVE_INSTANCE(ImGuiContext); imguic = RESOLVE_INSTANCE(ImGuiContext);
@ -45,8 +45,8 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
//return 2; //return 2;
//} //}
if (crdtn == nullptr) { if (crdtns == nullptr) {
std::cerr << "PLUGIN CRDTNIMGUI missing CRDTNotes\n"; std::cerr << "PLUGIN CRDTNIMGUI missing CRDTNotesSync\n";
return 2; return 2;
} }
@ -65,7 +65,7 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
// static store, could be anywhere tho // static store, could be anywhere tho
// construct with fetched dependencies // construct with fetched dependencies
g_crdtn_imgui = std::make_unique<CRDTNotesImGui>(*crdtn, *cr); g_crdtn_imgui = std::make_unique<CRDTNotesImGui>(*crdtns, *cr);
// register types // register types
PROVIDE_INSTANCE(CRDTNotesImGui, "CRDTNotesImGui", g_crdtn_imgui.get()); PROVIDE_INSTANCE(CRDTNotesImGui, "CRDTNotesImGui", g_crdtn_imgui.get());

View File

@ -35,7 +35,6 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
} }
//ConfigModelI* conf = nullptr; //ConfigModelI* conf = nullptr;
CRDTNotes* notes = nullptr;
CRDTNotesEventI* notes_sync = nullptr; CRDTNotesEventI* notes_sync = nullptr;
Contact3Registry* cr = nullptr; Contact3Registry* cr = nullptr;
ToxI* t = nullptr; ToxI* t = nullptr;
@ -44,7 +43,6 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
{ // make sure required types are loaded { // make sure required types are loaded
//conf = RESOLVE_INSTANCE(ConfigModelI); //conf = RESOLVE_INSTANCE(ConfigModelI);
notes = RESOLVE_INSTANCE(CRDTNotes);
notes_sync = RESOLVE_INSTANCE(CRDTNotesEventI); notes_sync = RESOLVE_INSTANCE(CRDTNotesEventI);
cr = RESOLVE_INSTANCE(Contact3Registry); cr = RESOLVE_INSTANCE(Contact3Registry);
t = RESOLVE_INSTANCE(ToxI); t = RESOLVE_INSTANCE(ToxI);
@ -56,11 +54,6 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
//return 2; //return 2;
//} //}
if (notes == nullptr) {
std::cerr << "PLUGIN CRDTNTS missing CRDTNotes\n";
return 2;
}
if (notes_sync == nullptr) { if (notes_sync == nullptr) {
std::cerr << "PLUGIN CRDTNTS missing CRDTNotesEventI\n"; std::cerr << "PLUGIN CRDTNTS missing CRDTNotesEventI\n";
return 2; return 2;
@ -89,7 +82,7 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
// static store, could be anywhere tho // static store, could be anywhere tho
// construct with fetched dependencies // construct with fetched dependencies
g_crdtn_ts = std::make_unique<CRDTNotesToxSync>(*notes, *notes_sync, *cr, *t, *tep, *tcm); g_crdtn_ts = std::make_unique<CRDTNotesToxSync>(*notes_sync, *cr, *t, *tep, *tcm);
// register types // register types
PROVIDE_INSTANCE(CRDTNotesToxSync, "CRDTNotesToxSync", g_crdtn_ts.get()); PROVIDE_INSTANCE(CRDTNotesToxSync, "CRDTNotesToxSync", g_crdtn_ts.get());

View File

@ -1,8 +1,6 @@
#include "./crdtnotes.hpp" #include "./crdtnotes.hpp"
CRDTNotes::CRDTNotes(void) { CRDTNotes::CRDTNotes(void) {
_rng.seed(std::random_device{}());
_rng.discard(707);
} }
CRDTNotes::~CRDTNotes(void) { CRDTNotes::~CRDTNotes(void) {
@ -39,13 +37,3 @@ CRDTNotes::Doc* CRDTNotes::addDoc(const CRDTAgent& self_agent, const DocID& id)
return &doc; return &doc;
} }
CRDTNotes::Doc* CRDTNotes::addDoc(const CRDTAgent& self_agent) {
DocID new_id;
for (auto& it : new_id) {
// TODO: this discards alot
it = static_cast<uint8_t>(_rng());
}
return addDoc(self_agent, new_id);
}

View File

@ -6,10 +6,6 @@
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
#include <random>
// fwd
struct CRDTNotesContactSyncModelI;
using ID32 = std::array<uint8_t, 32>; using ID32 = std::array<uint8_t, 32>;
@ -44,7 +40,6 @@ class CRDTNotes {
private: private:
// TODO: add metadata to docs // TODO: add metadata to docs
std::unordered_map<DocID, Doc> _docs; std::unordered_map<DocID, Doc> _docs;
std::default_random_engine _rng;
public: public:
// config? // config?
@ -57,8 +52,5 @@ class CRDTNotes {
Doc* getDoc(const DocID& id); Doc* getDoc(const DocID& id);
Doc* addDoc(const CRDTAgent& self_agent, const DocID& doc); Doc* addDoc(const CRDTAgent& self_agent, const DocID& doc);
// new doc with random id
Doc* addDoc(const CRDTAgent& self_agent);
}; };

View File

@ -1,6 +1,136 @@
#include "./crdtnotes_sync.hpp" #include "./crdtnotes_sync.hpp"
#include <solanaceae/contact/components.hpp>
#include <cstdint>
#include <vector>
#include <iostream>
static ID32 id_from_vec(const std::vector<uint8_t>& vec) {
ID32 new_id;
for (size_t i = 0; i < new_id.size() && i < vec.size(); i++) {
new_id.at(i) = vec.at(i);
}
return new_id;
}
CRDTNotesSync::CRDTNotesSync(CRDTNotes& notes, Contact3Registry& cr) : _notes(notes), _cr(cr) {
_rng.seed(std::random_device{}());
_rng.discard(707);
}
CRDTNotesSync::~CRDTNotesSync(void) {
}
float CRDTNotesSync::iterate(float time_delta) {
return 1.f;
}
CRDTNotes::Doc* CRDTNotesSync::getDoc(const CRDTNotes::DocID& doc_id) {
return _notes.getDoc(doc_id);
}
std::optional<CRDTNotes::DocID> CRDTNotesSync::addNewDoc(Contact3Handle c, bool secret) {
if (!static_cast<bool>(c)) {
std::cerr << "CRDTNS error: invalid contact\n";
return std::nullopt;
}
const auto& self = c.get<Contact::Components::Self>().self;
assert(_cr.all_of<Contact::Components::ID>(self));
const auto& self_id = _cr.get<Contact::Components::ID>(self);
assert(!self_id.data.empty());
CRDTNotes::CRDTAgent self_agent_id = id_from_vec(self_id.data);
CRDTNotes::DocID new_id;
{ // generate new random id
for (auto& it : new_id) {
// TODO: this discards alot
it = static_cast<uint8_t>(_rng());
}
}
const auto* doc_ptr = _notes.addDoc(
// tox id (id from self)
self_agent_id,
new_id // docid
);
if (doc_ptr == nullptr) {
return std::nullopt;
}
if (!secret) {
_docs_contacts[new_id].emplace(c);
}
return new_id;
}
bool CRDTNotesSync::addDoc(const CRDTNotes::DocID& doc_id, Contact3Handle c) {
if (!static_cast<bool>(c)) {
std::cerr << "CRDTNS error: invalid contact\n";
return false;
}
const auto& self = c.get<Contact::Components::Self>().self;
assert(_cr.all_of<Contact::Components::ID>(self));
const auto& self_id = _cr.get<Contact::Components::ID>(self);
assert(!self_id.data.empty());
CRDTNotes::CRDTAgent self_agent_id = id_from_vec(self_id.data);
// preexisting does not overwrite self!!!
const auto* doc_ptr = _notes.addDoc(self_agent_id, doc_id);
_docs_contacts[doc_id].emplace(c);
return doc_ptr != nullptr;
}
std::vector<CRDTNotes::DocID> CRDTNotesSync::getDocList(void) {
return _notes.getDocList();
}
std::vector<CRDTNotes::DocID> CRDTNotesSync::getDocList(Contact3Handle c) {
std::vector<CRDTNotes::DocID> list;
Contact3Handle parent;
if (c.all_of<Contact::Components::Parent>()) {
parent = Contact3Handle{*c.registry(), c.get<Contact::Components::Parent>().parent};
}
for (const auto& [k, v] : _docs_contacts) {
if (v.count(c)) {
list.push_back(k);
continue; // avoid dups
}
if (v.count(parent)) {
list.push_back(k);
}
}
return list;
}
void CRDTNotesSync::merge(const CRDTNotes::DocID& doc_id, std::string_view new_text) {
auto* doc_ptr = _notes.getDoc(doc_id);
if (doc_ptr == nullptr) {
std::cerr << "CRDTNS error: tried to merge into unknown doc\n";
return;
}
auto op_vec = doc_ptr->merge(new_text);
std::cout << "doc changed " << op_vec.size() << " ops generated\n";
// USE OPS
}
void CRDTNotesSync::onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip&& e) { void CRDTNotesSync::onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip&& e) {
addDoc(e.doc_id, e.c);
} }
void CRDTNotesSync::onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip_frontier&& e) { void CRDTNotesSync::onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip_frontier&& e) {

View File

@ -1,8 +1,15 @@
#pragma once #pragma once
#include "./crdtnotes.hpp" #include "./crdtnotes.hpp"
#include <solanaceae/contact/contact_model3.hpp> #include <solanaceae/contact/contact_model3.hpp>
#include <set>
#include <random>
// fwd
struct CRDTNotesContactSyncModelI;
namespace Events { namespace Events {
// - DocID // - DocID
@ -67,6 +74,37 @@ struct CRDTNotesEventI {
// gets called on incoming packets // gets called on incoming packets
// calls CRDTNotesContactSyncModelI on contacts // calls CRDTNotesContactSyncModelI on contacts
class CRDTNotesSync final : public CRDTNotesEventI { class CRDTNotesSync final : public CRDTNotesEventI {
// pull inside????
CRDTNotes& _notes;
Contact3Registry& _cr;
std::default_random_engine _rng;
std::unordered_map<CRDTNotes::DocID, std::set<Contact3Handle>> _docs_contacts;
public:
CRDTNotesSync(CRDTNotes& notes, Contact3Registry& cr);
~CRDTNotesSync(void);
// called from main thread periodically
float iterate(float time_delta);
public: // CRDTNotes api
CRDTNotes::Doc* getDoc(const CRDTNotes::DocID& doc_id);
// adds a doc and assosiates contact (and self)
// if secret, only self is added (and thats why contact is needed)
std::optional<CRDTNotes::DocID> addNewDoc(Contact3Handle c, bool secret = false);
// adds a doc by id to a contact
// (for gossip or manual add)
bool addDoc(const CRDTNotes::DocID& doc_id, Contact3Handle c);
std::vector<CRDTNotes::DocID> getDocList(void);
std::vector<CRDTNotes::DocID> getDocList(Contact3Handle c);
void merge(const CRDTNotes::DocID& doc_id, std::string_view new_text);
public: public:
void onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip&& e) override; void onCRDTNSyncEvent(Events::NGCEXT_crdtns_gossip&& e) override;

View File

@ -47,7 +47,7 @@ namespace detail {
} // detail } // detail
CRDTNotesImGui::CRDTNotesImGui(CRDTNotes& notes, Contact3Registry& cr) : _notes(notes), _cr(cr) { CRDTNotesImGui::CRDTNotesImGui(CRDTNotesSync& notes_sync, Contact3Registry& cr) : _notes_sync(notes_sync), _cr(cr) {
} }
float CRDTNotesImGui::render(void) { float CRDTNotesImGui::render(void) {
@ -60,24 +60,25 @@ float CRDTNotesImGui::render(void) {
if (ImGui::BeginPopup("create new doc contact")) { if (ImGui::BeginPopup("create new doc contact")) {
for (const auto& c : _cr.view<Contact::Components::TagBig>()) { for (const auto& c : _cr.view<Contact::Components::TagBig>()) {
if (renderContactListContactSmall(c, false)) { if (renderContactListContactSmall(c, false)) {
const auto& self = _cr.get<Contact::Components::Self>(c).self; //const auto& self = _cr.get<Contact::Components::Self>(c).self;
assert(_cr.all_of<Contact::Components::ID>(self)); //assert(_cr.all_of<Contact::Components::ID>(self));
const auto& self_id = _cr.get<Contact::Components::ID>(self); //const auto& self_id = _cr.get<Contact::Components::ID>(self);
assert(!self_id.data.empty()); //assert(!self_id.data.empty());
CRDTNotes::CRDTAgent self_agent_id; //CRDTNotes::CRDTAgent self_agent_id;
// at most agent size, up to self id size //// at most agent size, up to self id size
for (size_t i = 0; i < self_agent_id.size() && i < self_id.data.size(); i++) { //for (size_t i = 0; i < self_agent_id.size() && i < self_id.data.size(); i++) {
self_agent_id.at(i) = self_id.data.at(i); //self_agent_id.at(i) = self_id.data.at(i);
} //}
_notes.addDoc( //_notes.addDoc(
// tox id (id from self) //// tox id (id from self)
self_agent_id //self_agent_id
); //);
_notes_sync.addNewDoc({_cr, c}, false);
// and open the doc //// and open the doc
} }
} }
ImGui::EndPopup(); ImGui::EndPopup();
@ -85,7 +86,7 @@ float CRDTNotesImGui::render(void) {
ImGui::SeparatorText("Global list"); ImGui::SeparatorText("Global list");
const auto doclist = _notes.getDocList(); const auto doclist = _notes_sync.getDocList();
for (const auto& docid : doclist) { for (const auto& docid : doclist) {
const auto docid_str = detail::to_hex(docid); const auto docid_str = detail::to_hex(docid);
//ImGui::TextUnformatted(docid_str.c_str()); //ImGui::TextUnformatted(docid_str.c_str());
@ -132,16 +133,14 @@ bool CRDTNotesImGui::renderContactListContactSmall(const Contact3 c, const bool
} }
bool CRDTNotesImGui::renderDoc(const CRDTNotes::DocID& doc_id) { bool CRDTNotesImGui::renderDoc(const CRDTNotes::DocID& doc_id) {
auto* doc = _notes.getDoc(doc_id); auto* doc = _notes_sync.getDoc(doc_id);
if (doc == nullptr) { if (doc == nullptr) {
return false; return false;
} }
auto text = doc->getText(); auto text = doc->getText();
if (renderDocText(text)) { if (renderDocText(text)) {
auto op_vec = doc->merge(text); _notes_sync.merge(doc_id, text);
std::cout << "doc changed " << op_vec.size() << " ops generated\n";
// ... uh?
return true; return true;
} }

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <solanaceae/crdtnotes/crdtnotes.hpp> #include <solanaceae/crdtnotes/crdtnotes_sync.hpp>
#include <solanaceae/contact/contact_model3.hpp> #include <solanaceae/contact/contact_model3.hpp>
#include <set> #include <set>
class CRDTNotesImGui { class CRDTNotesImGui {
CRDTNotes& _notes; CRDTNotesSync& _notes_sync;
Contact3Registry& _cr; Contact3Registry& _cr;
bool _show_global_list {true}; bool _show_global_list {true};
@ -14,7 +14,7 @@ class CRDTNotesImGui {
std::set<CRDTNotes::DocID> _open_docs; std::set<CRDTNotes::DocID> _open_docs;
public: public:
CRDTNotesImGui(CRDTNotes& notes, Contact3Registry& cr); CRDTNotesImGui(CRDTNotesSync& notes_sync, Contact3Registry& cr);
float render(void); float render(void);

View File

@ -38,13 +38,12 @@ enum class NGCEXT_Event : uint8_t {
#define _DATA_HAVE(x, error) if ((data_size - curser) < (x)) { error } #define _DATA_HAVE(x, error) if ((data_size - curser) < (x)) { error }
CRDTNotesToxSync::CRDTNotesToxSync( CRDTNotesToxSync::CRDTNotesToxSync(
CRDTNotes& notes,
CRDTNotesEventI& notes_sync, CRDTNotesEventI& notes_sync,
Contact3Registry& cr, Contact3Registry& cr,
ToxI& t, ToxI& t,
ToxEventProviderI& tep, ToxEventProviderI& tep,
ToxContactModel2& tcm ToxContactModel2& tcm
) : _notes(notes), _notes_sync(notes_sync), _cr(cr), _t(t), _tep(tep), _tcm(tcm) { ) : _notes_sync(notes_sync), _cr(cr), _t(t), _tep(tep), _tcm(tcm) {
// TODO: non groups // TODO: non groups
// should be called for every peer (except self) // should be called for every peer (except self)

View File

@ -13,7 +13,6 @@ struct ToxEventProviderI;
// implements CRDTNotesContactSyncModelI and attaches itself to tox contacts // implements CRDTNotesContactSyncModelI and attaches itself to tox contacts
class CRDTNotesToxSync : public CRDTNotesContactSyncModelI, public ToxEventI { class CRDTNotesToxSync : public CRDTNotesContactSyncModelI, public ToxEventI {
CRDTNotes& _notes;
CRDTNotesEventI& _notes_sync; CRDTNotesEventI& _notes_sync;
Contact3Registry& _cr; Contact3Registry& _cr;
ToxI& _t; ToxI& _t;
@ -22,7 +21,6 @@ class CRDTNotesToxSync : public CRDTNotesContactSyncModelI, public ToxEventI {
public: public:
CRDTNotesToxSync( CRDTNotesToxSync(
CRDTNotes& notes,
CRDTNotesEventI& notes_sync, CRDTNotesEventI& notes_sync,
Contact3Registry& cr, Contact3Registry& cr,
ToxI& t, ToxI& t,