Skip to main content

boxlite_shared/
transport.rs

1//! Transport types for host-guest communication.
2
3use std::path::PathBuf;
4
5/// Transport mechanism for host-guest communication.
6///
7/// Represents the underlying connection type used by both host (to connect)
8/// and guest (to listen).
9#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
10pub enum Transport {
11    /// TCP transport
12    Tcp { port: u16 },
13
14    /// Unix socket transport
15    Unix { socket_path: PathBuf },
16
17    /// Vsock transport (guest-specific)
18    Vsock { port: u32 },
19}
20
21impl Transport {
22    /// Create a TCP transport.
23    pub fn tcp(port: u16) -> Self {
24        Self::Tcp { port }
25    }
26
27    /// Create a Unix socket transport.
28    pub fn unix(socket_path: PathBuf) -> Self {
29        Self::Unix { socket_path }
30    }
31
32    /// Create a Vsock transport.
33    pub fn vsock(port: u32) -> Self {
34        Self::Vsock { port }
35    }
36
37    /// Get the URI representation of this transport.
38    pub fn to_uri(&self) -> String {
39        match self {
40            Transport::Tcp { port } => format!("tcp://127.0.0.1:{}", port),
41            Transport::Unix { socket_path } => format!("unix://{}", socket_path.display()),
42            Transport::Vsock { port } => format!("vsock://{}", port),
43        }
44    }
45
46    /// Parse a transport from a URI string.
47    pub fn from_uri(uri: &str) -> Result<Self, String> {
48        if let Some(rest) = uri.strip_prefix("tcp://") {
49            let port = rest
50                .split(':')
51                .nth(1)
52                .ok_or_else(|| format!("invalid TCP URI '{}': missing port", uri))?
53                .parse::<u16>()
54                .map_err(|e| format!("invalid TCP port in '{}': {}", uri, e))?;
55            Ok(Self::tcp(port))
56        } else if let Some(path) = uri.strip_prefix("unix://") {
57            Ok(Self::unix(PathBuf::from(path)))
58        } else if let Some(port_str) = uri.strip_prefix("vsock://") {
59            let port = port_str
60                .parse::<u32>()
61                .map_err(|e| format!("invalid vsock port in '{}': {}", uri, e))?;
62            Ok(Self::vsock(port))
63        } else {
64            Err(format!(
65                "invalid transport URI '{}': expected tcp://, unix://, or vsock://",
66                uri
67            ))
68        }
69    }
70}
71
72impl std::fmt::Display for Transport {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(f, "{}", self.to_uri())
75    }
76}
77
78impl std::str::FromStr for Transport {
79    type Err = String;
80
81    fn from_str(s: &str) -> Result<Self, Self::Err> {
82        Self::from_uri(s)
83    }
84}