1#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
2use std::{
9 collections::{HashMap, HashSet},
10 sync::Arc,
11 time::Duration,
12};
13
14use super::{
15 Common::{DefaultTransportTypeDetector, TransportType, TransportTypeDetector},
16 TransportError::TransportError,
17 TransportStrategy::{TransportMetrics, TransportStrategy as CommonTransportStrategy},
18};
19
20pub struct TransportSelector {
22 #[allow(dead_code)]
24 EnvironmentDetector:Box<dyn TransportTypeDetector + Send + Sync>,
25 PriorityOrder:Vec<TransportType>,
27}
28
29impl TransportSelector {
30 pub fn New() -> Self {
32 Self {
33 EnvironmentDetector:Box::new(DefaultTransportTypeDetector),
34 PriorityOrder:Self::DefaultPriorityOrder(),
35 }
36 }
37
38 pub fn WithDetector(Detector:Box<dyn TransportTypeDetector + Send + Sync>) -> Self {
40 Self { EnvironmentDetector:Detector, PriorityOrder:Self::DefaultPriorityOrder() }
41 }
42
43 fn DefaultPriorityOrder() -> Vec<TransportType> {
45 let mut Order = Vec::new();
46
47 #[cfg(target_arch = "wasm32")]
48 {
49 Order.push(TransportType::Wasm);
50 Order.push(TransportType::Grpc);
51 }
52
53 #[cfg(not(target_arch = "wasm32"))]
54 {
55 Order.push(TransportType::Ipc);
56 Order.push(TransportType::Grpc);
57 }
58
59 Order
60 }
61
62 pub fn SelectBest(&self, Context:&TransportContext) -> Result<String, TransportError> {
64 let mut Candidates = Vec::new();
65
66 for TransportKind in self.PriorityOrder.iter() {
67 if !Context.TransportAvailable(*TransportKind) {
68 continue;
69 }
70
71 if !Context.IsAllowed(*TransportKind) {
72 continue;
73 }
74
75 let Score = self.CalculateScore(*TransportKind, Context);
76 Candidates.push((*TransportKind, Score));
77 }
78
79 Candidates.sort_by(|Left, Right| Right.1.total_cmp(&Left.1));
80
81 Candidates
82 .first()
83 .map(|(TransportKind, _)| TransportKind.AsString().to_string())
84 .ok_or_else(|| TransportError::NotFound("No suitable transport available for current context"))
85 }
86
87 fn CalculateScore(&self, TransportKind:TransportType, Context:&TransportContext) -> f64 {
89 let mut Score = 0.0;
90
91 if let Some(Position) = self.PriorityOrder.iter().position(|Kind| *Kind == TransportKind) {
92 Score += (self.PriorityOrder.len() - Position) as f64 * 10.0;
93 }
94
95 let Environment = Context.Environment();
96 match (Environment.IsWeb, TransportKind) {
97 (true, TransportType::Wasm) => Score += 50.0,
98 (false, TransportType::Ipc) => Score += 40.0,
99 _ => {},
100 }
101
102 let Requirements = Context.Requirements();
103 if Requirements.StreamingRequired {
104 match TransportKind {
105 TransportType::Grpc => Score += 30.0,
106 TransportType::Wasm => Score += 20.0,
107 TransportType::Ipc => Score -= 20.0,
108 TransportType::Unknown => {},
109 }
110 }
111
112 if Requirements.CrossNetwork {
113 match TransportKind {
114 TransportType::Grpc => Score += 50.0,
115 TransportType::Ipc => Score -= 50.0,
116 TransportType::Wasm => Score += 10.0,
117 TransportType::Unknown => {},
118 }
119 }
120
121 Score += match Requirements.Performance {
122 PerformanceLevel::Critical => {
123 match TransportKind {
124 TransportType::Ipc => 40.0,
125 TransportType::Grpc => 20.0,
126 TransportType::Wasm => 0.0,
127 TransportType::Unknown => 0.0,
128 }
129 },
130 PerformanceLevel::High => {
131 match TransportKind {
132 TransportType::Ipc => 30.0,
133 TransportType::Grpc => 20.0,
134 TransportType::Wasm => 10.0,
135 TransportType::Unknown => 0.0,
136 }
137 },
138 PerformanceLevel::Medium => 10.0,
139 PerformanceLevel::Low => 0.0,
140 };
141
142 if let Some(MaximumLatency) = Requirements.MaximumLatencyMilliseconds {
143 let EstimatedLatency = self.EstimateLatencyMilliseconds(TransportKind);
144 if EstimatedLatency <= MaximumLatency {
145 Score += 20.0;
146 } else {
147 Score -= 30.0;
148 }
149 }
150
151 Score
152 }
153
154 fn EstimateLatencyMilliseconds(&self, TransportKind:TransportType) -> u64 {
156 match TransportKind {
157 TransportType::Ipc => 1,
158 TransportType::Grpc => 5,
159 TransportType::Wasm => 20,
160 TransportType::Unknown => u64::MAX,
161 }
162 }
163}
164
165impl Default for TransportSelector {
166 fn default() -> Self { Self::New() }
167}
168
169#[derive(Debug, Clone)]
171pub struct TransportContext {
172 EnvironmentInfo:EnvironmentInfo,
173 RequirementsInfo:TransportRequirements,
174 ConstraintsInfo:TransportConstraints,
175 AvailableTransports:HashSet<TransportType>,
176}
177
178impl TransportContext {
179 pub fn New(
181 EnvironmentInfo:EnvironmentInfo,
182 RequirementsInfo:TransportRequirements,
183 ConstraintsInfo:TransportConstraints,
184 ) -> Self {
185 let AvailableTransports = DefaultTransportTypeDetector::list_available_transports().into_iter().collect();
186
187 Self { EnvironmentInfo, RequirementsInfo, ConstraintsInfo, AvailableTransports }
188 }
189
190 pub fn Detect() -> Self {
193 let EnvironmentInfo = DefaultTransportTypeDetector::DetectEnvironment();
194 let RequirementsInfo = TransportRequirements::default();
195 let ConstraintsInfo = TransportConstraints::default();
196
197 Self::New(EnvironmentInfo, RequirementsInfo, ConstraintsInfo)
198 }
199
200 pub fn Environment(&self) -> &EnvironmentInfo { &self.EnvironmentInfo }
202
203 pub fn Requirements(&self) -> &TransportRequirements { &self.RequirementsInfo }
205
206 pub fn Constraints(&self) -> &TransportConstraints { &self.ConstraintsInfo }
208
209 pub fn TransportAvailable(&self, TransportKind:TransportType) -> bool {
211 self.AvailableTransports.contains(&TransportKind)
212 }
213
214 pub fn IsAllowed(&self, TransportKind:TransportType) -> bool {
216 if self.ConstraintsInfo.ForbiddenTransports.contains(&TransportKind) {
217 return false;
218 }
219
220 if self.ConstraintsInfo.AllowedTransports.is_empty() {
221 true
222 } else {
223 self.ConstraintsInfo.AllowedTransports.contains(&TransportKind)
224 }
225 }
226
227 pub fn WithAvailableTransports(mut self, Transports:Vec<TransportType>) -> Self {
229 self.AvailableTransports = Transports.into_iter().collect();
230 self
231 }
232}
233
234#[derive(Debug, Clone)]
236pub struct EnvironmentInfo {
237 pub Platform:Platform,
239 pub IsWeb:bool,
241 pub IsDesktop:bool,
243 pub BrowserCapabilities:Option<BrowserCapabilities>,
245}
246
247impl EnvironmentInfo {
248 pub fn New(Platform:Platform, IsWeb:bool, IsDesktop:bool, BrowserCapabilities:Option<BrowserCapabilities>) -> Self {
250 Self { Platform, IsWeb, IsDesktop, BrowserCapabilities }
251 }
252}
253
254#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
256pub enum Platform {
257 Windows,
258 MacOS,
259 Linux,
260 Browser,
261 Mobile,
262 Unknown,
263}
264
265impl Platform {
266 pub fn Current() -> Self {
268 #[cfg(target_os = "windows")]
269 return Self::Windows;
270 #[cfg(target_os = "macos")]
271 return Self::MacOS;
272 #[cfg(target_os = "linux")]
273 return Self::Linux;
274 #[cfg(all(not(target_os = "windows"), not(target_os = "macos"), not(target_os = "linux")))]
275 return Self::Unknown;
276 }
277}
278
279#[derive(Debug, Clone)]
281pub struct BrowserCapabilities {
282 pub WasmSupported:bool,
283 pub WebWorkerSupported:bool,
284 pub WebSocketSupported:bool,
285 pub SharedArrayBufferSupported:bool,
286}
287
288impl Default for BrowserCapabilities {
289 fn default() -> Self {
290 Self {
291 WasmSupported:cfg!(target_arch = "wasm32"),
292 WebWorkerSupported:false,
293 WebSocketSupported:false,
294 SharedArrayBufferSupported:false,
295 }
296 }
297}
298
299#[derive(Debug, Clone)]
301pub struct TransportRequirements {
302 pub StreamingRequired:bool,
304 pub CrossProcess:bool,
306 pub CrossNetwork:bool,
308 pub Performance:PerformanceLevel,
310 pub Reliability:ReliabilityLevel,
312 pub MaximumLatencyMilliseconds:Option<u64>,
314}
315
316impl Default for TransportRequirements {
317 fn default() -> Self {
318 Self {
319 StreamingRequired:false,
320 CrossProcess:false,
321 CrossNetwork:false,
322 Performance:PerformanceLevel::Medium,
323 Reliability:ReliabilityLevel::Medium,
324 MaximumLatencyMilliseconds:None,
325 }
326 }
327}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
331pub enum PerformanceLevel {
332 Low = 1,
333 Medium = 2,
334 High = 3,
335 Critical = 4,
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
340pub enum ReliabilityLevel {
341 Low = 1,
342 Medium = 2,
343 High = 3,
344 Critical = 4,
345}
346
347#[derive(Debug, Clone)]
349pub struct TransportConstraints {
350 pub AllowedTransports:Vec<TransportType>,
352 pub ForbiddenTransports:Vec<TransportType>,
354 pub MaximumLatencyMilliseconds:Option<u64>,
356 pub MaximumBandwidthBytesPerSecond:Option<u64>,
358}
359
360impl Default for TransportConstraints {
361 fn default() -> Self {
362 Self {
363 AllowedTransports:Vec::new(),
364 ForbiddenTransports:Vec::new(),
365 MaximumLatencyMilliseconds:None,
366 MaximumBandwidthBytesPerSecond:None,
367 }
368 }
369}
370
371pub struct TransportRegistry {
373 Transports:HashMap<String, Arc<dyn CommonTransportStrategy>>,
375 Active:Option<String>,
377 Selector:TransportSelector,
379}
380
381impl TransportRegistry {
382 pub fn New() -> Self { Self { Transports:HashMap::new(), Active:None, Selector:TransportSelector::New() } }
384
385 pub fn WithSelector(Selector:TransportSelector) -> Self {
387 Self { Transports:HashMap::new(), Active:None, Selector }
388 }
389
390 pub fn Register(&mut self, Name:String, Transport:Arc<dyn CommonTransportStrategy>) {
392 log::info!("Registering transport: {}", Name);
393 self.Transports.insert(Name, Transport);
394 }
395
396 pub async fn Unregister(&mut self, Name:&str) -> Result<(), TransportError> {
398 let TransportOption = self.Transports.remove(Name);
399
400 if let Some(_Transport) = TransportOption {
401 log::info!("Unregistered transport: {}", Name);
404 Ok(())
405 } else {
406 Err(TransportError::NotFound(format!("Transport '{}' not found", Name)))
407 }
408 }
409
410 pub async fn Select(&mut self, Name:&str) -> Result<(), TransportError> {
412 if !self.Transports.contains_key(Name) {
413 return Err(TransportError::NotFound(format!("Transport '{}' not found", Name)));
414 }
415
416 log::info!("Selecting transport: {}", Name);
417 self.Active = Some(Name.to_string());
418 Ok(())
419 }
420
421 pub async fn AutoSelect(&mut self, Context:&TransportContext) -> Result<String, TransportError> {
423 let SelectedName = self.Selector.SelectBest(Context)?;
424 self.Select(&SelectedName).await?;
425 Ok(SelectedName)
426 }
427
428 pub fn GetActive(&self) -> Option<Arc<dyn CommonTransportStrategy>> {
430 self.Active.as_ref().and_then(|Name| self.Transports.get(Name)).cloned()
431 }
432
433 pub fn Get(&self, Name:&str) -> Option<Arc<dyn CommonTransportStrategy>> { self.Transports.get(Name).cloned() }
435
436 pub fn List(&self) -> Vec<String> { self.Transports.keys().cloned().collect() }
438
439 pub fn Has(&self, Name:&str) -> bool { self.Transports.contains_key(Name) }
441
442 pub fn GetAllMetrics(&self) -> HashMap<String, TransportMetrics> {
444 let mut Metrics = HashMap::new();
445 for (Name, Transport) in &self.Transports {
446 Metrics.insert(Name.clone(), Transport.Metrics());
447 }
448 Metrics
449 }
450
451 pub fn GetHealthStatus(&self) -> HashMap<String, bool> {
453 let mut Status = HashMap::new();
454 for (Name, Transport) in &self.Transports {
455 Status.insert(Name.clone(), Transport.IsConnected());
456 }
457 Status
458 }
459
460 pub fn ActiveName(&self) -> Option<&str> { self.Active.as_deref() }
462
463 pub fn SetSelector(&mut self, Selector:TransportSelector) { self.Selector = Selector; }
465
466 pub async fn WaitForReady(&self, Name:&str, Timeout:Duration) -> Result<(), TransportError> {
468 use tokio::time::Instant;
469
470 let Start = Instant::now();
471 let Transport = self
472 .Get(Name)
473 .ok_or_else(|| TransportError::NotFound(format!("Transport '{}' not found", Name)))?;
474
475 loop {
476 if Transport.IsConnected() {
477 return Ok(());
478 }
479
480 if Start.elapsed() >= Timeout {
481 return Err(TransportError::Timeout("Transport did not become ready within timeout"));
482 }
483
484 tokio::time::sleep(Duration::from_millis(50)).await;
485 }
486 }
487}
488
489impl Default for TransportRegistry {
490 fn default() -> Self { Self::New() }
491}
492
493impl DefaultTransportTypeDetector {
495 pub fn DetectEnvironment() -> EnvironmentInfo {
497 let CurrentPlatform = Platform::Current();
498 let IsDesktop = !cfg!(target_arch = "wasm32");
499
500 let Environment =
501 EnvironmentInfo { Platform:CurrentPlatform, IsWeb:false, IsDesktop, BrowserCapabilities:None };
502
503 #[cfg(target_arch = "wasm32")]
504 {
505 EnvironmentInfo {
506 IsWeb:true,
507 IsDesktop:false,
508 BrowserCapabilities:Some(BrowserCapabilities::default()),
509 ..Environment
510 }
511 }
512
513 #[cfg(not(target_arch = "wasm32"))]
514 {
515 Environment
516 }
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use async_trait::async_trait;
523
524 use super::{
525 super::{
526 TransportConfig::TransportConfig,
527 TransportError::TransportError,
528 TransportStrategy::{TransportCapabilities, TransportMetrics},
529 UnifiedRequest::UnifiedRequest,
530 UnifiedResponse::UnifiedResponse,
531 },
532 *,
533 };
534
535 #[test]
536 fn TestTransportSelectorCreation() {
537 let Selector = TransportSelector::New();
538 assert!(!Selector.PriorityOrder.is_empty());
539 }
540
541 #[test]
542 fn TestTransportContextCreation() {
543 let Environment = EnvironmentInfo::New(Platform::Linux, false, true, None);
544 let Requirements = TransportRequirements::default();
545 let Constraints = TransportConstraints::default();
546
547 let Context = TransportContext::New(Environment, Requirements, Constraints);
548 assert!(Context.TransportAvailable(TransportType::Grpc));
551 }
552
553 #[test]
554 fn TestTransportRegistryCreation() {
555 let Registry = TransportRegistry::New();
556 assert!(Registry.List().is_empty());
557 assert!(Registry.ActiveName().is_none());
558 }
559
560 #[tokio::test]
561 async fn TestRegistryRegisterUnregister() {
562 let mut Registry = TransportRegistry::New();
563
564 let MockTransportInstance = Arc::new(MockTransport::New());
565 Registry.Register("mock".to_string(), MockTransportInstance);
566
567 assert!(Registry.Has("mock"));
568 assert_eq!(Registry.List().len(), 1);
569
570 Registry.Unregister("mock").await.unwrap();
571 assert!(!Registry.Has("mock"));
572 }
573
574 #[derive(Debug, Clone)]
576 struct MockTransport;
577
578 impl MockTransport {
579 fn New() -> Self { Self }
580 }
581
582 #[async_trait]
583 impl CommonTransportStrategy for MockTransport {
584 async fn Connect(&mut self) -> Result<(), TransportError> { Ok(()) }
585
586 async fn Disconnect(&mut self) -> Result<(), TransportError> { Ok(()) }
587
588 async fn SendRequest(&mut self, Request:UnifiedRequest) -> Result<UnifiedResponse, TransportError> {
589 Ok(UnifiedResponse::Success(
590 Request.CorrelationIdentifier.clone().unwrap_or_default(),
591 Vec::new(),
592 ))
593 }
594
595 async fn SendNotification(&mut self, _Notification:UnifiedRequest) -> Result<(), TransportError> { Ok(()) }
596
597 fn StreamEvents(
598 &self,
599 ) -> std::result::Result<futures::stream::BoxStream<'static, UnifiedResponse>, TransportError> {
600 Err(TransportError::NotSupported("Streaming not supported"))
601 }
602
603 fn IsConnected(&self) -> bool { true }
604
605 fn LatencyMilliseconds(&self) -> u64 { 0 }
606
607 fn TransportKind(&self) -> TransportType { TransportType::Grpc }
608
609 fn Configuration(&self) -> &TransportConfig {
610 static CONFIG:std::sync::OnceLock<TransportConfig> = std::sync::OnceLock::new();
611 CONFIG.get_or_init(TransportConfig::default)
612 }
613
614 fn Capabilities(&self) -> TransportCapabilities { TransportCapabilities::default() }
615
616 fn Metrics(&self) -> TransportMetrics { TransportMetrics::New() }
617
618 fn SupportsStreaming(&self) -> bool { false }
619 }
620}