hello mr fox

This commit is contained in:
2023-08-03 22:27:19 +02:00
commit 7e90e4da33
7 changed files with 904 additions and 0 deletions

220
solanaceae/zox/ngc.cpp Normal file
View File

@@ -0,0 +1,220 @@
#include "./ngc.hpp"
#include <optional>
#include <tuple>
#include <iostream>
constexpr size_t zox_magic_size = 6;
static bool is_zox_magic(const uint8_t* data, size_t size) {
//0x667788113435
return size >= zox_magic_size &&
data != nullptr &&
data[0] == 0x66 &&
data[1] == 0x77 &&
data[2] == 0x88 &&
data[3] == 0x11 &&
data[4] == 0x34 &&
data[5] == 0x35;
}
constexpr size_t zox_header_size = zox_magic_size + 2;
std::optional<std::pair<uint8_t, uint8_t>> parse_zox_pkg_header(const uint8_t* data, size_t size) {
if (!is_zox_magic(data, size)) {
return std::nullopt;
}
data += zox_magic_size;
size -= zox_magic_size;
if (size < 2) {
return std::nullopt;
}
const uint8_t version = data[0];
const uint8_t pkt_id = data[1];
return std::make_pair(version, pkt_id);
}
void ZoxNGCEventProvider::subscribeToEvents(void) {
_tep.subscribe(this, Tox_Event::TOX_EVENT_GROUP_CUSTOM_PACKET);
_tep.subscribe(this, Tox_Event::TOX_EVENT_GROUP_CUSTOM_PRIVATE_PACKET);
}
ZoxNGCEventProvider::ZoxNGCEventProvider(ToxEventProviderI& tep) : _tep(tep) {
subscribeToEvents();
}
bool ZoxNGCEventProvider::onZoxGroupEvent(
uint32_t group_number, uint32_t peer_number,
uint8_t version, uint8_t pkt_id,
const uint8_t* data, size_t data_size,
bool _private
) {
if (version == 0x01 && pkt_id == 0x01) {
// ngch_request
return parse_ngch_request(group_number, peer_number, data, data_size, _private);
} else if (version == 0x01 && pkt_id == 0x02) {
// ngch_syncmsg
return parse_ngch_syncmsg(group_number, peer_number, data, data_size, _private);
} else if (version == 0x01 && pkt_id == 0x03) {
std::cout << "ZOX waring: ngch_syncmsg_file not implemented\n";
} else if (version == 0x01 && pkt_id == 0x11) {
std::cout << "ZOX waring: ngc_ft not implemented\n";
} else {
std::cout << "ZOX waring: unknown packet v" << (int)version << " id" << (int)pkt_id <<"\n";
}
return false;
}
bool ZoxNGCEventProvider::parse_ngch_request(
uint32_t group_number, uint32_t peer_number,
const uint8_t* data, size_t data_size,
bool _private
) {
if (data_size > 1) {
std::cerr << "ZOX ngch_request has wrong size, should: <=1 , is: " << data_size << "\n";
return false;
}
uint8_t sync_delta = 130u;
if (data_size == 1) {
sync_delta = data[0];
// clamp
if (sync_delta < 5u) {
sync_delta = 5u;
} else if (sync_delta > 130u) {
sync_delta = 130u;
}
}
return dispatch(
ZoxNGC_Event::ngch_request,
Events::ZoxNGC_ngch_request{
group_number,
peer_number,
_private,
sync_delta
}
);
}
bool ZoxNGCEventProvider::parse_ngch_syncmsg(
uint32_t group_number, uint32_t peer_number,
const uint8_t* data, size_t data_size,
bool _private
) {
constexpr size_t min_pkg_size = 4 + 32 + 4 + 25;
if (data_size <= 4 + 32 + 4 + 25) {
std::cerr << "ZOX ngch_syncmsg has wrong size, should: >=" << min_pkg_size << " , is: " << data_size << "\n";
return false;
}
// 4 bytes, message id
uint32_t message_id = 0;
message_id |= uint32_t(data[0]) << 8*3;
message_id |= uint32_t(data[1]) << 8*2;
message_id |= uint32_t(data[2]) << 8*1;
message_id |= uint32_t(data[3]) << 8*0;
data += 4;
data_size -= 4;
// 32 bytes, sender pub key
std::array<uint8_t, 32> sender_pub_key {
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15],
data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23],
data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31],
};
data += 32;
data_size -= 32;
// 4 bytes, timestamp
uint32_t timestamp = 0;
timestamp |= uint32_t(data[0]) << 8*3;
timestamp |= uint32_t(data[1]) << 8*2;
timestamp |= uint32_t(data[2]) << 8*1;
timestamp |= uint32_t(data[3]) << 8*0;
data += 4;
data_size -= 4;
// 25 bytes, sender name, truncated/filled with 0
std::string_view sender_name{reinterpret_cast<const char*>(data), 25};
sender_name = sender_name.substr(0, sender_name.find_first_of('\0')); // trim \0
data += 25;
data_size -= 25;
// up to 39927 bytes, message
std::string_view message_text{reinterpret_cast<const char*>(data), data_size};
message_text = message_text.substr(0, message_text.find_first_of('\0')); // trim \0
return dispatch(
ZoxNGC_Event::ngch_syncmsg,
Events::ZoxNGC_ngch_syncmsg{
group_number,
peer_number,
_private,
message_id,
sender_pub_key,
timestamp,
sender_name,
message_text
}
);
}
bool ZoxNGCEventProvider::onToxEvent(const Tox_Event_Group_Custom_Packet* e) {
const uint32_t group_number = tox_event_group_custom_packet_get_group_number(e);
const uint32_t peer_number = tox_event_group_custom_packet_get_peer_id(e);
const uint8_t* data = tox_event_group_custom_packet_get_data(e);
size_t size = tox_event_group_custom_packet_get_data_length(e);
auto res_opt = parse_zox_pkg_header(data, size);
if (!res_opt) {
return false;
}
auto [version, pkt_id] = *res_opt;
data += zox_header_size;
size -= zox_header_size;
return onZoxGroupEvent(
group_number, peer_number,
version, pkt_id,
data, size,
false
);
}
bool ZoxNGCEventProvider::onToxEvent(const Tox_Event_Group_Custom_Private_Packet* e) {
const uint32_t group_number = tox_event_group_custom_private_packet_get_group_number(e);
const uint32_t peer_number = tox_event_group_custom_private_packet_get_peer_id(e);
const uint8_t* data = tox_event_group_custom_private_packet_get_data(e);
size_t size = tox_event_group_custom_private_packet_get_data_length(e);
auto res_opt = parse_zox_pkg_header(data, size);
if (!res_opt) {
return false;
}
auto [version, pkt_id] = *res_opt;
data += zox_header_size;
size -= zox_header_size;
return onZoxGroupEvent(
group_number, peer_number,
version, pkt_id,
data, size,
true
);
}

121
solanaceae/zox/ngc.hpp Normal file
View File

@@ -0,0 +1,121 @@
#pragma once
#include <solanaceae/toxcore/tox_event_interface.hpp>
#include <solanaceae/util/event_provider.hpp>
#include <array>
#include <vector>
// fwd
//struct ToxI;
// zoff ngc history sync (draft1?)
// https://gist.github.com/zoff99/81917ddb2e55b2ce602cac4772a7b68c
namespace Events {
struct ZoxNGC_ngch_request {
uint32_t group_number {0u};
uint32_t peer_number {0u};
bool _private {true};
uint8_t sync_delta {130u};
};
struct ZoxNGC_ngch_syncmsg {
uint32_t group_number {0u};
uint32_t peer_number {0u};
bool _private {true};
uint32_t message_id {0u};
// TODO: span
std::array<uint8_t, 32> sender_pub_key;
uint32_t timestamp {0u};
std::string_view sender_name;
std::string_view message_text;
};
} // Events
enum class ZoxNGC_Event : uint32_t {
// hs
v0x01_id0x01 = 0,
ngch_request = v0x01_id0x01,
v0x01_id0x02,
ngch_syncmsg = v0x01_id0x02,
v0x01_id0x03,
ngch_syncmsg_file = v0x01_id0x03,
//v0x01_id0x04,
//v0x01_id0x05,
//v0x01_id0x06,
//v0x01_id0x07,
//v0x01_id0x08,
//v0x01_id0x09,
//v0x01_id0x0a,
//v0x01_id0x0b,
//v0x01_id0x0c,
//v0x01_id0x0d,
//v0x01_id0x0e,
//v0x01_id0x0f,
//v0x01_id0x10,
v0x01_id0x11,
ngch_ft = v0x01_id0x11,
// ...
// v0x02_id0x01
MAX
};
static_assert(size_t(ZoxNGC_Event::v0x01_id0x02) == size_t(ZoxNGC_Event::v0x01_id0x01) + 1u);
struct ZoxNGCEventI {
using enumType = ZoxNGC_Event;
virtual bool onEvent(const Events::ZoxNGC_ngch_request&) { return false; }
virtual bool onEvent(const Events::ZoxNGC_ngch_syncmsg&) { return false; }
};
using ZoxNGCEventProviderI = EventProviderI<ZoxNGCEventI>;
class ZoxNGCEventProvider : public ToxEventI, public ZoxNGCEventProviderI {
ToxEventProviderI& _tep;
//ToxI& _t;
void subscribeToEvents(void); // private
public:
ZoxNGCEventProvider(ToxEventProviderI& tep/*, ToxI& t*/);
protected:
bool onZoxGroupEvent(
uint32_t group_number, uint32_t peer_number,
uint8_t version, uint8_t pkt_id,
const uint8_t* data, size_t data_size,
bool _private
);
bool parse_ngch_request(
uint32_t group_number, uint32_t peer_number,
const uint8_t* data, size_t data_size,
bool _private
);
bool parse_ngch_syncmsg(
uint32_t group_number, uint32_t peer_number,
const uint8_t* data, size_t data_size,
bool _private
);
protected:
bool onToxEvent(const Tox_Event_Group_Custom_Packet* e) override;
bool onToxEvent(const Tox_Event_Group_Custom_Private_Packet* e) override;
};

412
solanaceae/zox/ngc_hs.cpp Normal file
View File

@@ -0,0 +1,412 @@
#include "./ngc_hs.hpp"
#include <solanaceae/toxcore/tox_interface.hpp>
#include <solanaceae/contact/components.hpp>
#include <solanaceae/tox_contacts/tox_contact_model2.hpp>
#include <solanaceae/tox_contacts/components.hpp>
#include <solanaceae/message3/components.hpp>
#include <solanaceae/tox_messages/components.hpp>
#include <optional>
#include <chrono>
#include <iostream>
#include <variant>
#include <vector>
void ZoxNGCHistorySync::subscribeToEvents(void) {
_zngcepi.subscribe(this, ZoxNGC_Event::ngch_request);
_zngcepi.subscribe(this, ZoxNGC_Event::ngch_syncmsg);
_tep.subscribe(this, Tox_Event::TOX_EVENT_GROUP_PEER_JOIN);
}
ZoxNGCHistorySync::ZoxNGCHistorySync(ToxEventProviderI& tep, ZoxNGCEventProviderI& zngcepi, ToxI& t, Contact3Registry& cr, ToxContactModel2& tcm, RegistryMessageModel& rmm)
: _tep(tep), _zngcepi(zngcepi), _t(t), _cr(cr), _tcm(tcm), _rmm(rmm), _rng(std::random_device{}())
{
subscribeToEvents();
}
void ZoxNGCHistorySync::tick(float delta) {
// send queued requests
for (auto it = _request_queue.begin(); it != _request_queue.end();) {
it->second.timer += delta;
if (it->second.timer >= it->second.delay) {
if (!_cr.all_of<Contact::Components::ToxGroupPeerEphemeral>(it->first)) {
// peer nolonger online
it = _request_queue.erase(it);
continue;
}
const auto [group_number, peer_number] = _cr.get<Contact::Components::ToxGroupPeerEphemeral>(it->first);
if (sendRequest(group_number, peer_number, it->second.sync_delta)) {
// on success, requeue with longer delay (minutes)
it->second.timer = 0.f;
it->second.delay = _delay_next_request_min + _rng_dist(_rng)*_delay_next_request_add;
// double the delay for overlap (9m-15m)
// TODO: finetune
it->second.sync_delta = uint8_t((it->second.delay/60.f)*2.f) + 1;
std::cout << "ZOX #### requeued request in " << it->second.delay << "s\n";
it++;
} else {
// on failure, assume disconnected
it = _request_queue.erase(it);
}
} else {
it++;
}
}
for (auto it = _sync_queue.begin(); it != _sync_queue.end();) {
it->second.timer += delta;
if (it->second.timer >= it->second.delay) {
Message3 msg_e = it->second.ents.front();
it->second.ents.pop();
if (!_cr.all_of<Contact::Components::ToxGroupPeerEphemeral>(it->first)) {
// peer nolonger online
it = _sync_queue.erase(it);
continue;
}
const auto [group_number, peer_number] = _cr.get<Contact::Components::ToxGroupPeerEphemeral>(it->first);
auto* reg_ptr = _rmm.get(it->first);
if (reg_ptr == nullptr) {
//std::cout << "°°°°°°°° no reg for contact\n";
it = _sync_queue.erase(it);
continue;
}
Message3Registry& reg = *reg_ptr;
if (!reg.valid(msg_e)) {
std::cerr << "ZOX NGCHS error: invalid message in sync send queue\n";
it = _sync_queue.erase(it);
continue;
}
const auto& msg_sender = reg.get<Message::Components::ContactFrom>(msg_e).c;
if (!_cr.all_of<Contact::Components::ToxGroupPeerPersistent>(msg_sender)) {
std::cerr << "ZOX NGCHS error: msg sender without persistant\n";
continue;
}
//if (auto peer_persist_opt = _cm.toPersistent(msg_sender); peer_persist_opt.has_value() && std::holds_alternative<ContactGroupPeerPersistent>(peer_persist_opt.value())) {
// get name for peer
// TODO: make sure there is no alias leaked
//const auto msg_sender_name = _cm.getContactName(msg_sender);
std::string_view msg_sender_name;
if (_cr.all_of<Contact::Components::Name>(msg_sender)) {
msg_sender_name = _cr.get<Contact::Components::Name>(msg_sender).name;
}
if (!sendSyncMessage(
group_number,
peer_number,
reg.get<Message::Components::ToxGroupMessageID>(msg_e).id,
_cr.get<Contact::Components::ToxGroupPeerPersistent>(msg_sender).peer_key.data,
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::milliseconds{reg.get<Message::Components::Timestamp>(msg_e).ts}).count(),
msg_sender_name,
reg.get<Message::Components::MessageText>(msg_e).text
) || it->second.ents.empty()) {
it = _sync_queue.erase(it);
continue;
}
}
it++;
}
}
bool ZoxNGCHistorySync::sendRequest(
uint32_t group_number, uint32_t peer_number,
uint8_t sync_delta
) {
std::vector<uint8_t> packet;
{ // magic
//0x667788113435
packet.push_back(0x66);
packet.push_back(0x77);
packet.push_back(0x88);
packet.push_back(0x11);
packet.push_back(0x34);
packet.push_back(0x35);
}
packet.push_back(0x01); // version
packet.push_back(0x01); // pkt_id
packet.push_back(sync_delta);
auto ret = _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, packet);
// TODO: log error
return ret == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
}
bool ZoxNGCHistorySync::sendSyncMessage(
uint32_t group_number, uint32_t peer_number,
uint32_t message_id,
const std::array<uint8_t, 32>& sender_pub_key,
uint32_t timestamp,
std::string_view sender_name,
std::string_view message_text
) {
std::vector<uint8_t> packet;
{ // magic
//0x667788113435
packet.push_back(0x66);
packet.push_back(0x77);
packet.push_back(0x88);
packet.push_back(0x11);
packet.push_back(0x34);
packet.push_back(0x35);
}
packet.push_back(0x01); // version
packet.push_back(0x02); // pkt_id
// 4 bytes, message id
packet.push_back(0xff & (message_id >> 8*3));
packet.push_back(0xff & (message_id >> 8*2));
packet.push_back(0xff & (message_id >> 8*1));
packet.push_back(0xff & (message_id >> 8*0));
// 32 bytes, sender pub key
packet.insert(packet.end(), sender_pub_key.cbegin(), sender_pub_key.cend());
// 4 bytes, timestamp
packet.push_back(0xff & (timestamp >> 8*3));
packet.push_back(0xff & (timestamp >> 8*2));
packet.push_back(0xff & (timestamp >> 8*1));
packet.push_back(0xff & (timestamp >> 8*0));
// 25 bytes, sender name, truncated/filled with 0
// TODO: handle unicode properly
for (size_t i = 0; i < 25; i++) {
if (i < sender_name.size()) {
packet.push_back(sender_name.at(i));
} else {
packet.push_back('\0');
}
}
// up to 39927 bytes, message
#if 0
packet.insert(packet.end(), message_text.cbegin(), message_text.cend());
#else
//const int64_t msg_max_possible_size = _t.toxGroup
// TODO: make pr and add functions
const uint64_t msg_max_possible_size = std::clamp<int64_t>(
TOX_GROUP_MAX_CUSTOM_LOSSLESS_PACKET_LENGTH - packet.size(),
0, // low
39927 // high
);
for (size_t i = 0; i < msg_max_possible_size && i < message_text.size(); i++) {
packet.push_back(message_text.at(i));
}
#endif
auto ret = _t.toxGroupSendCustomPrivatePacket(group_number, peer_number, true, packet);
// TODO: log error
return ret == TOX_ERR_GROUP_SEND_CUSTOM_PRIVATE_PACKET_OK;
}
bool ZoxNGCHistorySync::onEvent(const Events::ZoxNGC_ngch_request& e) {
std::cout << "ZOX ngch_request"
<< " grp:" << e.group_number
<< " per:" << e.peer_number
<< " prv:" << e._private
<< " sdl:" << (int)e.sync_delta
<< "\n";
// if blacklisted / on cool down
const auto request_sender = _tcm.getContactGroupPeer(e.group_number, e.peer_number);
if (_sync_queue.count(request_sender)) {
std::cerr << "ZNGCHS waring: ngch_request but still in sync send queue\n";
return true;
}
// const -> dont create (this is a request for existing messages)
auto* reg_ptr = static_cast<const RegistryMessageModel&>(_rmm).get(request_sender);
if (reg_ptr == nullptr) {
std::cerr << "ZNGCHS error: group without reg\n";
return true;
}
const Message3Registry& reg = *reg_ptr;
std::queue<Message3> msg_send_queue;
// convert sync delta to ms
const int64_t sync_delta_offset_ms = int64_t(e.sync_delta) * 1000 * 60;
const uint64_t ts_start = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() - sync_delta_offset_ms;
auto view = reg.view<Message::Components::ContactFrom, Message::Components::ContactTo, Message::Components::Timestamp, Message::Components::MessageText, Message::Components::ToxGroupMessageID>().use<Message::Components::Timestamp>();
view.each([&](const Message3 e, const auto&, const auto& c_t, const auto& ts, const auto&, const auto&) {
// private
if (!_cr.all_of<Contact::Components::TagBig>(c_t.c)) {
return;
}
if (ts.ts < ts_start) {
std::cout << "---- " << ts.ts << " < " << ts_start << " -> too old\n";
return;
}
std::cout << "---- " << ts.ts << " >= " << ts_start << " -> selected\n";
msg_send_queue.push(e);
});
std::cout << "ZOX ngch_request selected " << msg_send_queue.size() << " messages\n";
if (!msg_send_queue.empty()) {
_sync_queue[request_sender] = SyncQueueInfo{
_delay_between_syncs_min + _rng_dist(_rng)*_delay_between_syncs_add,
0.f,
std::move(msg_send_queue)
};
}
return true;
}
bool ZoxNGCHistorySync::onEvent(const Events::ZoxNGC_ngch_syncmsg& e) {
std::cout << "ZOX ngch_syncmsg"
// who sent the syncmsg
<< " grp:" << e.group_number
<< " per:" << e.peer_number
<< " prv:" << e._private
// its contents
<< " mid:" << e.message_id
<< " spk:" << std::hex << (uint16_t)e.sender_pub_key[0] << (uint16_t)e.sender_pub_key[1] << std::dec
<< " ts:" << e.timestamp
<< " snm:" << e.sender_name
<< " txt:" << e.message_text
<< "\n";
auto sync_by_c = _tcm.getContactGroupPeer(e.group_number, e.peer_number);
assert(static_cast<bool>(sync_by_c));
auto* reg_ptr = _rmm.get(sync_by_c);
if (reg_ptr == nullptr) {
std::cerr << "ZNGCHS error: group without reg\n";
return false;
}
Message3Registry& reg = *reg_ptr;
const auto sync_c = _tcm.getContactGroupPeer(e.group_number, ToxKey{e.sender_pub_key.data(), e.sender_pub_key.size()});
assert(static_cast<bool>(sync_c)); // TODO: make conditional
// convert to ms
uint64_t sync_ts = std::chrono::milliseconds(std::chrono::seconds{e.timestamp}).count(); // o.o
uint64_t now_ts = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// find matches
Message3 matching_e = entt::null;
{
const auto view = reg.view<Message::Components::ToxGroupMessageID, Message::Components::ContactFrom, Message::Components::Timestamp>();
for (const auto ent : view.use<Message::Components::Timestamp>()) {
if (view.get<Message::Components::ToxGroupMessageID>(ent).id != e.message_id) {
continue;
}
// how far apart the 2 timestamps can be, before they are considered different messages
if (std::abs(int64_t(view.get<Message::Components::Timestamp>(ent).ts) - int64_t(sync_ts)) > _max_age_difference_ms) {
std::cout << "ZOX NGCHS info: same message id, but different timestamp\n";
continue;
}
const auto& ent_c = view.get<Message::Components::ContactFrom>(ent).c;
if (!(ent_c == sync_c)) {
std::cout << "ZOX NGCHS info: same message id, but different sender\n";
continue;
}
matching_e = ent;
break; // TODO: matching list
}
}
if (reg.valid(matching_e)) {
// TODO: do something else, like average?, trust mods more?
const bool has_tw = reg.all_of<Message::Components::TimestampWritten>(matching_e);
auto& msg_ts_w = reg.get_or_emplace<Message::Components::TimestampWritten>(matching_e, sync_ts);
if (has_tw) {
if (msg_ts_w.ts > sync_ts) {
msg_ts_w.ts = sync_ts;
reg.emplace_or_replace<Message::Components::Timestamp>(matching_e, sync_ts);
// TODO: resort
//_rmm.resort({ContactGroupEphemeral{e.group_number}});
_rmm.throwEventUpdate(reg, matching_e);
}
} else {
// TODO: actually, dont do anything?
// TODO: resort
//_rmm.resort({ContactGroupEphemeral{e.group_number}});
_rmm.throwEventUpdate(reg, matching_e);
}
} else {
// tmp, assume message new
matching_e = reg.create();
reg.emplace<Message::Components::ContactFrom>(matching_e, sync_c);
reg.emplace<Message::Components::ContactTo>(matching_e, sync_by_c.get<Contact::Components::Parent>().parent);
reg.emplace<Message::Components::ToxGroupMessageID>(matching_e, e.message_id);
reg.emplace<Message::Components::MessageText>(matching_e, e.message_text);
reg.emplace<Message::Components::TimestampProcessed>(matching_e, now_ts);
reg.emplace<Message::Components::TimestampWritten>(matching_e, sync_ts);
reg.emplace<Message::Components::Timestamp>(matching_e, sync_ts); // reactive?
// TODO: resort
//_rmm.resort({ContactGroupEphemeral{e.group_number}});
_rmm.throwEventConstruct(reg, matching_e);
}
{ // by whom
auto& synced_by = reg.get_or_emplace<Message::Components::SyncedBy>(matching_e).list;
synced_by.emplace(sync_by_c);
// TODO: throw update?
}
return true;
}
bool ZoxNGCHistorySync::onToxEvent(const Tox_Event_Group_Peer_Join* e) {
const auto group_number = tox_event_group_peer_join_get_group_number(e);
const auto peer_number = tox_event_group_peer_join_get_peer_id(e);
const auto c = _tcm.getContactGroupPeer(group_number, peer_number);
if (!_request_queue.count(c)) {
_request_queue[c] = {
_delay_before_first_request_min + _rng_dist(_rng)*_delay_before_first_request_add,
0.f,
130u // TODO: magic number
};
}
return false;
}

101
solanaceae/zox/ngc_hs.hpp Normal file
View File

@@ -0,0 +1,101 @@
#pragma once
#include "./ngc.hpp"
#include <solanaceae/contact/contact_model3.hpp>
#include <solanaceae/message3/registry_message_model.hpp>
#include <array>
#include <queue>
#include <map>
#include <random>
// fwd
struct ToxI;
struct ContactModelI;
class RegistryMessageModel;
class ToxContactModel2;
// zoff ngc history sync (draft1?)
// https://gist.github.com/zoff99/81917ddb2e55b2ce602cac4772a7b68c
class ZoxNGCHistorySync : public ToxEventI, public ZoxNGCEventI {
ToxEventProviderI& _tep;
ZoxNGCEventProviderI& _zngcepi;
ToxI& _t;
Contact3Registry& _cr;
ToxContactModel2& _tcm;
RegistryMessageModel& _rmm;
// how far apart the 2 timestamps can be, before they are considered different messages
const int64_t _max_age_difference_ms {130*60*1000}; // TODO: make this larger?
// 5s-11s
const float _delay_before_first_request_min {5.f};
const float _delay_before_first_request_add {6.f};
// 30m-64m
const float _delay_next_request_min {30.f*60.f};
const float _delay_next_request_add {64.f*60.f};
// 0.3s-0.6s
const float _delay_between_syncs_min {0.3f};
const float _delay_between_syncs_add {0.3f};
std::uniform_real_distribution<float> _rng_dist {0.0f, 1.0f};
std::minstd_rand _rng;
struct RequestQueueInfo {
float delay; // const
float timer;
uint8_t sync_delta;
};
// request queue
// c -> delay, timer
std::map<Contact3, RequestQueueInfo> _request_queue;
struct SyncQueueInfo {
float delay; // const
float timer;
std::queue<Message3> ents;
//std::reference_wrapper<Message1Registry> reg;
};
std::map<Contact3, SyncQueueInfo> _sync_queue;
// sync queue
void subscribeToEvents(void); // private
public:
ZoxNGCHistorySync(ToxEventProviderI& tep, ZoNGCEventProviderI& zngcepi, ToxI& t, Contact3Registry& cr, ToxContactModel2& tcm, RegistryMessageModel& rmm);
void tick(float delta);
public:
// always private
bool sendRequest(
uint32_t group_number, uint32_t peer_number,
uint8_t sync_delta = 130u
);
// always private
bool sendSyncMessage(
uint32_t group_number, uint32_t peer_number,
uint32_t message_id,
const std::array<uint8_t, 32>& sender_pub_key,
uint32_t timestamp,
std::string_view sender_name,
std::string_view message_text
);
protected:
bool onEvent(const Events::ZoxNGC_ngch_request& e) override;
bool onEvent(const Events::ZoxNGC_ngch_syncmsg& e) override;
protected:
bool onToxEvent(const Tox_Event_Group_Peer_Join* e) override;
//bool onToxEvent(const Tox_Event_Group_Peer_Exit* e) override;
//bool onToxEvent(const Tox_Event_Group_Custom_Packet* e) override;
//bool onToxEvent(const Tox_Event_Group_Custom_Private_Packet* e) override;
};