WebSockets are routes, registered the same way as HTTP handlers.
app_ws(pattern, handler) uses the same
{param} matcher — so a chat room is just a param.
import "std/websocket" fn ws_room_handler(info: Array) -> int { let fd: int = info[0] let headers: Array = info[2] let params: Array = info[3] // flat [k1, v1, k2, v2, ...] var room: String = "?" var i: int = 0 while i + 1 < params.length() { let k: String = params[i] if k == "room" { let v: String = params[i + 1] room = v } i = i + 2 } let key: String = http_find_header(headers, "Sec-WebSocket-Key") tcp_write(fd, ws_handshake_response(key)) let data: String = tcp_read_partial(fd, 4096) if data.length() > 0 and !ws_is_close(data) { let msg: String = ws_parse(data) tcp_write(fd, ws_frame("[" + room + "] " + msg)) } tcp_write(fd, ws_close()) tcp_close(fd) return 1 // we own the fd — the server won't touch it } fn main() { let app: App = app_new() app_ws("/ws/chat/{room}", ws_room_handler) serve_app(app, 3000, 8) }
The handler's contract:
[fd, path, headers_flat, params_flat] — the raw socket, the path, the request headers, and the matched {params} as a flat array.1 to take ownership: you do the handshake with ws_handshake_response, read frames with ws_parse, write with ws_frame, and close yourself. The server never touches the fd again.0 to decline and let the request fall through.Connect with any WebSocket client to ws://localhost:3000/ws/chat/general and send a message — you get back [general] your message. The {room} param proves it routed.
std/websocket.