coderlib 0.1.0

A Rust library for AI-powered code assistance and agentic system
Documentation
//! Transport factory for creating and managing MCP transports
//!
//! This module provides a unified factory interface for creating different
//! types of MCP transports with proper configuration and error handling.

use std::collections::HashMap;
use std::sync::Arc;

#[cfg(feature = "mcp")]
use rmcp::{RoleClient, RoleServer};

use super::{
    transport_enhanced::{EnhancedTransportConfig, TransportError},
    tcp::{TcpTransport, TcpServer, TcpClient},
    config::McpTransportConfig,
};

#[cfg(feature = "websocket")]
use super::websocket::{WebSocketTransport, WebSocketServer, WebSocketClient};

/// Transport factory for creating enhanced MCP transports
pub struct TransportFactory {
    /// Default configuration
    default_config: TransportFactoryConfig,
}

/// Configuration for the transport factory
#[derive(Debug, Clone)]
pub struct TransportFactoryConfig {
    /// Default timeout for connections
    pub connection_timeout: std::time::Duration,
    /// Default retry attempts
    pub retry_attempts: u32,
    /// Default retry delay
    pub retry_delay: std::time::Duration,
    /// Enable transport statistics
    pub enable_stats: bool,
}

impl Default for TransportFactoryConfig {
    fn default() -> Self {
        Self {
            connection_timeout: std::time::Duration::from_secs(30),
            retry_attempts: 3,
            retry_delay: std::time::Duration::from_millis(1000),
            enable_stats: true,
        }
    }
}

impl TransportFactory {
    /// Create a new transport factory with default configuration
    pub fn new() -> Self {
        Self {
            default_config: TransportFactoryConfig::default(),
        }
    }

    /// Create a transport factory with custom configuration
    pub fn with_config(config: TransportFactoryConfig) -> Self {
        Self {
            default_config: config,
        }
    }

    /// Create a client transport from configuration
    pub async fn create_client_transport(
        &self,
        config: &EnhancedTransportConfig,
    ) -> Result<Box<dyn ClientTransport>, TransportError> {
        match config {
            EnhancedTransportConfig::WebSocket { url, headers } => {
                #[cfg(feature = "websocket")]
                {
                    // Simplified for now - would use proper WebSocket client
                    Err(TransportError::UnsupportedTransport("WebSocket client not yet implemented".to_string()))
                }
                #[cfg(not(feature = "websocket"))]
                {
                    Err(TransportError::UnsupportedTransport("WebSocket feature not enabled".to_string()))
                }
            }
            EnhancedTransportConfig::Tcp { host: _, port: _ } => {
                // Simplified for now - would use proper TCP client
                Err(TransportError::UnsupportedTransport("TCP client not yet implemented".to_string()))
            }
            #[cfg(unix)]
            EnhancedTransportConfig::UnixSocket { path: _ } => {
                // Unix socket implementation would go here
                Err(TransportError::UnsupportedTransport("Unix socket transport not yet implemented".to_string()))
            }
            #[cfg(windows)]
            EnhancedTransportConfig::NamedPipe { name: _ } => {
                // Named pipe implementation would go here
                Err(TransportError::UnsupportedTransport("Named pipe transport not yet implemented".to_string()))
            }
        }
    }

    /// Create a server transport from configuration
    pub async fn create_server_transport(
        &self,
        config: &EnhancedTransportConfig,
    ) -> Result<Box<dyn ServerTransport>, TransportError> {
        match config {
            EnhancedTransportConfig::WebSocket { url, headers: _ } => {
                #[cfg(feature = "websocket")]
                {
                    // Simplified for now - would use proper WebSocket server
                    Err(TransportError::UnsupportedTransport("WebSocket server not yet implemented".to_string()))
                }
                #[cfg(not(feature = "websocket"))]
                {
                    Err(TransportError::UnsupportedTransport("WebSocket feature not enabled".to_string()))
                }
            }
            EnhancedTransportConfig::Tcp { host: _, port: _ } => {
                // Simplified for now - would use proper TCP server
                Err(TransportError::UnsupportedTransport("TCP server not yet implemented".to_string()))
            }
            #[cfg(unix)]
            EnhancedTransportConfig::UnixSocket { path: _ } => {
                // Unix socket implementation would go here
                Err(TransportError::UnsupportedTransport("Unix socket transport not yet implemented".to_string()))
            }
            #[cfg(windows)]
            EnhancedTransportConfig::NamedPipe { name: _ } => {
                // Named pipe implementation would go here
                Err(TransportError::UnsupportedTransport("Named pipe transport not yet implemented".to_string()))
            }
        }
    }

    /// Create a transport from legacy MCP configuration
    pub async fn create_from_legacy_config(
        &self,
        config: &McpTransportConfig,
    ) -> Result<Box<dyn ClientTransport>, TransportError> {
        match config {
            McpTransportConfig::Stdio { command: _, args: _ } => {
                // Stdio transport is not supported in enhanced transports
                Err(TransportError::UnsupportedTransport("Stdio transport not supported in enhanced mode".to_string()))
            }
            McpTransportConfig::Sse { url, headers } => {
                // Convert SSE to WebSocket (if possible) or return error
                if url.starts_with("http") {
                    let ws_url = url.replace("http", "ws");
                    let enhanced_config = EnhancedTransportConfig::WebSocket {
                        url: ws_url,
                        headers: headers.clone(),
                    };
                    self.create_client_transport(&enhanced_config).await
                } else {
                    Err(TransportError::UnsupportedTransport("SSE transport conversion failed".to_string()))
                }
            }
        }
    }

    /// Create a transport with retry logic
    pub async fn create_with_retry(
        &self,
        config: &EnhancedTransportConfig,
    ) -> Result<Box<dyn ClientTransport>, TransportError> {
        let mut last_error = None;
        
        for attempt in 0..self.default_config.retry_attempts {
            match self.create_client_transport(config).await {
                Ok(transport) => return Ok(transport),
                Err(e) => {
                    last_error = Some(e);
                    if attempt < self.default_config.retry_attempts - 1 {
                        tracing::warn!(
                            attempt = attempt + 1,
                            max_attempts = self.default_config.retry_attempts,
                            "Transport connection failed, retrying..."
                        );
                        tokio::time::sleep(self.default_config.retry_delay).await;
                    }
                }
            }
        }
        
        Err(last_error.unwrap_or_else(|| {
            TransportError::ConnectionFailed("All retry attempts failed".to_string())
        }))
    }

    /// Extract address from WebSocket URL for server binding
    fn extract_address_from_ws_url(&self, url: &str) -> Result<String, TransportError> {
        // Simple URL parsing for WebSocket URLs
        if let Some(url_without_scheme) = url.strip_prefix("ws://").or_else(|| url.strip_prefix("wss://")) {
            if let Some(host_port) = url_without_scheme.split('/').next() {
                return Ok(host_port.to_string());
            }
        }
        Err(TransportError::ConnectionFailed(format!("Invalid WebSocket URL: {}", url)))
    }
}

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

/// Trait for client-side transports
pub trait ClientTransport: Send + Sync {
    /// Get transport description
    fn description(&self) -> String;
    
    /// Check if connected
    fn is_connected(&self) -> bool;
    
    /// Get transport statistics
    fn stats(&self) -> super::transport_enhanced::TransportStats;
}

/// Trait for server-side transports
#[async_trait::async_trait]
pub trait ServerTransport: Send + Sync {
    /// Accept a new connection
    async fn accept(&self) -> Result<Box<dyn ClientTransport>, TransportError>;
    
    /// Get server description
    fn description(&self) -> String;
    
    /// Get local address (if applicable)
    fn local_addr(&self) -> Option<String>;
}

// Transport implementations removed for simplicity
// In a full implementation, these would properly implement the traits

/// Transport manager for managing multiple transports
pub struct TransportManager {
    factory: TransportFactory,
    active_transports: Arc<tokio::sync::RwLock<HashMap<String, Box<dyn ClientTransport>>>>,
}

impl TransportManager {
    /// Create a new transport manager
    pub fn new() -> Self {
        Self {
            factory: TransportFactory::new(),
            active_transports: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
        }
    }

    /// Add a transport with a given name
    pub async fn add_transport(
        &self,
        name: String,
        config: &EnhancedTransportConfig,
    ) -> Result<(), TransportError> {
        let transport = self.factory.create_client_transport(config).await?;
        self.active_transports.write().await.insert(name, transport);
        Ok(())
    }

    /// Get a transport by name
    pub async fn get_transport(&self, name: &str) -> Option<String> {
        let transports = self.active_transports.read().await;
        transports.get(name).map(|t| t.description())
    }

    /// Remove a transport
    pub async fn remove_transport(&self, name: &str) -> bool {
        self.active_transports.write().await.remove(name).is_some()
    }

    /// List all active transports
    pub async fn list_transports(&self) -> Vec<(String, String)> {
        let transports = self.active_transports.read().await;
        transports
            .iter()
            .map(|(name, transport)| (name.clone(), transport.description()))
            .collect()
    }
}

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

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

    #[test]
    fn test_factory_creation() {
        let factory = TransportFactory::new();
        assert_eq!(factory.default_config.retry_attempts, 3);
    }

    #[test]
    fn test_factory_config() {
        let config = TransportFactoryConfig {
            connection_timeout: std::time::Duration::from_secs(60),
            retry_attempts: 5,
            retry_delay: std::time::Duration::from_millis(2000),
            enable_stats: false,
        };
        let factory = TransportFactory::with_config(config);
        assert_eq!(factory.default_config.retry_attempts, 5);
    }

    #[tokio::test]
    async fn test_transport_manager() {
        let manager = TransportManager::new();
        let transports = manager.list_transports().await;
        assert!(transports.is_empty());
    }
}