use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct I2IMessage {
pub sender: String,
pub recipient: String,
pub msg_type: String,
pub content: String,
#[serde(default = "default_priority")]
pub priority: String,
#[serde(default = "current_timestamp")]
pub timestamp: f64,
#[serde(default = "HashMap::new")]
pub metadata: HashMap<String, serde_json::Value>,
}
fn default_priority() -> String {
"P2".to_string()
}
fn current_timestamp() -> f64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs_f64()
}
impl I2IMessage {
pub fn new(
sender: impl Into<String>,
recipient: impl Into<String>,
msg_type: impl Into<String>,
content: impl Into<String>,
) -> Self {
Self {
sender: sender.into(),
recipient: recipient.into(),
msg_type: msg_type.into(),
content: content.into(),
priority: default_priority(),
timestamp: current_timestamp(),
metadata: HashMap::new(),
}
}
pub fn with_priority(
sender: impl Into<String>,
recipient: impl Into<String>,
msg_type: impl Into<String>,
content: impl Into<String>,
priority: impl Into<String>,
) -> Self {
Self {
sender: sender.into(),
recipient: recipient.into(),
msg_type: msg_type.into(),
content: content.into(),
priority: priority.into(),
timestamp: current_timestamp(),
metadata: HashMap::new(),
}
}
}
pub struct I2IProtocol;
impl I2IProtocol {
pub fn format_message(
sender: impl Into<String>,
recipient: impl Into<String>,
msg_type: impl Into<String>,
content: impl Into<String>,
priority: impl Into<String>,
) -> I2IMessage {
I2IMessage::with_priority(sender, recipient, msg_type, content, priority)
}
pub fn parse_message(raw: &str) -> Result<I2IMessage, String> {
if !raw.starts_with("[I2I:") {
return Err("Message must start with '[I2I:'".to_string());
}
let type_end = raw[5..].find(']').ok_or("Missing closing ']' for message type")? + 5;
let msg_type = raw[5..type_end].trim().to_string();
let remainder = raw[type_end + 1..].trim();
let arrow = remainder.find("->").ok_or("Missing '->' separator")?;
let sender = remainder[..arrow].trim().to_string();
let after_arrow = remainder[arrow + 2..].trim();
let em_dash = after_arrow.find('—');
let (recipient, content) = match em_dash {
Some(idx) => (
after_arrow[..idx].trim().to_string(),
after_arrow[idx + 1..].trim().to_string(),
),
None => {
let fallback = after_arrow.find("- ").ok_or("Missing '—' content separator")?;
(
after_arrow[..fallback].trim().to_string(),
after_arrow[fallback + 1..].trim().to_string(),
)
}
};
Ok(I2IMessage {
sender,
recipient,
msg_type,
content,
priority: default_priority(),
timestamp: current_timestamp(),
metadata: HashMap::new(),
})
}
pub fn serialize(message: &I2IMessage) -> String {
serde_json::to_string(message).unwrap_or_default()
}
pub fn deserialize(raw: &str) -> Result<I2IMessage, String> {
let payload: serde_json::Value = serde_json::from_str(raw).map_err(|e| format!("Invalid JSON: {e}"))?;
let required = ["sender", "recipient", "msg_type", "content"];
for key in &required {
if payload.get(key).is_none() {
return Err(format!("Missing required field: {key}"));
}
}
let message: I2IMessage = serde_json::from_value(payload)
.map_err(|e| format!("Invalid message structure: {e}"))?;
Ok(message)
}
pub fn validate(message: &I2IMessage) -> bool {
!message.sender.trim().is_empty()
&& !message.recipient.trim().is_empty()
&& !message.msg_type.trim().is_empty()
&& !message.content.trim().is_empty()
}
pub fn priority_gate(message: &I2IMessage, min_priority: &str) -> bool {
let rank = |p: &str| match p {
"P0" => 0,
"P1" => 1,
"P2" => 2,
_ => 99,
};
rank(&message.priority) <= rank(min_priority)
}
}
#[derive(Debug, Clone, Default)]
pub struct TrustRouter {
trust: HashMap<String, f64>,
}
impl TrustRouter {
pub fn new() -> Self {
Self {
trust: HashMap::new(),
}
}
pub fn add_trust(&mut self, agent_id: impl Into<String>, trust_level: f64) -> Result<(), String> {
if !(0.0..=1.0).contains(&trust_level) {
return Err("trust_level must be between 0.0 and 1.0".to_string());
}
self.trust.insert(agent_id.into(), trust_level);
Ok(())
}
pub fn get_trust(&self, agent_id: &str) -> f64 {
self.trust.get(agent_id).copied().unwrap_or(0.0)
}
pub fn route(&self, _message: &I2IMessage, available_agents: &[String]) -> Option<String> {
if available_agents.is_empty() {
return None;
}
let mut best_agent: Option<String> = None;
let mut best_score = -1.0;
for agent in available_agents {
let score = self.get_trust(agent);
if score > best_score {
best_score = score;
best_agent = Some(agent.clone());
}
}
if best_score <= 0.0 {
return None;
}
best_agent
}
pub fn is_trusted(&self, agent_id: &str, min_trust: f64) -> bool {
self.get_trust(agent_id) >= min_trust
}
pub fn stats(&self) -> HashMap<String, serde_json::Value> {
let mut result = HashMap::new();
if self.trust.is_empty() {
result.insert("count".to_string(), serde_json::json!(0));
result.insert("average_trust".to_string(), serde_json::json!(0.0));
result.insert("max_trust".to_string(), serde_json::json!(0.0));
result.insert("min_trust".to_string(), serde_json::json!(0.0));
return result;
}
let values: Vec<f64> = self.trust.values().copied().collect();
let count = values.len() as i64;
let sum: f64 = values.iter().sum();
let avg = sum / values.len() as f64;
let max = values.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
let min = values.iter().fold(f64::INFINITY, |a, &b| a.min(b));
result.insert("count".to_string(), serde_json::json!(count));
result.insert("average_trust".to_string(), serde_json::json!(avg));
result.insert("max_trust".to_string(), serde_json::json!(max));
result.insert("min_trust".to_string(), serde_json::json!(min));
result
}
}