287 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "./ngc_hs2_send.hpp"
 | |
| 
 | |
| #include <solanaceae/util/span.hpp>
 | |
| 
 | |
| #include <solanaceae/tox_contacts/tox_contact_model2.hpp>
 | |
| 
 | |
| #include <solanaceae/contact/components.hpp>
 | |
| 
 | |
| #include <iostream>
 | |
| 
 | |
| // https://www.youtube.com/watch?v=AdAqsgga3qo
 | |
| 
 | |
| namespace Components {
 | |
| 
 | |
| void IncommingInfoRequestQueue::queueRequest(const InfoRequest& new_request) {
 | |
| 	// TODO: do more than exact dedupe
 | |
| 	for (const auto& [ts_start, ts_end] : _queue) {
 | |
| 		if (ts_start == new_request.ts_start && ts_end == new_request.ts_end) {
 | |
| 			return; // already enqueued
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	_queue.push_back(new_request);
 | |
| }
 | |
| 
 | |
| void IncommingMsgRequestQueue::queueRequest(const SingleMessageRequest& new_request) {
 | |
| 	for (const auto& [ppk, mid, ts] : _queue) {
 | |
| 		if (mid == new_request.mid && ts == new_request.ts && ppk == new_request.ppk) {
 | |
| 			return; // already enqueued
 | |
| 		}
 | |
| 	}
 | |
| 	_queue.push_back(new_request);
 | |
| }
 | |
| 
 | |
| } // Components
 | |
| 
 | |
| 
 | |
| NGCHS2Send::NGCHS2Send(
 | |
| 	Contact3Registry& cr,
 | |
| 	RegistryMessageModelI& rmm,
 | |
| 	ToxContactModel2& tcm,
 | |
| 	NGCFT1& nft
 | |
| ) :
 | |
| 	_cr(cr),
 | |
| 	_rmm(rmm),
 | |
| 	_tcm(tcm),
 | |
| 	_nft(nft),
 | |
| 	_nftep_sr(_nft.newSubRef(this))
 | |
| {
 | |
| 	_nftep_sr
 | |
| 		.subscribe(NGCFT1_Event::recv_request)
 | |
| 		//.subscribe(NGCFT1_Event::recv_init) // we only send init
 | |
| 		//.subscribe(NGCFT1_Event::recv_data) // we only send data
 | |
| 		.subscribe(NGCFT1_Event::send_data)
 | |
| 		//.subscribe(NGCFT1_Event::recv_done)
 | |
| 		.subscribe(NGCFT1_Event::send_done)
 | |
| 	;
 | |
| }
 | |
| 
 | |
| NGCHS2Send::~NGCHS2Send(void) {
 | |
| }
 | |
| 
 | |
| float NGCHS2Send::iterate(float delta) {
 | |
| 	// limit how often we update here (new fts usually)
 | |
| 	if (_iterate_heat > 0.f) {
 | |
| 		_iterate_heat -= delta;
 | |
| 		return 1000.f;
 | |
| 	} else {
 | |
| 		_iterate_heat = _iterate_cooldown;
 | |
| 	}
 | |
| 
 | |
| 	// work request queue
 | |
| 	// check if already running, discard
 | |
| 
 | |
| 	auto fn_iirq = [this](auto&& view) {
 | |
| 		for (auto&& [cv, iirq] : view.each()) {
 | |
| 			Contact3Handle c{_cr, cv};
 | |
| 			auto& iirr = c.get_or_emplace<Components::IncommingInfoRequestRunning>();
 | |
| 
 | |
| 			// dedup queued from running
 | |
| 
 | |
| 			if (iirr._list.size() >= _max_parallel_per_peer) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			// new ft here?
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	auto fn_imrq = [this](auto&& view) {
 | |
| 		for (auto&& [cv, imrq] : view.each()) {
 | |
| 			Contact3Handle c{_cr, cv};
 | |
| 			auto& imrr = c.get_or_emplace<Components::IncommingMsgRequestRunning>();
 | |
| 
 | |
| 			// dedup queued from running
 | |
| 
 | |
| 			if (imrr._list.size() >= _max_parallel_per_peer) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			// new ft here?
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	// first handle range requests on weak self
 | |
| 	//for (auto&& [cv, iirq] : _cr.view<Contact::Components::TagSelfWeak, Components::IncommingInfoRequestQueue>().each()) {
 | |
| 	fn_iirq(_cr.view<Contact::Components::TagSelfWeak, Components::IncommingInfoRequestQueue>());
 | |
| 
 | |
| 	// then handle messages on weak self
 | |
| 	//for (auto&& [cv, imrq] : _cr.view<Contact::Components::TagSelfWeak, Components::IncommingMsgRequestQueue>().each()) {
 | |
| 	fn_imrq(_cr.view<Contact::Components::TagSelfWeak, Components::IncommingMsgRequestQueue>());
 | |
| 
 | |
| 	// we could stop here, if too much is already running
 | |
| 
 | |
| 	// then range on others
 | |
| 	//for (auto&& [cv, iirq] : _cr.view<Components::IncommingInfoRequestQueue>(entt::exclude_t<Contact::Components::TagSelfWeak>{}).each()) {
 | |
| 	fn_iirq(_cr.view<Components::IncommingInfoRequestQueue>(entt::exclude_t<Contact::Components::TagSelfWeak>{}));
 | |
| 
 | |
| 	// then messages on others
 | |
| 	//for (auto&& [cv, imrq] : _cr.view<Components::IncommingMsgRequestQueue>(entt::exclude_t<Contact::Components::TagSelfWeak>{}).each()) {
 | |
| 	fn_imrq(_cr.view<Components::IncommingMsgRequestQueue>(entt::exclude_t<Contact::Components::TagSelfWeak>{}));
 | |
| 
 | |
| 	return 1000.f;
 | |
| }
 | |
| 
 | |
| template<typename Type>
 | |
| static uint64_t deserlSimpleType(ByteSpan bytes) {
 | |
| 	if (bytes.size < sizeof(Type)) {
 | |
| 		throw int(1);
 | |
| 	}
 | |
| 
 | |
| 	Type value;
 | |
| 
 | |
| 	for (size_t i = 0; i < sizeof(Type); i++) {
 | |
| 		value |= Type(bytes[i]) << (i*8);
 | |
| 	}
 | |
| 
 | |
| 	return value;
 | |
| }
 | |
| 
 | |
| static uint32_t deserlMID(ByteSpan mid_bytes) {
 | |
| 	return deserlSimpleType<uint32_t>(mid_bytes);
 | |
| }
 | |
| 
 | |
| static uint64_t deserlTS(ByteSpan ts_bytes) {
 | |
| 	return deserlSimpleType<uint64_t>(ts_bytes);
 | |
| }
 | |
| 
 | |
| void NGCHS2Send::handleRange(Contact3Handle c, const Events::NGCFT1_recv_request& e) {
 | |
| 	ByteSpan fid{e.file_id, e.file_id_size};
 | |
| 	// TODO: better size check
 | |
| 	if (fid.size != sizeof(uint64_t)+sizeof(uint64_t)) {
 | |
| 		std::cerr << "NGCHS2S error: range not lange enough\n";
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// seconds
 | |
| 	uint64_t ts_start{0};
 | |
| 	uint64_t ts_end{0};
 | |
| 
 | |
| 	// parse
 | |
| 	try {
 | |
| 		ByteSpan ts_start_bytes{fid.ptr, sizeof(uint64_t)};
 | |
| 		ts_start = deserlTS(ts_start_bytes);
 | |
| 
 | |
| 		ByteSpan ts_end_bytes{ts_start_bytes.ptr+ts_start_bytes.size, sizeof(uint64_t)};
 | |
| 		ts_end = deserlTS(ts_end_bytes);
 | |
| 	} catch (...) {
 | |
| 		std::cerr << "NGCHS2S error: failed to parse range\n";
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// dedupe insert into queue
 | |
| 	// how much overlap do we allow?
 | |
| 	c.get_or_emplace<Components::IncommingInfoRequestQueue>().queueRequest({
 | |
| 		ts_start,
 | |
| 		ts_end,
 | |
| 	});
 | |
| }
 | |
| 
 | |
| void NGCHS2Send::handleSingleMessage(Contact3Handle c, const Events::NGCFT1_recv_request& e) {
 | |
| 	ByteSpan fid{e.file_id, e.file_id_size};
 | |
| 	// TODO: better size check
 | |
| 	if (fid.size != 32+sizeof(uint32_t)+sizeof(uint64_t)) {
 | |
| 		std::cerr << "NGCHS2S error: singlemessage not lange enough\n";
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	ByteSpan ppk;
 | |
| 	uint32_t mid {0};
 | |
| 	uint64_t ts {0}; // deciseconds
 | |
| 
 | |
| 	// parse
 | |
| 	try {
 | |
| 		// - ppk
 | |
| 		// TOX_GROUP_PEER_PUBLIC_KEY_SIZE (32)
 | |
| 		ppk = {fid.ptr, 32};
 | |
| 
 | |
| 		// - mid
 | |
| 		ByteSpan mid_bytes{fid.ptr+ppk.size, sizeof(uint32_t)};
 | |
| 		mid = deserlMID(mid_bytes);
 | |
| 
 | |
| 		// - ts
 | |
| 		ByteSpan ts_bytes{mid_bytes.ptr+mid_bytes.size, sizeof(uint64_t)};
 | |
| 		ts = deserlTS(ts_bytes);
 | |
| 	} catch (...) {
 | |
| 		std::cerr << "NGCHS2S error: failed to parse singlemessage\n";
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// file content
 | |
| 	// - message type (text/textaction/file(ft1sha1))
 | |
| 	// - if text/textaction
 | |
| 	//   - text (string)
 | |
| 	// - else if file
 | |
| 	//   - file type
 | |
| 	//   - file id
 | |
| 
 | |
| 	// for queue, we need group, peer, msg_ppk, msg_mid, msg_ts
 | |
| 
 | |
| 	// dedupe insert into queue
 | |
| 	c.get_or_emplace<Components::IncommingMsgRequestQueue>().queueRequest({
 | |
| 		ppk,
 | |
| 		mid,
 | |
| 		ts,
 | |
| 	});
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Message::Events::MessageConstruct&) {
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Message::Events::MessageUpdated&) {
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Message::Events::MessageDestory&) {
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Events::NGCFT1_recv_request& e) {
 | |
| 	if (
 | |
| 		e.file_kind != NGCFT1_file_kind::HS2_INFO_RANGE_TIME &&
 | |
| 		e.file_kind != NGCFT1_file_kind::HS2_SINGLE_MESSAGE
 | |
| 	) {
 | |
| 		return false; // not for us
 | |
| 	}
 | |
| 
 | |
| 	// TODO: when is it done from queue?
 | |
| 
 | |
| 	auto c = _tcm.getContactGroupPeer(e.group_number, e.peer_number);
 | |
| 	if (!c) {
 | |
| 		return false; // how
 | |
| 	}
 | |
| 
 | |
| 	// is other peer allowed to make requests
 | |
| 	//bool quick_allow {false};
 | |
| 	bool quick_allow {true}; // HACK: disable all restrictions for this early test
 | |
| 	// TODO: quick deny?
 | |
| 	{
 | |
| 		//  - tagged as weakself
 | |
| 		if (!quick_allow && c.all_of<Contact::Components::TagSelfWeak>()) {
 | |
| 			quick_allow = true;
 | |
| 		}
 | |
| 
 | |
| 		//  - sub perm level??
 | |
| 		//  - out of max time range (ft specific, not a quick_allow)
 | |
| 	}
 | |
| 
 | |
| 	if (e.file_kind == NGCFT1_file_kind::HS2_INFO_RANGE_TIME) {
 | |
| 		handleRange(c, e);
 | |
| 	} else if (e.file_kind == NGCFT1_file_kind::HS2_SINGLE_MESSAGE) {
 | |
| 		handleSingleMessage(c, e);
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Events::NGCFT1_send_data&) {
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| bool NGCHS2Send::onEvent(const Events::NGCFT1_send_done&) {
 | |
| 	return false;
 | |
| }
 | |
| 
 |