2 Commits

Author SHA1 Message Date
2e6b15e4ad more hs drafting 2024-11-01 11:31:05 +01:00
63de78aaeb add spec draft to repo 2024-10-31 15:46:48 +01:00
7 changed files with 146 additions and 41 deletions

View File

@ -61,10 +61,6 @@ struct CCAI {
// returns -1 if not implemented, can return 0
virtual int64_t inFlightBytes(void) const { return -1; }
// returns -1 if not implemented, can return 0
// excluded timed out packets (not those currently resent)
virtual int64_t inFlightBytesAccounted(void) const { return -1; }
public: // callbacks
// data size is without overhead
virtual void onSent(SeqIDType seq, size_t data_size) = 0;

View File

@ -93,8 +93,7 @@ int64_t CUBIC::canSend(float time_delta) {
}
const auto window = getCWnD();
//int64_t cspace_bytes = window - _in_flight_bytes;
int64_t cspace_bytes = window - _in_flight_bytes_accounted;
int64_t cspace_bytes = window - _in_flight_bytes;
if (cspace_bytes < MAXIMUM_SEGMENT_DATA_SIZE) {
//std::cerr << "CUBIC: cspace < seg size\n";
return 0u;

View File

@ -29,25 +29,6 @@ void FlowOnly::updateWindow(void) {
_fwnd = std::max(_fwnd, 2.f * MAXIMUM_SEGMENT_DATA_SIZE);
}
void FlowOnly::updateAccounted(void) {
int64_t size_timedout {0};
{ // can be expensive
// code see getTimeouts()
// after 3 rtt delay, we trigger timeout
const auto now_adjusted = getTimeNow() - getCurrentDelay()*3.f;
for (const auto& [seq, time_stamp, size, _] : _in_flight) {
if (now_adjusted > time_stamp) {
//list.push_back(seq);
size_timedout += size;
}
}
}
_in_flight_bytes_accounted = _in_flight_bytes - size_timedout;
}
void FlowOnly::updateCongestion(void) {
updateWindow();
const auto tmp_window = getWindow();
@ -89,10 +70,8 @@ int64_t FlowOnly::canSend(float time_delta) {
}
updateWindow();
updateAccounted();
//int64_t fspace = _fwnd - _in_flight_bytes;
int64_t fspace = _fwnd - _in_flight_bytes_accounted;
int64_t fspace = _fwnd - _in_flight_bytes;
if (fspace < MAXIMUM_SEGMENT_DATA_SIZE) {
return 0u;
}
@ -128,10 +107,6 @@ int64_t FlowOnly::inFlightBytes(void) const {
return _in_flight_bytes;
}
int64_t FlowOnly::inFlightBytesAccounted(void) const {
return _in_flight_bytes_accounted;
}
void FlowOnly::onSent(SeqIDType seq, size_t data_size) {
if constexpr (true) {
size_t sum {0u};

View File

@ -32,7 +32,6 @@ struct FlowOnly : public CCAI {
};
std::vector<FlyingBunch> _in_flight;
int64_t _in_flight_bytes {0};
int64_t _in_flight_bytes_accounted {0};
int32_t _consecutive_events {0};
@ -59,8 +58,6 @@ struct FlowOnly : public CCAI {
void updateWindow(void);
void updateAccounted(void);
virtual void onCongestion(void) {};
// internal logic, calls the onCongestion() event
@ -80,7 +77,6 @@ struct FlowOnly : public CCAI {
int64_t inFlightCount(void) const override;
int64_t inFlightBytes(void) const override;
int64_t inFlightBytesAccounted(void) const override;
public: // callbacks
// data size is without overhead

View File

@ -3,15 +3,26 @@
#include <solanaceae/tox_contacts/tox_contact_model2.hpp>
NGCHS2::NGCHS2(
Contact3Registry& cr,
RegistryMessageModelI& rmm,
ToxContactModel2& tcm,
ToxEventProviderI& tep,
NGCFT1& nft
) :
_cr(cr),
_rmm(rmm),
_rmm_sr(_rmm.newSubRef(this)),
_tcm(tcm),
_tep_sr(tep.newSubRef(this)),
_nft(nft),
_nftep_sr(_nft.newSubRef(this))
{
_rmm_sr
.subscribe(RegistryMessageModel_Event::message_construct)
.subscribe(RegistryMessageModel_Event::message_updated)
.subscribe(RegistryMessageModel_Event::message_destroy)
;
_tep_sr
.subscribe(TOX_EVENT_GROUP_PEER_JOIN)
.subscribe(TOX_EVENT_GROUP_PEER_EXIT)
@ -35,6 +46,18 @@ float NGCHS2::iterate(float delta) {
return 1000.f;
}
bool NGCHS2::onEvent(const Message::Events::MessageConstruct&) {
return false;
}
bool NGCHS2::onEvent(const Message::Events::MessageUpdated&) {
return false;
}
bool NGCHS2::onEvent(const Message::Events::MessageDestory&) {
return false;
}
bool NGCHS2::onEvent(const Events::NGCFT1_recv_request& e) {
if (
e.file_kind != NGCFT1_file_kind::HS2_INFO_RANGE_TIME &&

View File

@ -1,25 +1,55 @@
#pragma once
//#include <solanaceae/contact/contact_model3.hpp>
#include <solanaceae/toxcore/tox_event_interface.hpp>
//#include <solanaceae/message3/registry_message_model.hpp>
#include <solanaceae/contact/contact_model3.hpp>
#include <solanaceae/message3/registry_message_model.hpp>
#include <solanaceae/ngc_ft1/ngcft1.hpp>
#include <entt/container/dense_map.hpp>
// fwd
class ToxContactModel2;
class NGCHS2 : public ToxEventI, public NGCFT1EventI {
// time ranges
// should we just do last x minutes like zngchs?
// properly done, we need to use:
// - Message::Components::ViewCurserBegin
// - Message::Components::ViewCurserEnd
//
// on startup, manually check all registries for ranges (meh) (do later)
// listen on message events, check if range, see if range satisfied recently
// deal with a queue, and delay (at least 1sec, 3-10sec after a peer con change)
// or we always overrequest (eg 48h), and only fetch messages in, or close to range
class NGCHS2 : public RegistryMessageModelEventI, public ToxEventI, public NGCFT1EventI {
Contact3Registry& _cr;
RegistryMessageModelI& _rmm;
RegistryMessageModelI::SubscriptionReference _rmm_sr;
ToxContactModel2& _tcm;
//Contact3Registry& _cr;
//RegistryMessageModelI& _rmm;
ToxEventProviderI::SubscriptionReference _tep_sr;
NGCFT1& _nft;
NGCFT1EventProviderI::SubscriptionReference _nftep_sr;
// describes our knowlage of a remote peer
struct RemoteInfo {
// list of all ppk+mid+ts they sent us (filtered by reqs, like range, ppk...)
// with when it last sent a range? hmm
};
entt::dense_map<Contact3, RemoteInfo> _remote_info;
// open/running info requests (by c)
// open/running info responses (by c)
static const bool _only_send_self_observed {true};
static const int64_t _max_time_into_past_default {60}; // s
public:
NGCHS2(
Contact3Registry& cr,
RegistryMessageModelI& rmm,
ToxContactModel2& tcm,
ToxEventProviderI& tep,
NGCFT1& nf
@ -29,6 +59,15 @@ class NGCHS2 : public ToxEventI, public NGCFT1EventI {
float iterate(float delta);
// add to queue with timer
// check and updates all existing cursers for giving reg in queue
void enqueueWantCurser(Message3Handle m);
protected:
bool onEvent(const Message::Events::MessageConstruct&) override;
bool onEvent(const Message::Events::MessageUpdated&) override;
bool onEvent(const Message::Events::MessageDestory&) override;
protected:
bool onEvent(const Events::NGCFT1_recv_request&) override;
bool onEvent(const Events::NGCFT1_recv_init&) override;

View File

@ -0,0 +1,77 @@
# [NGC] Group-History-Sync (v2) [PoC] [Draft]
Simple group history sync that uses `peer public key` + `message_id` + `timestamp` (`ppk+mid+ts`) to, mostly, uniquely identify messages and deliver them.
## Requirements
TODO
### File transfers
For sending packs of messages. A single message can be larger than a single custom packet, so this is a must-have.
## Procedure
Peer A can request `ppk+mid+ts` list for a given time range from peer B.
Peer B then sends a filetransfer (with special file type) of list of `ppk+mid+ts`.
Optionally compressed. (Delta-coding / zstd)
Peer A keeps doing that until the desired time span is covered.
After that or simultaniously, Peer A requests messages from peer B, either indivitually, or packed? in ranges?.
Optionally compressed.
During all that, peer B usually does the same thing to peer A.
## Traffic savings
It is recomended to remember if a range has been requested and answered from a given peer, to reduce traffic.
While compression is optional, it is recommended.
## Message uniqueness
This protocol relies on the randomness of `message_id` and the clocks to be more or less synchronized.
However, `message_id` can be manipulated freely by any peer, this can make messages appear as duplicates.
This can be used here, if you don't wish your messages to be syncronized (to an extent).
## Security
Only sync publicly sent/recieved messages.
Only allow sync or extended time ranges from peers you trust (enough).
The default shall be to not offer any messages.
Indirect messages shall be low in credibility, while direct synced (by author), with mid credibility.
Either only high or mid credibility shall be sent.
Manual exceptions to all can be made at the users discretion, eg for other self owned devices.
## File transfer requests
TODO: is reusing the ft request api a good idea for this?
| fttype | name | content (ft id) |
|------------|------|---------------------|
| 0x00000f00 | time range | - ts start </br> - ts end </br> - supported compression? |
| | TODO: id range based request? | |
| 0x00000f01 | single message | - ppk </br> - mid </br> - ts |
## File transfers
| fttype | name | content |
|------------|------|---------------------|
| 0x00000f00 | time range | - feature bitset (1byte? different compressions?) </br> - ts start </br> - ts end </br> - list size </br> \\+ entry `ppk` </br> \\+ entry `mid` </br> \\+ entry `ts` |
| 0x00000f01 | single message | - message type (text/textaction/file) </br> - text if text or action, file type and file id if file |
## TODO
- [ ] figure out a pro-active approach (instead of waiting for a range request)
- [ ] compression in the ft layer? (would make it reusable) hint/autodetect?