[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "xcu-ipc-router"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] xcu-ipc-router"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -0,0 +1,48 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! Channel implementations for IPC
|
||||
|
||||
use crate::{IpcError, Result};
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub struct SharedMemoryChannel {
|
||||
buffer: Arc<Mutex<VecDeque<Vec<u8>>>>,
|
||||
capacity: usize,
|
||||
name: String,
|
||||
closed: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl SharedMemoryChannel {
|
||||
pub fn new(name: &str, capacity: usize) -> Self {
|
||||
Self {
|
||||
buffer: Arc::new(Mutex::new(VecDeque::with_capacity(capacity))),
|
||||
capacity, name: name.to_string(),
|
||||
closed: Arc::new(Mutex::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, data: Vec<u8>) -> Result<()> {
|
||||
let closed = self.closed.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
if *closed { return Err(IpcError::ChannelClosed); }
|
||||
drop(closed);
|
||||
let mut buf = self.buffer.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
if buf.len() >= self.capacity { return Err(IpcError::BufferFull); }
|
||||
buf.push_back(data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recv(&self) -> Result<Option<Vec<u8>>> {
|
||||
let mut buf = self.buffer.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
Ok(buf.pop_front())
|
||||
}
|
||||
|
||||
pub fn close(&self) -> Result<()> {
|
||||
let mut c = self.closed.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
*c = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str { &self.name }
|
||||
pub fn len(&self) -> usize { self.buffer.lock().map(|b| b.len()).unwrap_or(0) }
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! xcu-ipc-router — Inter-Process Communication Matrix
|
||||
#![deny(warnings)]
|
||||
|
||||
pub mod router;
|
||||
pub mod channel;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct IpcMessage {
|
||||
pub id: u64,
|
||||
pub channel: String,
|
||||
pub payload: Vec<u8>,
|
||||
pub priority: u8,
|
||||
pub timestamp_ns: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IpcError {
|
||||
ChannelNotFound(String),
|
||||
ChannelClosed,
|
||||
BufferFull,
|
||||
SerializationFailed(String),
|
||||
LockPoisoned(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for IpcError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ChannelNotFound(c) => write!(f, "Channel not found: {c}"),
|
||||
Self::ChannelClosed => write!(f, "Channel closed"),
|
||||
Self::BufferFull => write!(f, "Buffer full"),
|
||||
Self::SerializationFailed(e) => write!(f, "Serialization: {e}"),
|
||||
Self::LockPoisoned(e) => write!(f, "Lock poisoned: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for IpcError {}
|
||||
pub type Result<T> = std::result::Result<T, IpcError>;
|
||||
|
||||
pub struct MessageBus {
|
||||
subscribers: Arc<Mutex<HashMap<String, Vec<Arc<Mutex<Vec<IpcMessage>>>>>>>,
|
||||
msg_counter: Arc<Mutex<u64>>,
|
||||
}
|
||||
|
||||
impl MessageBus {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
subscribers: Arc::new(Mutex::new(HashMap::new())),
|
||||
msg_counter: Arc::new(Mutex::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subscribe(&self, topic: &str) -> Result<Arc<Mutex<Vec<IpcMessage>>>> {
|
||||
let inbox = Arc::new(Mutex::new(Vec::new()));
|
||||
let mut subs = self.subscribers.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
subs.entry(topic.to_string()).or_default().push(Arc::clone(&inbox));
|
||||
Ok(inbox)
|
||||
}
|
||||
|
||||
pub fn publish(&self, topic: &str, payload: Vec<u8>, priority: u8) -> Result<u64> {
|
||||
let mut counter = self.msg_counter.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
*counter += 1;
|
||||
let msg = IpcMessage {
|
||||
id: *counter, channel: topic.to_string(), payload, priority,
|
||||
timestamp_ns: std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("[TSM.ID]").as_nanos() as u64,
|
||||
};
|
||||
let subs = self.subscribers.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
if let Some(inboxes) = subs.get(topic) {
|
||||
for inbox in inboxes {
|
||||
if let Ok(mut q) = inbox.lock() { q.push(msg.clone()); }
|
||||
}
|
||||
}
|
||||
Ok(msg.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MessageBus {
|
||||
fn default() -> Self { Self::new() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_pubsub() {
|
||||
let bus = MessageBus::new();
|
||||
let inbox = bus.subscribe("test").unwrap();
|
||||
bus.publish("test", vec![1,2,3], 5).unwrap();
|
||||
let msgs = inbox.lock().unwrap();
|
||||
assert_eq!(msgs.len(), 1);
|
||||
assert_eq!(msgs[0].payload, vec![1,2,3]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! IPC Router with priority-based message routing
|
||||
|
||||
use crate::{IpcMessage, IpcError, Result};
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
use std::cmp::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
struct PriorityMessage { msg: Vec<u8>, priority: u8, seq: u64 }
|
||||
|
||||
impl Ord for PriorityMessage {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.priority.cmp(&other.priority).then_with(|| other.seq.cmp(&self.seq))
|
||||
}
|
||||
}
|
||||
impl PartialOrd for PriorityMessage {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
pub struct IpcRouter {
|
||||
routes: Arc<Mutex<HashMap<String, String>>>,
|
||||
priority_queue: Arc<Mutex<BinaryHeap<PriorityMessage>>>,
|
||||
seq: Arc<Mutex<u64>>,
|
||||
max_queue: usize,
|
||||
}
|
||||
|
||||
impl IpcRouter {
|
||||
pub fn new(max_queue: usize) -> Self {
|
||||
Self {
|
||||
routes: Arc::new(Mutex::new(HashMap::new())),
|
||||
priority_queue: Arc::new(Mutex::new(BinaryHeap::new())),
|
||||
seq: Arc::new(Mutex::new(0)),
|
||||
max_queue,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_route(&self, source: &str, target: &str) -> Result<()> {
|
||||
let mut r = self.routes.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
r.insert(source.to_string(), target.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn resolve(&self, source: &str) -> Result<String> {
|
||||
let r = self.routes.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
r.get(source).cloned().ok_or_else(|| IpcError::ChannelNotFound(source.to_string()))
|
||||
}
|
||||
|
||||
pub fn enqueue(&self, msg: IpcMessage) -> Result<()> {
|
||||
let mut pq = self.priority_queue.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
if pq.len() >= self.max_queue { return Err(IpcError::BufferFull); }
|
||||
let mut s = self.seq.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
*s += 1;
|
||||
pq.push(PriorityMessage { msg: msg.payload, priority: msg.priority, seq: *s });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dequeue(&self) -> Result<Option<Vec<u8>>> {
|
||||
let mut pq = self.priority_queue.lock().map_err(|e| IpcError::LockPoisoned(e.to_string()))?;
|
||||
Ok(pq.pop().map(|pm| pm.msg))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user