stream-tungstenite 0.6.1

A streaming implementation of the Tungstenite WebSocket protocol
Documentation
//! TCP transport implementation.

use async_trait::async_trait;
use tokio::net::TcpStream;

use super::traits::{Transport, TransportConfig};
use crate::error::ConnectError;

/// Plain TCP transport (no encryption)
#[derive(Debug, Clone)]
pub struct TcpTransport {
    config: TransportConfig,
}

impl TcpTransport {
    /// Create a new TCP transport with default configuration
    #[must_use]
    pub fn new() -> Self {
        Self {
            config: TransportConfig::default(),
        }
    }

    /// Create a TCP transport with custom configuration
    #[must_use]
    pub const fn with_config(config: TransportConfig) -> Self {
        Self { config }
    }

    /// Get the transport configuration
    #[must_use]
    pub const fn config(&self) -> &TransportConfig {
        &self.config
    }
}

impl Default for TcpTransport {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl Transport for TcpTransport {
    type Stream = TcpStream;

    async fn connect(&self, host: &str, port: u16) -> Result<Self::Stream, ConnectError> {
        let addr = format!("{host}:{port}");

        let stream = tokio::time::timeout(self.config.connect_timeout, TcpStream::connect(&addr))
            .await
            .map_err(|_| ConnectError::Timeout(self.config.connect_timeout))?
            .map_err(|e| {
                tracing::debug!(addr = %addr, error = ?e, "TCP connection failed");
                ConnectError::TcpConnect(e.to_string())
            })?;

        // Apply socket options
        if self.config.disable_nagle {
            stream.set_nodelay(true).map_err(|e| {
                tracing::warn!(error = ?e, "Failed to set TCP_NODELAY");
                ConnectError::Io(e.to_string())
            })?;
        }

        tracing::debug!(addr = %addr, "TCP connection established");
        Ok(stream)
    }

    fn name(&self) -> &'static str {
        "tcp"
    }

    fn default_port(&self) -> u16 {
        80
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_tcp_transport_creation() {
        let transport = TcpTransport::new();
        assert_eq!(transport.name(), "tcp");
        assert_eq!(transport.default_port(), 80);
    }

    #[test]
    fn test_tcp_transport_config() {
        let config = TransportConfig::low_latency();
        let transport = TcpTransport::with_config(config);
        assert!(transport.config().disable_nagle);
    }
}