use std::sync::Arc;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio::sync::oneshot;
use zerust::datapack::DataPack;
use zerust::{DefaultRouter, Response, Server};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
let router = Arc::new(DefaultRouter::new());
let router_clone = router.clone();
router_clone.add_route(1, |req| {
println!("Received echo request: {:?}", req.data());
Response::new(req.msg_id(), req.data().to_vec()) });
let server = Server::new("127.0.0.1:8000", router);
let server_handle = tokio::spawn(async move {
if let Err(e) = server.run(shutdown_rx).await {
eprintln!("[Zerust] Server runtime error: {}", e);
}
});
if let Err(_) = wait_for_server(8000, Duration::from_secs(5)).await {
eprintln!("[Client] Failed to connect to server within 5 seconds.");
return Err("Server did not start in time".into());
}
println!("[Client] Server is ready. Proceeding with test...");
match client().await {
Ok(()) => println!("✅ Client finished successfully."),
Err(e) => eprintln!("❌ Client error: {}", e),
}
let _ = shutdown_tx.send(());
println!("[Main] Shutdown signal sent.");
let _ = server_handle.await;
println!("🎉 Program exited gracefully.");
Ok(())
}
async fn client() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("127.0.0.1:8000").await?;
println!("Connected to server");
let bytes = DataPack::pack(1, b"test");
stream.write_all(&bytes).await?;
println!("Sent request: msg_id=1, data=test");
let mut header = [0u8; 8];
stream.read_exact(&mut header).await?;
let (msg_id, data_len) = DataPack::unpack_header(&header)?;
println!(
"Received response header: msg_id={}, data_len={}",
msg_id, data_len
);
let mut data = vec![0u8; data_len as usize];
stream.read_exact(&mut data).await?;
println!(
"Received response: msg_id={}, data={:?}",
msg_id,
String::from_utf8_lossy(&data)
);
Ok(())
}
async fn wait_for_server(port: u16, timeout: Duration) -> Result<(), Box<dyn std::error::Error>> {
let deadline = tokio::time::Instant::now() + timeout;
loop {
let connect_fut = TcpStream::connect(("127.0.0.1", port));
if tokio::time::timeout(deadline - tokio::time::Instant::now(), connect_fut)
.await
.is_ok()
{
return Ok(()); }
tokio::time::sleep(Duration::from_millis(10)).await;
}
}