#![allow(unused)]
use crate::{
error::ChannelError,
runtime::{Runtime, UdpSocket as _},
};
use futures::{
future::{select, Either},
Stream,
};
use thingbuf::mpsc::{channel, Receiver, Sender};
use alloc::{vec, vec::Vec};
use core::{
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
pin::{pin, Pin},
task::{Context, Poll},
};
const CHANNEL_SIZE: usize = 512usize;
#[derive(Clone)]
struct Datagram {
datagram: Vec<u8>,
target: SocketAddr,
}
impl Default for Datagram {
fn default() -> Self {
Self {
datagram: Vec::new(),
target: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080)),
}
}
}
pub struct UdpSocketHandle {
local_address: Option<SocketAddr>,
rx: Receiver<Datagram>,
tx: Sender<Datagram>,
}
impl UdpSocketHandle {
pub fn try_send_to(
&mut self,
datagram: Vec<u8>,
target: SocketAddr,
) -> Result<(), ChannelError> {
self.tx.try_send(Datagram { datagram, target }).map_err(From::from)
}
pub fn local_address(&self) -> Option<SocketAddr> {
self.local_address
}
}
impl Stream for UdpSocketHandle {
type Item = (Vec<u8>, SocketAddr);
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(
futures::ready!(self.rx.poll_recv(cx))
.map(|Datagram { datagram, target }| (datagram, target)),
)
}
}
pub struct UdpSocket<R: Runtime> {
rx: Receiver<Datagram>,
socket: R::UdpSocket,
tx: Sender<Datagram>,
}
impl<R: Runtime> UdpSocket<R> {
pub fn new(socket: R::UdpSocket) -> (Self, UdpSocketHandle) {
let (recv_tx, recv_rx) = channel(CHANNEL_SIZE);
let (send_tx, send_rx) = channel(CHANNEL_SIZE);
let local_address = socket.local_address();
(
Self {
rx: send_rx,
socket,
tx: recv_tx,
},
UdpSocketHandle {
local_address,
rx: recv_rx,
tx: send_tx,
},
)
}
pub async fn run(mut self) {
let mut buffer = vec![0u8; 8192];
loop {
let result =
match select(pin!(self.socket.recv_from(&mut buffer)), self.rx.recv()).await {
Either::Left((Some((size, address)), _)) => Either::Left((size, address)),
Either::Right((Some(Datagram { datagram, target }), _)) =>
Either::Right((datagram, target)),
_ => return,
};
if match result {
Either::Left((size, address)) => self
.tx
.send(Datagram {
datagram: buffer[..size].to_vec(),
target: address,
})
.await
.ok(),
Either::Right((datagram, target)) =>
self.socket.send_to(&datagram, target).await.map(|_| ()),
}
.is_none()
{
return;
}
}
}
}