use tracing::Span;
use tokio::{
sync::broadcast,
task
};
use crate::message::Packet;
use crate::peer::Address;
use crate::util::*;
use super::InterfaceAddress;
use super::chacha20;
#[derive(Debug)]
pub struct Interface {
address: InterfaceAddress,
channel: Option<Sender<PktTo>>
}
pub enum InterfaceLauncher {
Chacha20Udp(chacha20::Server),
Dummy(DummyServer)
}
pub enum Terminated {
Shutdown,
Crashed(String),
Panic
}
#[derive(Clone, Debug)]
struct PktFromTo {
pub to: Address,
pub from: Address,
pub pkt: Packet
}
pub struct DummyServer {
address: usize,
pkt_bus: broadcast::Sender<PktFromTo>
}
impl std::fmt::Debug for InterfaceLauncher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Chacha20Udp(server) => {
write!(f, "Chacha20Udp @ {}", server.get_address())
},
Self::Dummy(server) => {
write!(f, "DummyServer @ {}", server.get_address())
}
}
}
}
impl InterfaceLauncher {
pub fn get_address(&self) -> InterfaceAddress {
match self {
Self::Chacha20Udp(server) => server.get_address(),
Self::Dummy(server) => server.get_address()
}
}
pub fn spawn(
self,
channel: ServerChannel,
span: &Span)
-> task::JoinHandle<Terminated>
{
match self {
Self::Chacha20Udp(server) => {
let address = server.get_address();
trace!(:span, %address, "spawned chacha20 task");
task::spawn(server.launch(channel))
},
Self::Dummy(server) => {
let address = server.get_address();
trace!(:span, %address, "spawned dummy server task");
task::spawn(server.run(channel))
}
}
}
}
impl Interface {
pub fn new(address: InterfaceAddress, channel: Sender<PktTo>) -> Self {
Self {address, channel: Some(channel)}
}
pub fn shutdown(&mut self) {
self.channel.take();
}
pub fn replace_address(&mut self, address: InterfaceAddress) {
self.address = address;
}
pub fn get_address(&self) -> Address {
self.address.get_address()
}
pub fn get_interface_address(&self) -> InterfaceAddress {
self.address.clone()
}
pub fn can_send(&self, address: Address) -> bool {
self.address.can_send(address)
}
pub fn send(&self, pkt: PktTo) {
if let Some(channel) = self.channel.as_ref() {
let _ = channel.send(pkt);
}
}
}
impl std::fmt::Display for Interface {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.address.fmt(f)
}
}
impl DummyServer {
async fn observe(mut pkt_bus: broadcast::Receiver<PktFromTo>) {
while let Ok(pkt) = pkt_bus.recv().await {
println!("{} → {} : {:?}", pkt.from, pkt.to, pkt.pkt);
}
}
pub fn create_n(n: usize)
-> (Vec<Self>, task::JoinHandle<()>)
{
let dummy_bus = broadcast::channel::<PktFromTo>(1024).0;
let dummies = (0..n)
.map(|address| Self { address, pkt_bus: dummy_bus.clone()})
.collect();
let observer_handle = task::spawn(
Self::observe(dummy_bus.subscribe())
);
(dummies, observer_handle)
}
pub fn get_address(&self) -> InterfaceAddress {
InterfaceAddress::Dummy(self.address)
}
pub async fn run(self, channel: ServerChannel) -> Terminated {
let (inbound_pkt_tx, mut outbound_pkt_rx) = channel.split();
let mut bus_receiver = self.pkt_bus.subscribe();
println!("dummy {} running", self.address);
loop { tokio::select! {
r = bus_receiver.recv() => { match r {
Ok(pkt) if pkt.to == Address::Dummy(self.address) => {
println!("{} received pkt from {}", pkt.to, pkt.from);
let _ = inbound_pkt_tx.send(Self::strip_to(pkt));
},
Ok(pkt) => {
println!(
"{} ignoring pkt for {} from {}",
self.address,
pkt.to,
pkt.from
);
},
Err(_) => break,
}},
p = outbound_pkt_rx.recv() => { match p {
Some(p) => {
let _ = self.pkt_bus.send(self.add_from(p));
},
None => break
}}
}}
Terminated::Shutdown
}
fn add_from(&self, pkt_to: PktTo) -> PktFromTo {
PktFromTo {
from: Address::Dummy(self.address),
to: pkt_to.0,
pkt: pkt_to.1
}
}
fn strip_to(pkt_from_to: PktFromTo) -> PktFrom {
(pkt_from_to.from, pkt_from_to.pkt)
}
}