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};
pub struct TransportFactory {
default_config: TransportFactoryConfig,
}
#[derive(Debug, Clone)]
pub struct TransportFactoryConfig {
pub connection_timeout: std::time::Duration,
pub retry_attempts: u32,
pub retry_delay: std::time::Duration,
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 {
pub fn new() -> Self {
Self {
default_config: TransportFactoryConfig::default(),
}
}
pub fn with_config(config: TransportFactoryConfig) -> Self {
Self {
default_config: config,
}
}
pub async fn create_client_transport(
&self,
config: &EnhancedTransportConfig,
) -> Result<Box<dyn ClientTransport>, TransportError> {
match config {
EnhancedTransportConfig::WebSocket { url, headers } => {
#[cfg(feature = "websocket")]
{
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: _ } => {
Err(TransportError::UnsupportedTransport("TCP client not yet implemented".to_string()))
}
#[cfg(unix)]
EnhancedTransportConfig::UnixSocket { path: _ } => {
Err(TransportError::UnsupportedTransport("Unix socket transport not yet implemented".to_string()))
}
#[cfg(windows)]
EnhancedTransportConfig::NamedPipe { name: _ } => {
Err(TransportError::UnsupportedTransport("Named pipe transport not yet implemented".to_string()))
}
}
}
pub async fn create_server_transport(
&self,
config: &EnhancedTransportConfig,
) -> Result<Box<dyn ServerTransport>, TransportError> {
match config {
EnhancedTransportConfig::WebSocket { url, headers: _ } => {
#[cfg(feature = "websocket")]
{
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: _ } => {
Err(TransportError::UnsupportedTransport("TCP server not yet implemented".to_string()))
}
#[cfg(unix)]
EnhancedTransportConfig::UnixSocket { path: _ } => {
Err(TransportError::UnsupportedTransport("Unix socket transport not yet implemented".to_string()))
}
#[cfg(windows)]
EnhancedTransportConfig::NamedPipe { name: _ } => {
Err(TransportError::UnsupportedTransport("Named pipe transport not yet implemented".to_string()))
}
}
}
pub async fn create_from_legacy_config(
&self,
config: &McpTransportConfig,
) -> Result<Box<dyn ClientTransport>, TransportError> {
match config {
McpTransportConfig::Stdio { command: _, args: _ } => {
Err(TransportError::UnsupportedTransport("Stdio transport not supported in enhanced mode".to_string()))
}
McpTransportConfig::Sse { url, headers } => {
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()))
}
}
}
}
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())
}))
}
fn extract_address_from_ws_url(&self, url: &str) -> Result<String, TransportError> {
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()
}
}
pub trait ClientTransport: Send + Sync {
fn description(&self) -> String;
fn is_connected(&self) -> bool;
fn stats(&self) -> super::transport_enhanced::TransportStats;
}
#[async_trait::async_trait]
pub trait ServerTransport: Send + Sync {
async fn accept(&self) -> Result<Box<dyn ClientTransport>, TransportError>;
fn description(&self) -> String;
fn local_addr(&self) -> Option<String>;
}
pub struct TransportManager {
factory: TransportFactory,
active_transports: Arc<tokio::sync::RwLock<HashMap<String, Box<dyn ClientTransport>>>>,
}
impl TransportManager {
pub fn new() -> Self {
Self {
factory: TransportFactory::new(),
active_transports: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
}
}
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(())
}
pub async fn get_transport(&self, name: &str) -> Option<String> {
let transports = self.active_transports.read().await;
transports.get(name).map(|t| t.description())
}
pub async fn remove_transport(&self, name: &str) -> bool {
self.active_transports.write().await.remove(name).is_some()
}
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());
}
}