use std::net::SocketAddr;
use tokio::{
net::UdpSocket,
sync::mpsc::{Receiver, Sender},
};
use crate::{
msg::{Addr, YgwMessage},
LinkStatus, Result, YgwError, YgwLinkNodeProperties, YgwNode,
};
use async_trait::async_trait;
pub struct TcUdpNode {
props: YgwLinkNodeProperties,
socket: UdpSocket,
}
#[async_trait]
impl YgwNode for TcUdpNode {
fn properties(&self) -> &crate::YgwLinkNodeProperties {
&self.props
}
fn sub_links(&self) -> &[crate::Link] {
&[]
}
async fn run(
self: Box<Self>,
node_id: u32,
tx: Sender<YgwMessage>,
mut rx: Receiver<YgwMessage>,
) -> Result<()> {
let addr = Addr::new(node_id, 0);
let mut link_status = LinkStatus::new(addr);
link_status.send(&tx).await?;
while let Some(msg) = rx.recv().await {
match msg {
YgwMessage::Tc(_id, pc) => match pc.binary {
Some(ref cmd_binary) => {
link_status.data_out(1, cmd_binary.len() as u64);
log::debug!("Sending command {:?}", pc);
if let Err(err) = self.socket.send(&cmd_binary[..]).await {
log::warn!("Got error when sending command {:?}", err);
}
}
None => log::warn!("Command has no binary {:?}", pc),
},
_ => log::warn!("Got unexpected message {:?}", msg),
};
link_status.send(&tx).await?;
}
log::debug!("TC UDP node exiting");
Ok(())
}
}
impl TcUdpNode {
pub async fn new(name: &str, description: &str, addr: SocketAddr) -> Result<Self> {
let socket = UdpSocket::bind("0.0.0.0:0")
.await
.map_err(|e| YgwError::IOError("Cannot bind to 0.0.0.0:0".into(), e))?;
socket
.connect(addr)
.await
.map_err(|e| YgwError::IOError(format!("Cannot connect to {addr}"), e))?;
let props = YgwLinkNodeProperties::new(name, description).tc(true);
Ok(Self { socket, props })
}
}