|
| 1 | +//! # Transport Common Types |
| 2 | +//! |
| 3 | +//! Shared types and utilities used across all transport implementations. |
| 4 | +//! |
| 5 | +//! This module provides: |
| 6 | +//! |
| 7 | +//! - [`CorrelationId`] - UUID type for request correlation |
| 8 | +//! - [`Timestamp`] - Microsecond timestamp type |
| 9 | +//! - [`TransportType`] - Transport kind enumeration |
| 10 | +//! - [`TransportTypeDetector`] - Runtime transport detection |
| 11 | +//! - [`CorrelationIdGenerator`] - Trait for generating correlation IDs |
| 12 | +//! - [`TimestampGenerator`] - Trait for getting current timestamps |
| 13 | +
|
| 14 | +use serde::{Deserialize, Serialize}; |
| 15 | +use std::fmt; |
| 16 | +use std::time::{SystemTime, UNIX_EPOCH}; |
| 17 | + |
| 18 | +/// Correlation ID type. |
| 19 | +/// |
| 20 | +/// Used to uniquely identify requests and match responses to requests. |
| 21 | +pub type CorrelationId = String; |
| 22 | + |
| 23 | +/// Timestamp type. |
| 24 | +/// |
| 25 | +/// Represents time in microseconds since Unix epoch (1970-01-01 00:00:00 UTC). |
| 26 | +pub type Timestamp = u64; |
| 27 | + |
| 28 | +/// Generator trait for correlation IDs. |
| 29 | +/// |
| 30 | +/// This allows different ID generation strategies (UUID, sequential, etc.) |
| 31 | +/// to be injected for testing or special requirements. |
| 32 | +pub trait CorrelationIdGenerator { |
| 33 | + /// Generates a new unique correlation ID. |
| 34 | + fn generate() -> CorrelationId; |
| 35 | +} |
| 36 | + |
| 37 | +/// Default correlation ID generator using UUID v4. |
| 38 | +pub struct UuidCorrelationIdGenerator; |
| 39 | + |
| 40 | +impl CorrelationIdGenerator for UuidCorrelationIdGenerator { |
| 41 | + fn generate() -> CorrelationId { |
| 42 | + uuid::Uuid::new_v4().to_string() |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +/// Generator trait for timestamps. |
| 47 | +/// |
| 48 | +/// Allows time to be injected for testing (mock clocks) or obtained |
| 49 | +/// from system clocks. |
| 50 | +pub trait TimestampGenerator { |
| 51 | + /// Returns the current timestamp in microseconds since Unix epoch. |
| 52 | + fn now() -> Timestamp; |
| 53 | +} |
| 54 | + |
| 55 | +/// Default timestamp generator using system clock. |
| 56 | +pub struct SystemTimestampGenerator; |
| 57 | + |
| 58 | +impl TimestampGenerator for SystemTimestampGenerator { |
| 59 | + fn now() -> Timestamp { |
| 60 | + SystemTime::now() |
| 61 | + .duration_since(UNIX_EPOCH) |
| 62 | + .map(|d| d.as_micros() as Timestamp) |
| 63 | + .unwrap_or(0) |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +/// Transport type enumeration. |
| 68 | +/// |
| 69 | +/// Indicates which transport mechanism is being used or requested. |
| 70 | +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] |
| 71 | +pub enum TransportType { |
| 72 | + /// gRPC over HTTP/2 |
| 73 | + Grpc, |
| 74 | + /// Native inter-process communication (Unix sockets, named pipes) |
| 75 | + Ipc, |
| 76 | + /// WebAssembly/WebWorker transport (browser) |
| 77 | + Wasm, |
| 78 | + /// Unknown or unspecified transport |
| 79 | + Unknown, |
| 80 | +} |
| 81 | + |
| 82 | +impl TransportType { |
| 83 | + /// Returns the string representation of this transport type. |
| 84 | + pub fn as_str(&self) -> &'static str { |
| 85 | + match self { |
| 86 | + Self::Grpc => "grpc", |
| 87 | + Self::Ipc => "ipc", |
| 88 | + Self::Wasm => "wasm", |
| 89 | + Self::Unknown => "unknown", |
| 90 | + } |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +impl fmt::Display for TransportType { |
| 95 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 96 | + f.write_str(self.as_str()) |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +impl std::str::FromStr for TransportType { |
| 101 | + type Err = anyhow::Error; |
| 102 | + |
| 103 | + fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 104 | + match s.to_lowercase().as_str() { |
| 105 | + "grpc" => Ok(Self::Grpc), |
| 106 | + "ipc" => Ok(Self::Ipc), |
| 107 | + "wasm" => Ok(Self::Wasm), |
| 108 | + "unknown" => Ok(Self::Unknown), |
| 109 | + _ => Err(anyhow::anyhow!("Unknown transport type: {}", s)), |
| 110 | + } |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +/// Transport type detector. |
| 115 | +/// |
| 116 | +/// Provides runtime detection of the appropriate transport based on |
| 117 | +/// environment and capabilities. |
| 118 | +pub trait TransportTypeDetector { |
| 119 | + /// Detects the best available transport for the current environment. |
| 120 | + fn detect_best_transport() -> TransportType; |
| 121 | + |
| 122 | + /// Checks if a specific transport is available in the current environment. |
| 123 | + fn is_transport_available(transport_type: TransportType) -> bool; |
| 124 | + |
| 125 | + /// Lists all available transports in the current environment. |
| 126 | + fn list_available_transports() -> Vec<TransportType>; |
| 127 | +} |
| 128 | + |
| 129 | +/// Default transport detector using environment detection. |
| 130 | +pub struct DefaultTransportTypeDetector; |
| 131 | + |
| 132 | +impl TransportTypeDetector for DefaultTransportTypeDetector { |
| 133 | + fn detect_best_transport() -> TransportType { |
| 134 | + // Priority order based on environment: |
| 135 | + // - If in browser and WASM supported: WASM |
| 136 | + // - If same-process and IPC available: IPC |
| 137 | + // - Otherwise: gRPC |
| 138 | + |
| 139 | + #[cfg(target_arch = "wasm32")] |
| 140 | + { |
| 141 | + // In browser, prefer WASM |
| 142 | + TransportType::Wasm |
| 143 | + } |
| 144 | + |
| 145 | + #[cfg(not(target_arch = "wasm32"))] |
| 146 | + { |
| 147 | + // On desktop/server, check if we're in same process |
| 148 | + // For now, default to gRPC (cross-process) |
| 149 | + TransportType::Grpc |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + fn is_transport_available(transport_type: TransportType) -> bool { |
| 154 | + match transport_type { |
| 155 | + TransportType::Grpc => true, // gRPC always available |
| 156 | + TransportType::Ipc => { |
| 157 | + #[cfg(unix)] |
| 158 | + { |
| 159 | + true // Unix sockets available |
| 160 | + } |
| 161 | + #[cfg(windows)] |
| 162 | + { |
| 163 | + true // Named pipes available |
| 164 | + } |
| 165 | + } |
| 166 | + TransportType::Wasm => { |
| 167 | + #[cfg(target_arch = "wasm32")] |
| 168 | + { |
| 169 | + true |
| 170 | + } |
| 171 | + #[cfg(not(target_arch = "wasm32"))] |
| 172 | + { |
| 173 | + false // WASM not available outside browser |
| 174 | + } |
| 175 | + } |
| 176 | + TransportType::Unknown => false, |
| 177 | + } |
| 178 | + } |
| 179 | + |
| 180 | + fn list_available_transports() -> Vec<TransportType> { |
| 181 | + let mut available = Vec::new(); |
| 182 | + |
| 183 | + if Self::is_transport_available(TransportType::Grpc) { |
| 184 | + available.push(TransportType::Grpc); |
| 185 | + } |
| 186 | + if Self::is_transport_available(TransportType::Ipc) { |
| 187 | + available.push(TransportType::Ipc); |
| 188 | + } |
| 189 | + if Self::is_transport_available(TransportType::Wasm) { |
| 190 | + available.push(TransportType::Wasm); |
| 191 | + } |
| 192 | + |
| 193 | + available |
| 194 | + } |
| 195 | +} |
| 196 | + |
| 197 | +#[cfg(test)] |
| 198 | +mod tests { |
| 199 | + use super::*; |
| 200 | + |
| 201 | + #[test] |
| 202 | + fn test_transport_type_as_str() { |
| 203 | + assert_eq!(TransportType::Grpc.as_str(), "grpc"); |
| 204 | + assert_eq!(TransportType::Ipc.as_str(), "ipc"); |
| 205 | + assert_eq!(TransportType::Wasm.as_str(), "wasm"); |
| 206 | + assert_eq!(TransportType::Unknown.as_str(), "unknown"); |
| 207 | + } |
| 208 | + |
| 209 | + #[test] |
| 210 | + fn test_transport_type_from_str() { |
| 211 | + assert_eq!("grpc".parse().unwrap(), TransportType::Grpc); |
| 212 | + assert_eq!("ipc".parse().unwrap(), TransportType::Ipc); |
| 213 | + assert_eq!("wasm".parse().unwrap(), TransportType::Wasm); |
| 214 | + assert!("invalid".parse::<TransportType>().is_err()); |
| 215 | + } |
| 216 | + |
| 217 | + #[test] |
| 218 | + fn test_default_detector() { |
| 219 | + let available = DefaultTransportTypeDetector::list_available_transports(); |
| 220 | + // At minimum gRPC should be available |
| 221 | + assert!(available.contains(&TransportType::Grpc)); |
| 222 | + } |
| 223 | +} |
0 commit comments