use async_trait::async_trait;
use std::io;
use tokio::io::{AsyncRead, AsyncWrite};
#[cfg(feature = "async-client")]
pub mod tcp;
#[cfg(feature = "tls")]
pub mod tls;
#[cfg(feature = "quic")]
pub mod quic;
#[cfg(feature = "rustls-tls")]
pub mod rustls_tls;
#[derive(Debug, thiserror::Error)]
pub enum TransportError {
#[error("Connection failed: {0}")]
ConnectionFailed(String),
#[error("IO error: {0}")]
Io(#[from] io::Error),
#[cfg(any(feature = "tls", feature = "rustls-tls"))]
#[error("TLS error: {0}")]
Tls(String),
#[cfg(feature = "quic")]
#[error("QUIC error: {0}")]
Quic(String),
#[error("Transport not supported: {0}")]
NotSupported(String),
#[error("Invalid address: {0}")]
InvalidAddress(String),
}
pub fn parse_mqtt_address(addr: &str) -> Result<(String, String), TransportError> {
let addr = addr.trim_start_matches("mqtts://");
if let Some((host, port)) = addr.rsplit_once(':') {
Ok((host.to_string(), format!("{}:{}", host, port)))
} else {
Err(TransportError::InvalidAddress(format!(
"Invalid address format: '{}'. Expected 'host:port' or 'mqtts://host:port'",
addr
)))
}
}
#[async_trait]
pub trait Transport: AsyncRead + AsyncWrite + Send + Sync + Unpin {
async fn connect(addr: &str) -> Result<Self, TransportError>
where
Self: Sized;
async fn close(&mut self) -> Result<(), TransportError>;
fn peer_addr(&self) -> Result<String, TransportError>;
fn local_addr(&self) -> Result<String, TransportError>;
fn set_nodelay(&self, _nodelay: bool) -> Result<(), TransportError> {
Ok(()) }
}
pub type BoxedTransport = Box<dyn Transport>;
#[cfg(feature = "async-client")]
pub use tcp::TcpTransport;
#[cfg(feature = "tls")]
pub use tls::TlsTransport;
#[cfg(feature = "rustls-tls")]
pub use rustls_tls::{RustlsTlsConfig, RustlsTlsTransport};