use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::atomic::AtomicBool;
use bytes::BytesMut;
use parking_lot::Mutex;
use tokio::sync::broadcast;
use crate::config::{Lane, ShapeConfig};
use crate::error::Error;
use crate::frame::{random_cover, ID_SIZE};
pub const SUBSCRIBER_CAPACITY: usize = 1024;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Target {
Unicast(SocketAddr),
Broadcast,
}
#[derive(Clone, Debug)]
pub struct PendingFrame {
pub bytes: BytesMut,
pub target: Target,
}
pub struct Shaper {
config: ShapeConfig,
incoming: broadcast::Sender<BytesMut>,
high_lane: Mutex<VecDeque<PendingFrame>>,
low_lane: Mutex<VecDeque<PendingFrame>>,
shutting_down: AtomicBool,
}
impl Shaper {
pub fn new(config: &ShapeConfig) -> Self {
assert!(
config.high_lane_capacity > 0,
"high_lane_capacity must be non-zero",
);
assert!(
config.low_lane_capacity > 0,
"low_lane_capacity must be non-zero",
);
let (incoming, _) = broadcast::channel(SUBSCRIBER_CAPACITY);
Self {
config: config.clone(),
incoming,
high_lane: Mutex::new(VecDeque::with_capacity(config.high_lane_capacity)),
low_lane: Mutex::new(VecDeque::with_capacity(config.low_lane_capacity)),
shutting_down: AtomicBool::new(false),
}
}
pub fn config(&self) -> &ShapeConfig {
&self.config
}
pub fn incoming(&self) -> broadcast::Sender<BytesMut> {
self.incoming.clone()
}
pub fn shutting_down(&self) -> &AtomicBool {
&self.shutting_down
}
pub fn enqueue(
&self,
lane: Lane,
target: Target,
payload: &[u8],
) -> Result<[u8; ID_SIZE], Error> {
let max_payload = self.config.frame_size - ID_SIZE;
if payload.len() > max_payload {
return Err(Error::PayloadTooLarge {
size: payload.len(),
max: max_payload,
});
}
let (id, msg) = crate::frame::build_frame(&self.config, payload);
self.enqueue_raw(lane, target, msg)?;
Ok(id)
}
pub fn enqueue_raw(&self, lane: Lane, target: Target, frame: BytesMut) -> Result<(), Error> {
if frame.len() != self.config.frame_size {
return Err(Error::FrameSizeMismatch {
size: frame.len(),
expected: self.config.frame_size,
});
}
let pframe = PendingFrame {
bytes: frame,
target,
};
match lane {
Lane::High => {
let mut l = self.high_lane.lock();
if l.len() >= self.config.high_lane_capacity {
return Err(Error::LaneFull);
}
l.push_back(pframe);
}
Lane::Low => {
let mut l = self.low_lane.lock();
while l.len() >= self.config.low_lane_capacity {
l.pop_back();
}
l.push_front(pframe);
}
}
Ok(())
}
pub fn next_frame(&self) -> Option<PendingFrame> {
if let Some(f) = self.high_lane.lock().pop_front() {
return Some(f);
}
self.low_lane.lock().pop_front()
}
pub fn queued(&self) -> usize {
self.high_lane.lock().len() + self.low_lane.lock().len()
}
pub fn cover(&self) -> PendingFrame {
PendingFrame {
bytes: random_cover(&self.config),
target: Target::Broadcast,
}
}
pub fn handle_incoming(&self, message: BytesMut) {
if message.len() != self.config.frame_size {
return;
}
let _ = self.incoming.send(message);
}
}