mod noop;
mod stream;
mod udp;
pub use noop::NoopSouthwardTransportMeter;
use std::{fmt::Debug, io::Result as IoResult, net::SocketAddr, sync::Arc};
pub use stream::MeteredStream;
use tokio::net::{TcpStream, UdpSocket};
use tokio::time::{timeout, Duration as TokioDuration};
use tokio_serial::{DataBits, Parity, SerialPortBuilderExt, SerialStream, StopBits};
pub use udp::MeteredUdpSocket;
pub trait SouthwardTransportMeter: Send + Sync + Debug {
fn add_bytes_in(&self, bytes: u64);
fn add_bytes_out(&self, bytes: u64);
}
#[inline]
#[allow(unused)]
pub async fn connect_tcp_metered(
addr: SocketAddr,
meter: Arc<dyn SouthwardTransportMeter>,
) -> IoResult<MeteredStream<TcpStream>> {
let stream = TcpStream::connect(addr).await?;
Ok(MeteredStream::new(stream, meter))
}
#[inline]
#[allow(unused)]
pub async fn connect_tcp_metered_with_timeout(
addr: SocketAddr,
meter: Arc<dyn SouthwardTransportMeter>,
connect_timeout_ms: u64,
) -> IoResult<MeteredStream<TcpStream>> {
let d = TokioDuration::from_millis(connect_timeout_ms.max(1));
match timeout(d, connect_tcp_metered(addr, meter)).await {
Ok(r) => r,
Err(_elapsed) => Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"tcp connect timeout",
)),
}
}
#[inline]
#[allow(unused)]
pub async fn bind_udp_metered(
bind_addr: SocketAddr,
meter: Arc<dyn SouthwardTransportMeter>,
) -> IoResult<MeteredUdpSocket> {
let sock = UdpSocket::bind(bind_addr).await?;
Ok(MeteredUdpSocket::new(sock, meter))
}
#[inline]
#[allow(unused)]
pub async fn bind_udp_metered_with_timeout(
bind_addr: SocketAddr,
meter: Arc<dyn SouthwardTransportMeter>,
bind_timeout_ms: u64,
) -> IoResult<MeteredUdpSocket> {
let d = TokioDuration::from_millis(bind_timeout_ms.max(1));
match timeout(d, bind_udp_metered(bind_addr, meter)).await {
Ok(r) => r,
Err(_elapsed) => Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
"udp bind timeout",
)),
}
}
#[derive(Clone, Debug)]
pub struct SerialConnectConfig {
pub port: String,
pub baud_rate: u32,
pub data_bits: DataBits,
pub stop_bits: StopBits,
pub parity: Parity,
}
#[inline]
#[allow(unused)]
pub fn connect_serial_metered(
cfg: SerialConnectConfig,
meter: Arc<dyn SouthwardTransportMeter>,
) -> IoResult<MeteredStream<SerialStream>> {
let stream = tokio_serial::new(cfg.port, cfg.baud_rate)
.data_bits(cfg.data_bits)
.stop_bits(cfg.stop_bits)
.parity(cfg.parity)
.open_native_async()?;
Ok(MeteredStream::new(stream, meter))
}