use crate::{error::TransportError, packet::Packet, SessionId};
use tokio::sync::oneshot;
#[derive(Debug)]
pub enum TransportCommand {
Send {
session_id: SessionId,
packet: Packet,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
Close {
session_id: SessionId,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
Configure {
config: ConfigUpdate,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
GetStats {
response_tx: oneshot::Sender<TransportStats>,
},
GetConnectionInfo {
session_id: SessionId,
response_tx: oneshot::Sender<Result<ConnectionInfo, TransportError>>,
},
GetActiveSessions {
response_tx: oneshot::Sender<Vec<SessionId>>,
},
ForceDisconnect {
session_id: SessionId,
reason: String,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
PauseSession {
session_id: SessionId,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
ResumeSession {
session_id: SessionId,
response_tx: oneshot::Sender<Result<(), TransportError>>,
},
}
#[derive(Debug)]
pub enum ConfigUpdate {
BufferSize(usize),
Timeout(std::time::Duration),
MaxConnections(usize),
Protocol(Box<dyn std::any::Any + Send>),
}
#[derive(Debug, Clone)]
pub struct TransportStats {
pub packets_sent: u64,
pub packets_received: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
pub active_connections: u64,
pub total_connections: u64,
pub errors: u64,
pub start_time: std::time::SystemTime,
pub last_activity: std::time::SystemTime,
}
impl Default for TransportStats {
fn default() -> Self {
let now = std::time::SystemTime::now();
Self {
packets_sent: 0,
packets_received: 0,
bytes_sent: 0,
bytes_received: 0,
active_connections: 0,
total_connections: 0,
errors: 0,
start_time: now,
last_activity: now,
}
}
}
impl TransportStats {
pub fn new() -> Self {
Default::default()
}
pub fn update_activity(&mut self) {
self.last_activity = std::time::SystemTime::now();
}
pub fn record_packet_sent(&mut self, size: usize) {
self.packets_sent += 1;
self.bytes_sent += size as u64;
self.update_activity();
}
pub fn record_packet_received(&mut self, size: usize) {
self.packets_received += 1;
self.bytes_received += size as u64;
self.update_activity();
}
pub fn record_connection_opened(&mut self) {
self.active_connections += 1;
self.total_connections += 1;
self.update_activity();
}
pub fn record_connection_closed(&mut self) {
if self.active_connections > 0 {
self.active_connections -= 1;
}
self.update_activity();
}
pub fn record_error(&mut self) {
self.errors += 1;
self.update_activity();
}
pub fn uptime(&self) -> std::time::Duration {
self.start_time.elapsed().unwrap_or_default()
}
pub fn idle_time(&self) -> std::time::Duration {
self.last_activity.elapsed().unwrap_or_default()
}
}
#[derive(Debug, Clone)]
pub struct ConnectionInfo {
pub session_id: SessionId,
pub local_addr: std::net::SocketAddr,
pub peer_addr: std::net::SocketAddr,
pub protocol: String,
pub state: ConnectionState,
pub established_at: std::time::SystemTime,
pub closed_at: Option<std::time::SystemTime>,
pub last_activity: std::time::SystemTime,
pub packets_sent: u64,
pub packets_received: u64,
pub bytes_sent: u64,
pub bytes_received: u64,
}
impl Default for ConnectionInfo {
fn default() -> Self {
let now = std::time::SystemTime::now();
Self {
session_id: SessionId::new(0),
local_addr: "0.0.0.0:0".parse().unwrap(),
peer_addr: "0.0.0.0:0".parse().unwrap(),
protocol: "tcp".to_string(),
state: ConnectionState::Connecting,
established_at: now,
closed_at: None,
last_activity: now,
packets_sent: 0,
packets_received: 0,
bytes_sent: 0,
bytes_received: 0,
}
}
}
impl ConnectionInfo {
pub fn update_activity(&mut self) {
self.last_activity = std::time::SystemTime::now();
}
pub fn record_packet_sent(&mut self, size: usize) {
self.packets_sent += 1;
self.bytes_sent += size as u64;
self.update_activity();
}
pub fn record_packet_received(&mut self, size: usize) {
self.packets_received += 1;
self.bytes_received += size as u64;
self.update_activity();
}
pub fn connection_duration(&self) -> std::time::Duration {
self.established_at.elapsed().unwrap_or_default()
}
pub fn idle_duration(&self) -> std::time::Duration {
self.last_activity.elapsed().unwrap_or_default()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectionState {
Connecting,
Connected,
Closing,
Closed,
Paused,
Error,
}
impl std::fmt::Display for ConnectionState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConnectionState::Connecting => write!(f, "Connecting"),
ConnectionState::Connected => write!(f, "Connected"),
ConnectionState::Closing => write!(f, "Closing"),
ConnectionState::Closed => write!(f, "Closed"),
ConnectionState::Paused => write!(f, "Paused"),
ConnectionState::Error => write!(f, "Error"),
}
}
}
pub trait ProtocolCommand: Send + std::fmt::Debug + 'static {
type Response: Send;
fn into_transport_command(self) -> TransportCommand;
fn execute(self) -> impl std::future::Future<Output = Self::Response> + Send;
}
pub struct CommandBuilder;
impl CommandBuilder {
pub fn send(
session_id: SessionId,
packet: Packet,
) -> (
TransportCommand,
oneshot::Receiver<Result<(), TransportError>>,
) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::Send {
session_id,
packet,
response_tx,
};
(command, response_rx)
}
pub fn close(
session_id: SessionId,
) -> (
TransportCommand,
oneshot::Receiver<Result<(), TransportError>>,
) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::Close {
session_id,
response_tx,
};
(command, response_rx)
}
pub fn get_stats() -> (TransportCommand, oneshot::Receiver<TransportStats>) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::GetStats { response_tx };
(command, response_rx)
}
pub fn get_connection_info(
session_id: SessionId,
) -> (
TransportCommand,
oneshot::Receiver<Result<ConnectionInfo, TransportError>>,
) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::GetConnectionInfo {
session_id,
response_tx,
};
(command, response_rx)
}
pub fn get_active_sessions() -> (TransportCommand, oneshot::Receiver<Vec<SessionId>>) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::GetActiveSessions { response_tx };
(command, response_rx)
}
pub fn force_disconnect(
session_id: SessionId,
reason: String,
) -> (
TransportCommand,
oneshot::Receiver<Result<(), TransportError>>,
) {
let (response_tx, response_rx) = oneshot::channel();
let command = TransportCommand::ForceDisconnect {
session_id,
reason,
response_tx,
};
(command, response_rx)
}
}
pub struct CommandExecutor;
impl CommandExecutor {
pub async fn send_and_wait(
command_tx: &tokio::sync::mpsc::Sender<TransportCommand>,
session_id: SessionId,
packet: Packet,
) -> Result<(), TransportError> {
let (command, response_rx) = CommandBuilder::send(session_id, packet);
command_tx
.send(command)
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))?;
response_rx
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))?
}
pub async fn close_and_wait(
command_tx: &tokio::sync::mpsc::Sender<TransportCommand>,
session_id: SessionId,
) -> Result<(), TransportError> {
let (command, response_rx) = CommandBuilder::close(session_id);
command_tx
.send(command)
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))?;
response_rx
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))?
}
pub async fn get_stats(
command_tx: &tokio::sync::mpsc::Sender<TransportCommand>,
) -> Result<TransportStats, TransportError> {
let (command, response_rx) = CommandBuilder::get_stats();
command_tx
.send(command)
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))?;
response_rx
.await
.map_err(|_| TransportError::connection_error("Channel closed", false))
}
}