## 🚀 ChatGPT大会議設計の完全実現 - Bus = ローカルOS:常に保持、配送・購読・監視のハブ - Transport = NIC:通信手段選択、InProcess/WebSocket/WebRTC切り替え - MessageIntentBox:Nyashネイティブメッセージコンテナ ## ⚡ 天才送信アルゴリズム実装 ```rust if self.bus.has_node(to) { self.bus.route(message)?; // 爆速ローカル(ゼロコピー級) } else { self.transport.send(to, intent, data)?; // Transport経由 } ``` ## 🎯 4つの核心完全達成 1. ✅ P2PBoxは、トランスポートがネットでもBusを持ち続ける 2. ✅ P2PBoxはMessageIntentBoxを使って送る 3. ✅ 送信アルゴリズム:ローカルならBus、それ以外はTransport 4. ✅ 受信フロー:BusMessage→MessageIntentBoxラッパー実装 ## 📦 新規実装コンポーネント - MessageBus:グローバルシングルトン、Arc<Mutex>統一パターン - Transport trait:NyaMesh参考、同期ファースト設計 - InProcessTransport:高速ローカル通信実装 - MessageIntentBox:HashMap<String, Box<dyn NyashBox>>構造 - TransportKind enum:create_transport()ファクトリ含む - NewP2PBox:天才アルゴリズム内蔵、同期・シンプル実装 ## 🎉 設計思想実現 「ローカル高速・ネット分離・デバッグ容易・拡張自在」を完全両立 NyaMesh実証済みパターン + Everything is Box哲学の融合 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
173 lines
5.1 KiB
Rust
173 lines
5.1 KiB
Rust
/**
|
|
* MessageBus - Central communication hub (Bus = Local OS metaphor)
|
|
*
|
|
* Design principles from ChatGPT discussion:
|
|
* - Always present in P2PBox (even for network transport)
|
|
* - Handles local routing, subscription, monitoring
|
|
* - Singleton pattern for process-wide message coordination
|
|
* - Synchronous-first implementation
|
|
*
|
|
* NyaMesh inspiration:
|
|
* - InProcessMessageBus singleton pattern
|
|
* - Node registration/unregistration
|
|
* - Statistics tracking
|
|
*/
|
|
|
|
use std::collections::HashMap;
|
|
use std::sync::{Arc, Mutex, RwLock};
|
|
use crate::NyashBox;
|
|
|
|
/// Message structure for internal routing
|
|
#[derive(Debug)]
|
|
pub struct BusMessage {
|
|
pub from: String,
|
|
pub to: String,
|
|
pub intent: String,
|
|
pub data: Box<dyn NyashBox>,
|
|
pub timestamp: std::time::SystemTime,
|
|
}
|
|
|
|
impl Clone for BusMessage {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
from: self.from.clone(),
|
|
to: self.to.clone(),
|
|
intent: self.intent.clone(),
|
|
data: self.data.clone_box(), // NyashBoxのclone_box()メソッドを使用
|
|
timestamp: self.timestamp,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Node registration information
|
|
struct NodeInfo {
|
|
node_id: String,
|
|
callbacks: HashMap<String, Vec<Box<dyn Fn(&BusMessage) + Send + Sync>>>,
|
|
}
|
|
|
|
/// Central MessageBus - handles all local message routing
|
|
pub struct MessageBus {
|
|
/// Registered nodes in this process
|
|
nodes: RwLock<HashMap<String, Arc<Mutex<NodeInfo>>>>,
|
|
|
|
/// Bus-level statistics
|
|
stats: Mutex<BusStats>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct BusStats {
|
|
pub messages_routed: u64,
|
|
pub routing_errors: u64,
|
|
pub nodes_registered: u64,
|
|
pub total_callbacks: u64,
|
|
}
|
|
|
|
impl MessageBus {
|
|
/// Create new MessageBus instance
|
|
pub fn new() -> Self {
|
|
Self {
|
|
nodes: RwLock::new(HashMap::new()),
|
|
stats: Mutex::new(BusStats::default()),
|
|
}
|
|
}
|
|
|
|
/// Register a node in the message bus
|
|
pub fn register_node(&self, node_id: &str) -> Result<(), String> {
|
|
let mut nodes = self.nodes.write().unwrap();
|
|
|
|
if nodes.contains_key(node_id) {
|
|
return Err(format!("Node '{}' already registered", node_id));
|
|
}
|
|
|
|
let node_info = NodeInfo {
|
|
node_id: node_id.to_string(),
|
|
callbacks: HashMap::new(),
|
|
};
|
|
|
|
nodes.insert(node_id.to_string(), Arc::new(Mutex::new(node_info)));
|
|
|
|
// Update stats
|
|
let mut stats = self.stats.lock().unwrap();
|
|
stats.nodes_registered += 1;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Unregister a node from the message bus
|
|
pub fn unregister_node(&self, node_id: &str) {
|
|
let mut nodes = self.nodes.write().unwrap();
|
|
nodes.remove(node_id);
|
|
}
|
|
|
|
/// Check if a node is registered locally
|
|
pub fn has_node(&self, node_id: &str) -> bool {
|
|
let nodes = self.nodes.read().unwrap();
|
|
nodes.contains_key(node_id)
|
|
}
|
|
|
|
/// Route message to local node
|
|
pub fn route(&self, message: BusMessage) -> Result<(), String> {
|
|
let nodes = self.nodes.read().unwrap();
|
|
|
|
if let Some(node) = nodes.get(&message.to) {
|
|
let node = node.lock().unwrap();
|
|
|
|
// Find callbacks for this intent
|
|
if let Some(callbacks) = node.callbacks.get(&message.intent) {
|
|
for callback in callbacks {
|
|
callback(&message);
|
|
}
|
|
}
|
|
|
|
// Update stats
|
|
let mut stats = self.stats.lock().unwrap();
|
|
stats.messages_routed += 1;
|
|
|
|
Ok(())
|
|
} else {
|
|
let mut stats = self.stats.lock().unwrap();
|
|
stats.routing_errors += 1;
|
|
Err(format!("Node '{}' not found for routing", message.to))
|
|
}
|
|
}
|
|
|
|
/// Register callback for specific intent on a node
|
|
pub fn on(&self, node_id: &str, intent: &str, callback: Box<dyn Fn(&BusMessage) + Send + Sync>) -> Result<(), String> {
|
|
let nodes = self.nodes.read().unwrap();
|
|
|
|
if let Some(node) = nodes.get(node_id) {
|
|
let mut node = node.lock().unwrap();
|
|
node.callbacks.entry(intent.to_string()).or_insert_with(Vec::new).push(callback);
|
|
|
|
// Update stats
|
|
let mut stats = self.stats.lock().unwrap();
|
|
stats.total_callbacks += 1;
|
|
|
|
Ok(())
|
|
} else {
|
|
Err(format!("Node '{}' not found for callback registration", node_id))
|
|
}
|
|
}
|
|
|
|
/// Get list of registered nodes
|
|
pub fn get_registered_nodes(&self) -> Vec<String> {
|
|
let nodes = self.nodes.read().unwrap();
|
|
nodes.keys().cloned().collect()
|
|
}
|
|
|
|
/// Get bus statistics
|
|
pub fn get_stats(&self) -> BusStats {
|
|
let stats = self.stats.lock().unwrap();
|
|
stats.clone()
|
|
}
|
|
}
|
|
|
|
use std::sync::OnceLock;
|
|
|
|
/// Global MessageBus singleton
|
|
static GLOBAL_MESSAGE_BUS: OnceLock<Arc<MessageBus>> = OnceLock::new();
|
|
|
|
/// Get global message bus instance
|
|
pub fn get_global_message_bus() -> Arc<MessageBus> {
|
|
GLOBAL_MESSAGE_BUS.get_or_init(|| Arc::new(MessageBus::new())).clone()
|
|
} |