use nwep::{Address, Client, Identity, Method, RangeOutcome, Server, Status};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
fn now_ms() -> i64 {
use std::sync::OnceLock;
static START: OnceLock<Instant> = OnceLock::new();
START.get_or_init(Instant::now).elapsed().as_millis() as i64
}
const PAGE: &[u8] = b"the quick brown fox jumps over the lazy dog";
const ETAG: &str = "\"v1\"";
fn main() -> nwep::Result<()> {
let (tx, rx) = mpsc::channel();
let stop = Arc::new(AtomicBool::new(false));
let stop_t = stop.clone();
let server_thread = std::thread::spawn(move || {
let server = Server::builder()
.identity(Identity::generate().unwrap())
.bind(Address::loopback(0))
.on_request(|req, res| {
if req.path() != Some("/page") {
return res.not_found();
}
if req.is_fresh(ETAG) {
return res.not_modified(ETAG);
}
let total = PAGE.len() as u64;
match req.range(total, Some(ETAG)) {
Ok(RangeOutcome::Ranges(rs)) => {
res.header("etag", ETAG).partial(PAGE, &rs, "text/plain")
}
Ok(RangeOutcome::Unsatisfiable) => res.range_not_satisfiable(total),
_ => res.header("etag", ETAG).ok(PAGE),
}
})
.build()
.unwrap();
tx.send((server.node_id().unwrap(), server.local_port()))
.unwrap();
while !stop_t.load(Ordering::Relaxed) {
server.tick(now_ms()).unwrap();
std::thread::sleep(Duration::from_millis(1));
}
});
let (node, port) = rx.recv_timeout(Duration::from_secs(3)).unwrap();
let client = Client::builder()
.identity(Identity::generate()?)
.connect(&node, &Address::loopback(port))?;
let full = client.send(Method::Read, "/page", &[])?;
let etag = full.header("etag").unwrap_or("?").to_owned();
println!(
"full read -> {} {:?} (etag {})",
full.status().unwrap_or(Status::Error),
String::from_utf8_lossy(full.body()),
etag
);
let part = client
.request(Method::Read, "/page")
.header("range", "bytes=4-8")
.send()?;
println!(
"range 4-8 -> {} {:?}",
part.status().unwrap_or(Status::Error),
String::from_utf8_lossy(part.body())
);
let over = client
.request(Method::Read, "/page")
.header("range", "bytes=999-1099")
.send()?;
println!("range 999- -> {}", over.status().unwrap_or(Status::Error));
let fresh = client
.request(Method::Read, "/page")
.header("if-none-match", ETAG)
.send()?;
println!(
"if-none-match-> {} (body {} bytes)",
fresh.status().unwrap_or(Status::Error),
fresh.body().len()
);
stop.store(true, Ordering::Relaxed);
server_thread.join().unwrap();
Ok(())
}