#![allow(
clippy::expect_used,
clippy::unwrap_used,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::doc_markdown,
clippy::indexing_slicing,
clippy::cast_possible_truncation,
clippy::panic
)]
#[cfg(not(target_os = "linux"))]
fn main() {
eprintln!("talaris quickstart: skipped — io_uring 只在 Linux 上可用");
}
#[cfg(target_os = "linux")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener};
use std::sync::mpsc;
use std::thread;
use std::time::{Duration, Instant};
use talaris::connection_meta::{ConnectionConfig, State};
use talaris::proactor::pin_current_thread_to;
use talaris::ws::Event as WsEvent;
use talaris::{Pool, PoolConfig};
let user_cpu = parse_cpu_args();
eprintln!("[quickstart] user thread → CPU {user_cpu}");
eprintln!(
"[quickstart] 提示:进程父 affinity 必须覆盖目标 CPU,建议外面套 \
`taskset -c 0-N`"
);
let listener = TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0))?;
let addr = listener.local_addr()?;
let (_shutdown_tx, shutdown_rx) = mpsc::channel::<()>();
let server = thread::Builder::new()
.name("quickstart-echo".into())
.spawn(move || ws_echo_server(&listener, &shutdown_rx))?;
eprintln!("[quickstart] in-process WS echo server up on {addr}");
pin_current_thread_to(user_cpu)?;
let cfg = ConnectionConfig::new("localhost", addr.port(), "/echo").with_tls(false);
let mut pool = Pool::new(PoolConfig::default())?;
let handle = pool.connect_blocking_to(cfg, addr)?;
assert_eq!(pool.state(handle), Some(State::Open));
eprintln!("[quickstart] WS upgrade OK, handle = {handle:?}");
let payload = br#"{"ping":"talaris"}"#;
let sent_at = Instant::now();
pool.send_text(handle, payload)?;
let deadline = Instant::now() + Duration::from_secs(5);
let mut got_echo = false;
while Instant::now() < deadline && !got_echo {
pool.pump(|_h, ev| {
if let WsEvent::Text(s) = ev {
eprintln!("[quickstart] ← {s}");
if s.contains("talaris") {
got_echo = true;
}
}
})?;
}
let rtt = sent_at.elapsed();
if got_echo {
eprintln!("[quickstart] round-trip RTT (loopback) = {rtt:?}");
} else {
eprintln!("[quickstart] timed out waiting for echo");
}
pool.initiate_close(handle, 1000, "bye")?;
let deadline = Instant::now() + Duration::from_secs(2);
while Instant::now() < deadline && !matches!(pool.state(handle), Some(State::Closed)) {
let _ = pool.pump_nowait(|_, _| {});
}
server.join().expect("server thread");
Ok(())
}
#[cfg(target_os = "linux")]
fn parse_cpu_args() -> usize {
let mut user_cpu = 1_usize;
let mut args = std::env::args().skip(1);
while let Some(a) = args.next() {
if a.as_str() == "--user-cpu"
&& let Some(v) = args.next().and_then(|s| s.parse().ok())
{
user_cpu = v;
}
}
user_cpu
}
#[cfg(target_os = "linux")]
fn ws_echo_server(listener: &std::net::TcpListener, _shutdown: &std::sync::mpsc::Receiver<()>) {
use std::io::{Read, Write};
use talaris::ws::OpCode;
use talaris::ws::frame::{MAX_HEADER_LEN, encode_header};
use talaris::ws::handshake::compute_accept;
use talaris::ws::mask::mask_inplace;
let (mut s, _) = listener.accept().expect("accept");
s.set_nodelay(true).expect("nodelay");
let mut buf = [0_u8; 4096];
let mut req = Vec::<u8>::new();
loop {
let n = s.read(&mut buf).expect("read upgrade");
assert!(n > 0, "client closed mid-upgrade");
req.extend_from_slice(&buf[..n]);
if req.windows(4).any(|w| w == b"\r\n\r\n") {
break;
}
}
let req_str = std::str::from_utf8(&req).expect("utf8");
let key = req_str
.lines()
.find(|l| l.to_ascii_lowercase().starts_with("sec-websocket-key:"))
.and_then(|l| l.split(':').nth(1))
.expect("Sec-WebSocket-Key")
.trim();
let accept = compute_accept(key);
let resp = format!(
"HTTP/1.1 101 Switching Protocols\r\n\
Upgrade: websocket\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: {accept}\r\n\r\n"
);
s.write_all(resp.as_bytes()).expect("write upgrade resp");
let (opcode, payload) = read_one_frame(&mut s);
assert_eq!(opcode, OpCode::Text);
let mut frame = vec![0_u8; MAX_HEADER_LEN];
let hn = encode_header(&mut frame, true, OpCode::Text, None, payload.len() as u64);
frame.truncate(hn);
frame.extend_from_slice(&payload);
s.write_all(&frame).expect("write echo");
let (close_op, _) = read_one_frame(&mut s);
assert_eq!(close_op, OpCode::Close);
let mut close_frame = vec![0_u8; MAX_HEADER_LEN + 2];
let hn = encode_header(&mut close_frame, true, OpCode::Close, None, 2);
close_frame.truncate(hn);
close_frame.extend_from_slice(&1000_u16.to_be_bytes());
let _ = s.write_all(&close_frame);
let _ = mask_inplace;
}
#[cfg(target_os = "linux")]
fn read_one_frame(stream: &mut std::net::TcpStream) -> (talaris::ws::OpCode, Vec<u8>) {
use std::io::Read;
use talaris::ws::OpCode;
use talaris::ws::mask::mask_inplace;
let mut hdr = [0_u8; 2];
stream.read_exact(&mut hdr).expect("hdr");
let fin = (hdr[0] & 0x80) != 0;
assert!(fin, "fragmented frame not supported in quickstart server");
let opcode = match hdr[0] & 0x0F {
0x1 => OpCode::Text,
0x2 => OpCode::Binary,
0x8 => OpCode::Close,
0x9 => OpCode::Ping,
0xA => OpCode::Pong,
other => panic!("unsupported opcode 0x{other:x}"),
};
let masked = (hdr[1] & 0x80) != 0;
let len_field = hdr[1] & 0x7F;
let len: usize = match len_field {
0..=125 => usize::from(len_field),
126 => {
let mut b = [0_u8; 2];
stream.read_exact(&mut b).expect("len16");
usize::from(u16::from_be_bytes(b))
}
127 => {
let mut b = [0_u8; 8];
stream.read_exact(&mut b).expect("len64");
usize::try_from(u64::from_be_bytes(b)).expect("u64→usize")
}
_ => unreachable!("len_field is masked to 7 bits"),
};
let mut mask = [0_u8; 4];
if masked {
stream.read_exact(&mut mask).expect("mask key");
}
let mut payload = vec![0_u8; len];
stream.read_exact(&mut payload).expect("payload");
if masked {
mask_inplace(&mut payload, mask);
}
(opcode, payload)
}