diff options
| -rw-r--r-- | crates/utils/tcp_connection/src/error.rs | 24 | ||||
| -rw-r--r-- | crates/utils/tcp_connection/src/instance.rs | 11 | ||||
| -rw-r--r-- | crates/utils/tcp_connection/src/target_configure.rs | 51 | ||||
| -rw-r--r-- | crates/utils/tcp_connection/src/target_connection.rs | 63 |
4 files changed, 149 insertions, 0 deletions
diff --git a/crates/utils/tcp_connection/src/error.rs b/crates/utils/tcp_connection/src/error.rs new file mode 100644 index 0000000..02f96e3 --- /dev/null +++ b/crates/utils/tcp_connection/src/error.rs @@ -0,0 +1,24 @@ +#[derive(Default, Clone, Eq, PartialEq)] +pub struct TcpTargetError { + msg: String, +} + +impl<'a> std::fmt::Display for TcpTargetError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.msg) + } +} + +impl<'a> From<&'a str> for TcpTargetError { + fn from(value: &'a str) -> Self { + Self { + msg: value.to_string(), + } + } +} + +impl<'a> From<String> for TcpTargetError { + fn from(value: String) -> Self { + Self { msg: value } + } +} diff --git a/crates/utils/tcp_connection/src/instance.rs b/crates/utils/tcp_connection/src/instance.rs new file mode 100644 index 0000000..7f8cfce --- /dev/null +++ b/crates/utils/tcp_connection/src/instance.rs @@ -0,0 +1,11 @@ +use tokio::net::TcpStream; + +pub struct ConnectionInstance { + stream: TcpStream, +} + +impl From<TcpStream> for ConnectionInstance { + fn from(value: TcpStream) -> Self { + Self { stream: value } + } +} diff --git a/crates/utils/tcp_connection/src/target_configure.rs b/crates/utils/tcp_connection/src/target_configure.rs new file mode 100644 index 0000000..09c4d0d --- /dev/null +++ b/crates/utils/tcp_connection/src/target_configure.rs @@ -0,0 +1,51 @@ +#[derive(Default, Debug, Clone, Copy)] +pub struct ServerTargetConfig { + /// Only process a single connection, then shut down the server. + once: bool, + + /// Timeout duration in milliseconds. (0 is Closed) + timeout: u64, +} + +impl ServerTargetConfig { + /// Set `once` to True + /// This method configures the `once` field of `ServerTargetConfig`. + pub fn once(mut self) -> Self { + self.once = true; + self + } + + /// Set `timeout` to the given value + /// This method configures the `timeout` field of `ServerTargetConfig`. + pub fn timeout(mut self, timeout: u64) -> Self { + self.timeout = timeout; + self + } + + /// Set `once` to the given value + /// This method configures the `once` field of `ServerTargetConfig`. + pub fn set_once(&mut self, enable: bool) { + self.once = enable; + } + + /// Set `timeout` to the given value + /// This method configures the `timeout` field of `ServerTargetConfig`. + pub fn set_timeout(&mut self, timeout: u64) { + self.timeout = timeout; + } + + /// Check if the server is configured to process only a single connection. + /// Returns `true` if the server will shut down after processing one connection. + pub fn is_once(&self) -> bool { + self.once + } + + /// Get the current timeout value in milliseconds. + /// Returns the timeout duration. A value of 0 indicates the connection is closed. + pub fn get_timeout(&self) -> u64 { + self.timeout + } +} + +#[derive(Default, Debug, Clone, Copy)] +pub struct ClientTargetConfig {} diff --git a/crates/utils/tcp_connection/src/target_connection.rs b/crates/utils/tcp_connection/src/target_connection.rs new file mode 100644 index 0000000..1e25edd --- /dev/null +++ b/crates/utils/tcp_connection/src/target_connection.rs @@ -0,0 +1,63 @@ +use tokio::{net::TcpListener, spawn}; + +use crate::{ + error::TcpTargetError, + handle::{ClientHandle, ServerHandle}, + instance::ConnectionInstance, + target::TcpServerTarget, + target_configure::ServerTargetConfig, +}; + +impl<Client, Server> TcpServerTarget<Client, Server> +where + Client: ClientHandle<Server>, + Server: ServerHandle<Client>, +{ + pub async fn connect(&self) -> Result<(), TcpTargetError> { + Ok(()) + } + + pub async fn listen(&self) -> Result<(), TcpTargetError> { + let addr = self.get_addr(); + let listener = match TcpListener::bind(addr.clone()).await { + Ok(listener) => listener, + Err(_) => { + let err = format!("Bind to `{}` failed", addr); + return Err(TcpTargetError::from(err)); + } + }; + + let cfg: ServerTargetConfig = match self.get_server_cfg() { + Some(cfg) => cfg.clone(), + None => ServerTargetConfig::default(), + }; + + if cfg.is_once() { + let (stream, _) = match listener.accept().await { + Ok(result) => result, + Err(e) => { + let err = format!("Accept connection failed: {}", e); + return Err(TcpTargetError::from(err)); + } + }; + let instance = ConnectionInstance::from(stream); + Server::process(instance).await; + } else { + loop { + let (stream, _) = match listener.accept().await { + Ok(result) => result, + Err(e) => { + let err = format!("Accept connection failed: {}", e); + return Err(TcpTargetError::from(err)); + } + }; + let instance = ConnectionInstance::from(stream); + spawn(async move { + Server::process(instance).await; + }); + } + } + + Ok(()) + } +} |
