use reputation_core::Calculator;
use reputation_types::{AgentData, AgentDataBuilder, ReputationScore};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::time::{Duration, Instant};
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Reputation Engine Integration Patterns ===\n");
println!("1. CACHING PATTERN");
println!("------------------");
caching_pattern()?;
println!("\n2. CONCURRENT ACCESS PATTERN");
println!("----------------------------");
concurrent_pattern()?;
println!("\n3. EVENT-DRIVEN PATTERN");
println!("-----------------------");
event_driven_pattern()?;
println!("\n4. SERVICE LAYER PATTERN");
println!("------------------------");
service_layer_pattern()?;
println!("\n5. RATE LIMITING PATTERN");
println!("------------------------");
rate_limiting_pattern()?;
Ok(())
}
struct ScoreCache {
cache: RwLock<HashMap<String, (ReputationScore, Instant)>>,
ttl: Duration,
}
impl ScoreCache {
fn new(ttl: Duration) -> Self {
Self {
cache: RwLock::new(HashMap::new()),
ttl,
}
}
fn get(&self, did: &str) -> Option<ReputationScore> {
let cache = self.cache.read().unwrap();
if let Some((score, timestamp)) = cache.get(did) {
if timestamp.elapsed() < self.ttl {
return Some(score.clone());
}
}
None
}
fn set(&self, did: String, score: ReputationScore) {
let mut cache = self.cache.write().unwrap();
cache.insert(did, (score, Instant::now()));
}
fn invalidate(&self, did: &str) {
let mut cache = self.cache.write().unwrap();
cache.remove(did);
}
}
fn caching_pattern() -> Result<(), Box<dyn std::error::Error>> {
let calculator = Calculator::default();
let cache = ScoreCache::new(Duration::from_secs(300));
let calculate_with_cache = |agent: &AgentData| -> Result<ReputationScore, Box<dyn std::error::Error>> {
if let Some(cached_score) = cache.get(&agent.did) {
println!(" Cache HIT for {}", agent.did);
return Ok(cached_score);
}
println!(" Cache MISS for {} - calculating...", agent.did);
let score = calculator.calculate(agent)?;
cache.set(agent.did.clone(), score.clone());
Ok(score)
};
let agent = AgentDataBuilder::new("did:example:cached")
.with_reviews(100, 4.2)
.total_interactions(150)
.build()?;
let score1 = calculate_with_cache(&agent)?;
println!(" Score: {:.1}", score1.score);
let score2 = calculate_with_cache(&agent)?;
assert_eq!(score1.score, score2.score);
println!(" Invalidating cache...");
cache.invalidate(&agent.did);
let _score3 = calculate_with_cache(&agent)?;
Ok(())
}
fn concurrent_pattern() -> Result<(), Box<dyn std::error::Error>> {
let calculator = Arc::new(Calculator::default());
let results = Arc::new(Mutex::new(Vec::new()));
let agents: Vec<_> = (0..20)
.map(|i| {
AgentDataBuilder::new(&format!("did:example:concurrent{}", i))
.with_reviews(i * 10, 3.5 + (i as f64 * 0.1))
.total_interactions(i * 15)
.build()
.unwrap()
})
.collect();
let mut handles = vec![];
for agent in agents {
let calc = Arc::clone(&calculator);
let res = Arc::clone(&results);
let handle = std::thread::spawn(move || {
match calc.calculate(&agent) {
Ok(score) => {
println!(" Thread {:?} calculated score for {}: {:.1}",
std::thread::current().id(),
agent.did,
score.score
);
res.lock().unwrap().push((agent.did, score));
}
Err(e) => eprintln!(" Error: {}", e),
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!(" Processed {} agents concurrently", results.lock().unwrap().len());
Ok(())
}
enum ReputationEvent {
ReviewAdded { agent_id: String, rating: f64 },
AgentUpdated { agent_id: String },
BatchProcess { agent_ids: Vec<String> },
}
struct EventProcessor {
#[allow(dead_code)]
calculator: Calculator,
cache: ScoreCache,
}
impl EventProcessor {
fn new() -> Self {
Self {
calculator: Calculator::default(),
cache: ScoreCache::new(Duration::from_secs(600)),
}
}
fn process_event(&self, event: ReputationEvent) -> Result<(), Box<dyn std::error::Error>> {
match event {
ReputationEvent::ReviewAdded { agent_id, rating } => {
println!(" Processing ReviewAdded: {} got {:.1}★", agent_id, rating);
self.cache.invalidate(&agent_id);
}
ReputationEvent::AgentUpdated { agent_id } => {
println!(" Processing AgentUpdated: {}", agent_id);
self.cache.invalidate(&agent_id);
}
ReputationEvent::BatchProcess { agent_ids } => {
println!(" Processing BatchProcess for {} agents", agent_ids.len());
for id in &agent_ids {
self.cache.invalidate(id);
}
}
}
Ok(())
}
}
fn event_driven_pattern() -> Result<(), Box<dyn std::error::Error>> {
let processor = EventProcessor::new();
let events = vec![
ReputationEvent::ReviewAdded {
agent_id: "did:example:event1".to_string(),
rating: 4.5,
},
ReputationEvent::AgentUpdated {
agent_id: "did:example:event2".to_string(),
},
ReputationEvent::BatchProcess {
agent_ids: vec![
"did:example:batch1".to_string(),
"did:example:batch2".to_string(),
"did:example:batch3".to_string(),
],
},
];
for event in events {
processor.process_event(event)?;
}
Ok(())
}
struct ReputationService {
calculator: Arc<Calculator>,
cache: Arc<ScoreCache>,
}
impl ReputationService {
fn new() -> Self {
Self {
calculator: Arc::new(Calculator::default()),
cache: Arc::new(ScoreCache::new(Duration::from_secs(300))),
}
}
fn get_score(&self, agent: &AgentData) -> Result<ReputationScore, Box<dyn std::error::Error>> {
if let Some(score) = self.cache.get(&agent.did) {
return Ok(score);
}
let score = self.calculator.calculate(agent)?;
self.cache.set(agent.did.clone(), score.clone());
Ok(score)
}
#[allow(dead_code)]
fn get_scores_batch(&self, agents: &[AgentData]) -> Vec<Result<ReputationScore, reputation_core::ReputationError>> {
self.calculator.calculate_batch(agents)
}
fn get_score_explanation(&self, agent: &AgentData) -> Result<String, Box<dyn std::error::Error>> {
let explanation = self.calculator.explain_score(agent)?;
Ok(explanation.explanation)
}
fn predict_score_change(&self, agent: &AgentData, new_reviews: u32, rating: f64)
-> Result<reputation_core::ScorePrediction, Box<dyn std::error::Error>> {
self.calculator.predict_score_change(agent, new_reviews, rating)
.map_err(|e| e.into())
}
}
fn service_layer_pattern() -> Result<(), Box<dyn std::error::Error>> {
let service = ReputationService::new();
let agent = AgentDataBuilder::new("did:example:service")
.with_reviews(75, 4.3)
.total_interactions(100)
.mcp_level(2)
.build()?;
println!(" Getting score...");
let score = service.get_score(&agent)?;
println!(" Score: {:.1}", score.score);
println!("\n Getting explanation...");
let explanation = service.get_score_explanation(&agent)?;
println!("{}", explanation.split('\n').take(3).collect::<Vec<_>>().join("\n"));
println!("\n Predicting score change...");
let prediction = service.predict_score_change(&agent, 25, 4.5)?;
println!(" Change: {:+.1} points", prediction.score_change);
Ok(())
}
struct RateLimiter {
requests: Mutex<HashMap<String, Vec<Instant>>>,
max_requests: usize,
window: Duration,
}
impl RateLimiter {
fn new(max_requests: usize, window: Duration) -> Self {
Self {
requests: Mutex::new(HashMap::new()),
max_requests,
window,
}
}
fn check_rate_limit(&self, client_id: &str) -> bool {
let mut requests = self.requests.lock().unwrap();
let now = Instant::now();
let client_requests = requests.entry(client_id.to_string()).or_insert_with(Vec::new);
client_requests.retain(|&req_time| now.duration_since(req_time) < self.window);
if client_requests.len() < self.max_requests {
client_requests.push(now);
true
} else {
false
}
}
}
fn rate_limiting_pattern() -> Result<(), Box<dyn std::error::Error>> {
let calculator = Calculator::default();
let rate_limiter = RateLimiter::new(5, Duration::from_secs(60));
let agent = AgentDataBuilder::new("did:example:ratelimited")
.with_reviews(50, 4.0)
.total_interactions(75)
.build()?;
let client_id = "client_123";
for i in 0..8 {
if rate_limiter.check_rate_limit(client_id) {
let score = calculator.calculate(&agent)?;
println!(" Request {} - OK: score = {:.1}", i + 1, score.score);
} else {
println!(" Request {} - RATE LIMITED", i + 1);
}
std::thread::sleep(Duration::from_millis(100));
}
Ok(())
}