use crate::endpoint::Endpoint;
use std::fmt;
#[derive(Debug, Clone)]
pub enum SocketEvent {
Connected(Endpoint),
Disconnected(Endpoint),
Bound(Endpoint),
BindFailed { endpoint: Endpoint, reason: String },
ConnectFailed { endpoint: Endpoint, reason: String },
Listening(Endpoint),
Accepted(Endpoint),
}
impl fmt::Display for SocketEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Connected(ep) => write!(f, "Connected to {ep}"),
Self::Disconnected(ep) => write!(f, "Disconnected from {ep}"),
Self::Bound(ep) => write!(f, "Bound to {ep}"),
Self::BindFailed { endpoint, reason } => {
write!(f, "Bind failed for {endpoint}: {reason}")
}
Self::ConnectFailed { endpoint, reason } => {
write!(f, "Connect failed for {endpoint}: {reason}")
}
Self::Listening(ep) => write!(f, "Listening on {ep}"),
Self::Accepted(ep) => write!(f, "Accepted connection from {ep}"),
}
}
}
pub type SocketMonitor = flume::Receiver<SocketEvent>;
pub type SocketEventSender = flume::Sender<SocketEvent>;
pub const MONITOR_CHANNEL_CAP: usize = 256;
#[must_use]
pub fn create_monitor() -> (SocketEventSender, SocketMonitor) {
flume::bounded(MONITOR_CHANNEL_CAP)
}
pub fn emit(sender: &SocketEventSender, event: SocketEvent) {
let _ = sender.try_send(event);
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::SocketAddr;
#[test]
fn test_socket_event_display() {
let addr: SocketAddr = "127.0.0.1:5555".parse().unwrap();
let event = SocketEvent::Connected(Endpoint::Tcp(addr));
assert_eq!(event.to_string(), "Connected to tcp://127.0.0.1:5555");
}
#[test]
fn test_monitor_channel() {
let (sender, receiver) = create_monitor();
let addr: SocketAddr = "127.0.0.1:5555".parse().unwrap();
emit(&sender, SocketEvent::Connected(Endpoint::Tcp(addr)));
let event = receiver.recv().unwrap();
assert!(matches!(event, SocketEvent::Connected(_)));
}
#[test]
fn emit_is_bounded_and_never_blocks_when_undrained() {
let (sender, receiver) = create_monitor();
let addr: SocketAddr = "127.0.0.1:5555".parse().unwrap();
for _ in 0..(MONITOR_CHANNEL_CAP * 4) {
emit(&sender, SocketEvent::Connected(Endpoint::Tcp(addr)));
}
assert_eq!(
receiver.len(),
MONITOR_CHANNEL_CAP,
"monitor channel must stay bounded at its cap when undrained"
);
}
}