use karlcommon::{ServerboundPacket, ProtoError, ClientboundPacket, version}; use log::{debug, error, info}; use std::net::{TcpListener, TcpStream}; use std::thread; use tungstenite::{accept, Message}; use crate::{handle_packet, CLIENT_ID_COUNTER}; pub fn run() { info!("binding websocket server"); let server = TcpListener::bind("127.0.0.1:9001").unwrap(); info!("listening"); for stream in server.incoming() { thread::spawn(move || { if let Err(e) = handle_connection(stream) { error!("{e}"); } }); } } fn handle_connection(stream: Result) -> anyhow::Result<()> { let id = CLIENT_ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed); let stream = stream?; stream.set_nonblocking(true)?; let mut websocket = accept(stream)?; let (responder, responses) = crossbeam_channel::unbounded(); responder .send(ClientboundPacket::Handshake { version: version!(), }) .unwrap(); loop { match websocket.read_message() { Ok(Message::Text(t)) => { debug!("<- {t:?}"); match serde_json::from_str::(&t) { Ok(packet) => { handle_packet(id, packet, responder.clone()) }, Err(e) => { responder.send(karlcommon::ClientboundPacket::Error(ProtoError::FormatError(format!("{e}"))))? }, } } Ok(_) => (), Err(tungstenite::Error::ConnectionClosed) => { break Ok(()); } Err(tungstenite::Error::Io(e)) if let std::io::ErrorKind::WouldBlock = e.kind() => { // its fine } Err(e) => Err(e)?, } for r in responses.try_iter() { websocket.write_message(Message::Text( serde_json::to_string(&r)?))?; } thread::sleep(std::time::Duration::from_millis(50)); // how would you do this properly?? } }