use super::packet::Opcode;
use crate::utils::clock::Instant;
use std::collections::{BTreeMap, VecDeque};
use std::time::Duration;
pub const MAX_ACK_ARRAY: usize = 4;
pub const SEND_WINDOW: usize = 4;
pub const RECV_WINDOW: u32 = 8;
pub const MAX_CONTROL_PAYLOAD: usize = 1100;
const INITIAL_RETRANSMIT: Duration = Duration::from_millis(1000);
const MAX_RETRANSMIT: Duration = Duration::from_secs(8);
pub const MAX_ATTEMPTS: u32 = 8;
const MAX_PENDING_ACKS: usize = 64;
const MAX_BUFFERED: usize = RECV_WINDOW as usize;
#[derive(Debug, Clone)]
pub struct Outgoing {
pub packet_id: u32,
pub opcode: Opcode,
pub acks: Vec<u32>,
pub payload: Vec<u8>,
sent_at: Option<Instant>,
attempts: u32,
}
impl Outgoing {
fn due_at(&self) -> Option<Instant> {
let sent = self.sent_at?;
let mut backoff = INITIAL_RETRANSMIT;
for _ in 1..self.attempts {
backoff = (backoff * 2).min(MAX_RETRANSMIT);
}
Some(sent + backoff)
}
}
pub struct ReliableSender {
next_packet_id: u32,
outgoing: VecDeque<Outgoing>,
}
impl ReliableSender {
pub fn new() -> Self {
ReliableSender {
next_packet_id: 0,
outgoing: VecDeque::new(),
}
}
pub fn queue(&mut self, opcode: Opcode, acks: Vec<u32>, payload: Vec<u8>) -> u32 {
let packet_id = self.next_packet_id;
self.next_packet_id = self.next_packet_id.wrapping_add(1);
self.outgoing.push_back(Outgoing {
packet_id,
opcode,
acks,
payload,
sent_at: None,
attempts: 0,
});
packet_id
}
pub fn on_ack(&mut self, ids: &[u32]) {
if ids.is_empty() {
return;
}
self.outgoing.retain(|o| !ids.contains(&o.packet_id));
}
pub fn take_due(&mut self, now: Instant) -> Vec<Outgoing> {
let mut due = Vec::new();
for entry in self.outgoing.iter_mut().take(SEND_WINDOW) {
let ready = match entry.due_at() {
None => true,
Some(at) => at <= now,
};
if ready {
entry.sent_at = Some(now);
entry.attempts = entry.attempts.saturating_add(1);
due.push(entry.clone());
}
}
due
}
pub fn mark_all_due(&mut self) {
for entry in self.outgoing.iter_mut() {
entry.sent_at = None;
}
}
pub fn is_exhausted(&self) -> bool {
self.outgoing.iter().any(|o| o.attempts >= MAX_ATTEMPTS)
}
pub fn in_flight(&self) -> usize {
self.outgoing.len()
}
}
impl Default for ReliableSender {
fn default() -> Self {
Self::new()
}
}
pub struct ReliableReceiver {
next_expected: u32,
buffered: BTreeMap<u32, Vec<u8>>,
pending_acks: VecDeque<u32>,
}
impl ReliableReceiver {
pub fn new(next_expected: u32) -> Self {
ReliableReceiver {
next_expected,
buffered: BTreeMap::new(),
pending_acks: VecDeque::new(),
}
}
pub fn accept(&mut self, packet_id: u32, payload: Vec<u8>) -> Vec<Vec<u8>> {
if packet_id < self.next_expected {
self.note_ack(packet_id);
return Vec::new();
}
if packet_id.saturating_sub(self.next_expected) >= RECV_WINDOW {
return Vec::new();
}
self.note_ack(packet_id);
if packet_id > self.next_expected {
if self.buffered.len() < MAX_BUFFERED {
self.buffered.entry(packet_id).or_insert(payload);
}
return Vec::new();
}
let mut delivered = vec![payload];
self.next_expected = self.next_expected.wrapping_add(1);
while let Some(next) = self.buffered.remove(&self.next_expected) {
delivered.push(next);
self.next_expected = self.next_expected.wrapping_add(1);
}
delivered
}
fn note_ack(&mut self, packet_id: u32) {
if self.pending_acks.contains(&packet_id) {
return;
}
if self.pending_acks.len() >= MAX_PENDING_ACKS {
self.pending_acks.pop_front();
}
self.pending_acks.push_back(packet_id);
}
pub fn take_acks(&mut self) -> Vec<u32> {
let n = self.pending_acks.len().min(MAX_ACK_ARRAY);
self.pending_acks.drain(..n).collect()
}
pub fn has_pending_acks(&self) -> bool {
!self.pending_acks.is_empty()
}
pub fn next_expected(&self) -> u32 {
self.next_expected
}
}
pub fn fragment(data: &[u8]) -> Vec<Vec<u8>> {
data.chunks(MAX_CONTROL_PAYLOAD)
.map(|c| c.to_vec())
.collect()
}