Files
hakorune/src/message_bus.rs
Moe Charm 312ba73b4b 🌐 feat: P2PBox天才アルゴリズム完全実装 - Bus+Transport統合システム
## 🚀 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>
2025-08-11 17:20:05 +09:00

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()
}