use bytes::Bytes;
use ipfrs_core::Cid;
use ipfrs_transport::{
AdvancedScheduler, CoalescerConfig, ConnectionMigration, MigrationConfig, RequestCoalescer,
SchedulePriority, ScheduledRequest, SchedulingPolicy,
};
use multihash::Multihash;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::time::sleep;
fn dummy_cid(seed: u64) -> Cid {
let data = seed.to_le_bytes();
let hash = Multihash::wrap(0x12, &data).unwrap();
Cid::new_v1(0x55, hash)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Advanced Features Demonstration ===\n");
demonstrate_request_coalescing().await?;
println!();
demonstrate_connection_migration().await?;
println!();
demonstrate_advanced_scheduling().await?;
println!("\n=== All demonstrations completed successfully! ===");
Ok(())
}
async fn demonstrate_request_coalescing() -> Result<(), Box<dyn std::error::Error>> {
println!("--- Request Coalescing Demonstration ---");
let config = CoalescerConfig {
coalesce_window: Duration::from_millis(20),
max_waiters_per_request: 100,
broadcast_capacity: 128,
enable_stats: true,
};
let coalescer = Arc::new(RequestCoalescer::new(config));
let cid = dummy_cid(12345);
println!("Scenario: 10 concurrent requests for the same block");
println!("Expected: Only 1 network request, 9 coalesced\n");
let mut handles = vec![];
for i in 0..10 {
let coalescer_clone = coalescer.clone();
let cid_clone = cid;
let handle = tokio::spawn(async move {
let start = Instant::now();
let rx = coalescer_clone.register_request(&cid_clone).await.unwrap();
if let Some(mut receiver) = rx {
println!(" Request {}: Waiting for coalesced result", i);
match receiver.recv().await {
Ok(Ok(data)) => {
println!(
" Request {}: Received data ({} bytes) in {:?}",
i,
data.len(),
start.elapsed()
);
}
Ok(Err(e)) => println!(" Request {}: Error: {}", i, e),
Err(e) => println!(" Request {}: Channel error: {}", i, e),
}
} else {
println!(" Request {}: Fetching data (first request)", i);
sleep(Duration::from_millis(50)).await;
let data = Bytes::from(format!("Block data for CID {}", i));
coalescer_clone.complete_request(&cid_clone, data).await;
println!(" Request {}: Completed fetch in {:?}", i, start.elapsed());
}
});
handles.push(handle);
if i == 0 {
sleep(Duration::from_millis(5)).await;
}
}
for handle in handles {
handle.await?;
}
let stats = coalescer.stats().await;
println!("\nCoalescing Statistics:");
println!(" Total requests: {}", stats.total_requests);
println!(" Unique requests: {}", stats.unique_requests);
println!(" Coalesced requests: {}", stats.coalesced_requests);
println!(" Efficiency: {:.1}%", stats.efficiency() * 100.0);
println!(" Reduction ratio: {:.1}%", stats.reduction_ratio() * 100.0);
println!(
" Average waiters per request: {:.1}",
stats.avg_waiters_per_request
);
Ok(())
}
async fn demonstrate_connection_migration() -> Result<(), Box<dyn std::error::Error>> {
println!("--- Connection Migration Demonstration ---");
let config = MigrationConfig {
enable_auto_migration: true,
migration_timeout: Duration::from_secs(5),
max_retries: 3,
grace_period: Duration::from_secs(2),
..Default::default()
};
let migration = Arc::new(ConnectionMigration::new(config));
let event_count = Arc::new(std::sync::atomic::AtomicUsize::new(0));
let count_clone = event_count.clone();
migration
.on_event(move |event| {
count_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
match event {
ipfrs_transport::MigrationEvent::NetworkChangeDetected { old_addr, new_addr } => {
println!(" Event: Network change detected");
println!(" Old address: {}", old_addr);
println!(" New address: {}", new_addr);
}
ipfrs_transport::MigrationEvent::MigrationStarted {
connection_id,
from_addr,
to_addr,
} => {
println!(" Event: Migration started");
println!(" Connection: {}", connection_id);
println!(" From: {} -> To: {}", from_addr, to_addr);
}
ipfrs_transport::MigrationEvent::MigrationCompleted {
connection_id,
new_addr,
duration,
} => {
println!(" Event: Migration completed");
println!(" Connection: {}", connection_id);
println!(" New address: {}", new_addr);
println!(" Duration: {:?}", duration);
}
ipfrs_transport::MigrationEvent::MigrationFailed {
connection_id,
reason,
retry_count,
} => {
println!(" Event: Migration failed");
println!(" Connection: {}", connection_id);
println!(" Reason: {}", reason);
println!(" Retry count: {}", retry_count);
}
}
})
.await;
println!("Scenario 1: Successful migration (WiFi -> Cellular)\n");
let old_addr = "192.168.1.100:8000".parse()?;
let new_addr = "10.0.0.50:8000".parse()?;
migration
.start_migration("conn1".to_string(), old_addr, new_addr)
.await?;
sleep(Duration::from_millis(100)).await;
migration.complete_migration("conn1").await?;
println!("\nScenario 2: Failed migration with retry\n");
let old_addr2 = "192.168.1.100:8001".parse()?;
let new_addr2 = "10.0.0.51:8001".parse()?;
migration
.start_migration("conn2".to_string(), old_addr2, new_addr2)
.await?;
sleep(Duration::from_millis(50)).await;
let _ = migration
.fail_migration("conn2", "Network timeout".to_string())
.await;
sleep(Duration::from_millis(50)).await;
let _ = migration
.fail_migration("conn2", "Network timeout".to_string())
.await;
sleep(Duration::from_millis(50)).await;
let _ = migration
.fail_migration("conn2", "Network timeout".to_string())
.await;
let stats = migration.stats().await;
println!("\nMigration Statistics:");
println!(" Total migrations: {}", stats.total_migrations);
println!(" Successful: {}", stats.successful_migrations);
println!(" Failed: {}", stats.failed_migrations);
println!(" Success rate: {:.1}%", stats.success_rate() * 100.0);
println!(" Average duration: {:?}", stats.avg_migration_duration);
println!(
" Total events received: {}",
event_count.load(std::sync::atomic::Ordering::SeqCst)
);
Ok(())
}
async fn demonstrate_advanced_scheduling() -> Result<(), Box<dyn std::error::Error>> {
println!("--- Advanced Scheduling Demonstration ---");
let policies = vec![
(SchedulingPolicy::Fifo, "FIFO"),
(SchedulingPolicy::ShortestJobFirst, "Shortest Job First"),
(
SchedulingPolicy::EarliestDeadlineFirst,
"Earliest Deadline First",
),
(
SchedulingPolicy::WeightedFairQueueing,
"Weighted Fair Queueing",
),
(SchedulingPolicy::MultilevelFeedback, "Multi-Level Feedback"),
];
for (policy, name) in policies {
println!("\n{} Policy:", name);
demonstrate_scheduling_policy(policy).await?;
}
Ok(())
}
async fn demonstrate_scheduling_policy(
policy: SchedulingPolicy,
) -> Result<(), Box<dyn std::error::Error>> {
let scheduler = AdvancedScheduler::new(policy);
let requests = vec![
ScheduledRequest::new(dummy_cid(1), SchedulePriority::Low)
.with_size(10_000_000)
.with_deadline(Instant::now() + Duration::from_secs(60)),
ScheduledRequest::new(dummy_cid(2), SchedulePriority::Normal)
.with_size(1_000)
.with_deadline(Instant::now() + Duration::from_secs(30)),
ScheduledRequest::new(dummy_cid(3), SchedulePriority::High)
.with_size(100_000)
.with_deadline(Instant::now() + Duration::from_secs(5)),
ScheduledRequest::new(dummy_cid(4), SchedulePriority::Urgent)
.with_size(500)
.with_deadline(Instant::now() + Duration::from_secs(1)),
ScheduledRequest::new(dummy_cid(5), SchedulePriority::Critical)
.with_size(50_000)
.with_deadline(Instant::now() + Duration::from_millis(100)),
];
for req in requests {
scheduler.schedule(req).await;
}
println!(" Scheduled 5 requests with varying priorities, sizes, and deadlines");
println!(" Processing order:");
let mut order = vec![];
while let Some(req) = scheduler.next().await {
let size_str = req
.estimated_size
.map(|s| format!("{} bytes", s))
.unwrap_or_else(|| "unknown".to_string());
let deadline_str = req
.deadline
.map(|d| {
if d > Instant::now() {
format!("{}s from now", d.duration_since(Instant::now()).as_secs())
} else {
"overdue".to_string()
}
})
.unwrap_or_else(|| "none".to_string());
println!(
" CID {:?}: priority={:?}, size={}, deadline={}",
req.cid, req.priority, size_str, deadline_str
);
let completion_time = Duration::from_millis(10);
scheduler.mark_completed(&req, completion_time).await;
order.push(req.cid);
}
let stats = scheduler.stats().await;
println!("\n Scheduling Statistics:");
println!(" Total scheduled: {}", stats.total_scheduled);
println!(" Total completed: {}", stats.total_completed);
println!(" Average wait time: {:?}", stats.avg_wait_time);
println!(
" Average completion time: {:?}",
stats.avg_completion_time
);
println!(" Deadline misses: {}", stats.deadline_misses);
println!(
" Deadline miss rate: {:.1}%",
stats.deadline_miss_rate() * 100.0
);
Ok(())
}