[TSM.ID].[11031972] PXE : 10 Template/Kosong -> REAL Implementation (3Z Complete)
This commit is contained in:
@@ -1,104 +1,125 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! xcu-orbital-router — Mesh fallback routing with circuit breaker
|
||||
#![deny(warnings)]
|
||||
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-orbital-router -- Mesh Routing with Latency Scoring & Circuit Breaker
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum XcuError {
|
||||
InitFailed(String),
|
||||
InvalidConfig(String),
|
||||
OperationFailed(String),
|
||||
ResourceExhausted,
|
||||
NotFound(String),
|
||||
Timeout,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XcuError {
|
||||
pub enum OrbitalError { NoRoute(String), CircuitOpen(String), AllPathsFailed(String) }
|
||||
impl std::fmt::Display for OrbitalError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::InitFailed(e) => write!(f, "Init failed: {e}"),
|
||||
Self::InvalidConfig(e) => write!(f, "Invalid config: {e}"),
|
||||
Self::OperationFailed(e) => write!(f, "Operation failed: {e}"),
|
||||
Self::ResourceExhausted => write!(f, "Resource exhausted"),
|
||||
Self::NotFound(e) => write!(f, "Not found: {e}"),
|
||||
Self::Timeout => write!(f, "Operation timed out"),
|
||||
match self { Self::NoRoute(e) => write!(f, "No route: {e}"), Self::CircuitOpen(e) => write!(f, "Circuit: {e}"), Self::AllPathsFailed(e) => write!(f, "All failed: {e}") }
|
||||
}
|
||||
}
|
||||
impl std::error::Error for OrbitalError {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshNode { pub id: String, pub region: String, pub latency_ms: u32, pub capacity: u32, pub current_load: u32 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MeshEdge { pub from: String, pub to: String, pub latency_ms: u32, pub bandwidth_mbps: u32 }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CircuitBreaker { pub failures: u32, pub threshold: u32, pub is_open: bool, pub last_failure: u64 }
|
||||
impl CircuitBreaker {
|
||||
pub fn new(threshold: u32) -> Self { Self { failures: 0, threshold, is_open: false, last_failure: 0 } }
|
||||
pub fn record_failure(&mut self, now: u64) { self.failures += 1; self.last_failure = now; if self.failures >= self.threshold { self.is_open = true; } }
|
||||
pub fn record_success(&mut self) { self.failures = 0; self.is_open = false; }
|
||||
pub fn try_half_open(&mut self, now: u64, cooldown_secs: u64) -> bool {
|
||||
if self.is_open && now - self.last_failure > cooldown_secs { self.is_open = false; self.failures = self.threshold - 1; return true; }
|
||||
!self.is_open
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OrbitalRouter {
|
||||
nodes: HashMap<String, MeshNode>,
|
||||
edges: Vec<MeshEdge>,
|
||||
breakers: HashMap<String, CircuitBreaker>,
|
||||
breaker_threshold: u32,
|
||||
}
|
||||
|
||||
impl OrbitalRouter {
|
||||
pub fn new(breaker_threshold: u32) -> Self {
|
||||
Self { nodes: HashMap::new(), edges: Vec::new(), breakers: HashMap::new(), breaker_threshold }
|
||||
}
|
||||
pub fn add_node(&mut self, node: MeshNode) { self.nodes.insert(node.id.clone(), node); }
|
||||
pub fn add_edge(&mut self, edge: MeshEdge) { self.edges.push(edge); }
|
||||
|
||||
/// Find best route using scoring (latency + load + circuit state)
|
||||
pub fn find_route(&mut self, from: &str, to: &str, now: u64) -> Result<Vec<String>, OrbitalError> {
|
||||
// Direct edge?
|
||||
let direct: Vec<&MeshEdge> = self.edges.iter().filter(|e| e.from == from && e.to == to).collect();
|
||||
for edge in &direct {
|
||||
let key = format!("{}->{}", edge.from, edge.to);
|
||||
let breaker = self.breakers.entry(key).or_insert_with(|| CircuitBreaker::new(self.breaker_threshold));
|
||||
if breaker.try_half_open(now, 30) {
|
||||
return Ok(vec![from.into(), to.into()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for XcuError {}
|
||||
pub type Result<T> = std::result::Result<T, XcuError>;
|
||||
// Multi-hop: find via intermediate nodes
|
||||
let intermediates: Vec<String> = self.edges.iter()
|
||||
.filter(|e| e.from == from)
|
||||
.flat_map(|e1| {
|
||||
self.edges.iter()
|
||||
.filter(|e2| e2.from == e1.to && e2.to == to)
|
||||
.map(move |e2| (e1.clone(), e2.clone()))
|
||||
})
|
||||
.map(|(e1, _)| e1.to.clone())
|
||||
.collect();
|
||||
|
||||
pub struct Config {
|
||||
pub params: HashMap<String, String>,
|
||||
}
|
||||
if intermediates.is_empty() { return Err(OrbitalError::NoRoute(format!("{from} -> {to}"))); }
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Self { Self { params: HashMap::new() } }
|
||||
pub fn set(&mut self, key: &str, val: &str) -> &mut Self {
|
||||
self.params.insert(key.to_string(), val.to_string()); self
|
||||
}
|
||||
pub fn get(&self, key: &str) -> Result<&str> {
|
||||
self.params.get(key).map(|s| s.as_str()).ok_or_else(|| XcuError::NotFound(key.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
pub struct Engine {
|
||||
config: Config,
|
||||
state: Arc<Mutex<EngineState>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum EngineState {
|
||||
Idle,
|
||||
Running,
|
||||
Paused,
|
||||
ShuttingDown,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
pub fn new(config: Config) -> Result<Self> {
|
||||
Ok(Self { config, state: Arc::new(Mutex::new(EngineState::Idle)) })
|
||||
// Score intermediates by latency + load
|
||||
let mut best_hop = intermediates[0].clone();
|
||||
let mut best_score = f64::MAX;
|
||||
for hop in &intermediates {
|
||||
let key = format!("{from}->{hop}");
|
||||
let breaker = self.breakers.entry(key).or_insert_with(|| CircuitBreaker::new(self.breaker_threshold));
|
||||
if !breaker.try_half_open(now, 30) { continue; }
|
||||
if let Some(node) = self.nodes.get(hop) {
|
||||
let load_ratio = if node.capacity > 0 { node.current_load as f64 / node.capacity as f64 } else { 1.0 };
|
||||
let score = node.latency_ms as f64 + load_ratio * 100.0;
|
||||
if score < best_score { best_score = score; best_hop = hop.clone(); }
|
||||
}
|
||||
}
|
||||
Ok(vec![from.into(), best_hop, to.into()])
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Result<()> {
|
||||
let mut s = self.state.lock().map_err(|e| XcuError::OperationFailed(e.to_string()))?;
|
||||
*s = EngineState::Running;
|
||||
Ok(())
|
||||
pub fn report_failure(&mut self, from: &str, to: &str, now: u64) {
|
||||
let key = format!("{from}->{to}");
|
||||
let breaker = self.breakers.entry(key).or_insert_with(|| CircuitBreaker::new(self.breaker_threshold));
|
||||
breaker.record_failure(now);
|
||||
}
|
||||
|
||||
pub fn stop(&self) -> Result<()> {
|
||||
let mut s = self.state.lock().map_err(|e| XcuError::OperationFailed(e.to_string()))?;
|
||||
*s = EngineState::ShuttingDown;
|
||||
// graceful shutdown logic
|
||||
*s = EngineState::Stopped;
|
||||
Ok(())
|
||||
pub fn report_success(&mut self, from: &str, to: &str) {
|
||||
let key = format!("{from}->{to}");
|
||||
if let Some(breaker) = self.breakers.get_mut(&key) { breaker.record_success(); }
|
||||
}
|
||||
|
||||
pub fn state(&self) -> Result<EngineState> {
|
||||
let s = self.state.lock().map_err(|e| XcuError::OperationFailed(e.to_string()))?;
|
||||
Ok(s.clone())
|
||||
}
|
||||
|
||||
pub fn config(&self) -> &Config { &self.config }
|
||||
pub fn node_count(&self) -> usize { self.nodes.len() }
|
||||
pub fn open_circuits(&self) -> usize { self.breakers.values().filter(|b| b.is_open).count() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
fn setup() -> OrbitalRouter {
|
||||
let mut r = OrbitalRouter::new(3);
|
||||
r.add_node(MeshNode { id: "a".into(), region: "sg".into(), latency_ms: 5, capacity: 100, current_load: 10 });
|
||||
r.add_node(MeshNode { id: "b".into(), region: "jp".into(), latency_ms: 20, capacity: 100, current_load: 50 });
|
||||
r.add_node(MeshNode { id: "c".into(), region: "de".into(), latency_ms: 10, capacity: 100, current_load: 20 });
|
||||
r.add_edge(MeshEdge { from: "a".into(), to: "b".into(), latency_ms: 15, bandwidth_mbps: 100 });
|
||||
r.add_edge(MeshEdge { from: "a".into(), to: "c".into(), latency_ms: 10, bandwidth_mbps: 100 });
|
||||
r.add_edge(MeshEdge { from: "c".into(), to: "b".into(), latency_ms: 20, bandwidth_mbps: 50 });
|
||||
r
|
||||
}
|
||||
#[test]
|
||||
fn test_engine_lifecycle() {
|
||||
let engine = Engine::new(Config::new()).unwrap();
|
||||
assert_eq!(engine.state().unwrap(), EngineState::Idle);
|
||||
engine.start().unwrap();
|
||||
assert_eq!(engine.state().unwrap(), EngineState::Running);
|
||||
engine.stop().unwrap();
|
||||
assert_eq!(engine.state().unwrap(), EngineState::Stopped);
|
||||
fn test_direct_route() { let mut r = setup(); let route = r.find_route("a", "b", 1000).unwrap(); assert_eq!(route, vec!["a", "b"]); }
|
||||
#[test]
|
||||
fn test_circuit_breaker() {
|
||||
let mut r = setup();
|
||||
r.report_failure("a", "b", 100);
|
||||
r.report_failure("a", "b", 101);
|
||||
r.report_failure("a", "b", 102);
|
||||
assert_eq!(r.open_circuits(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user