use anyhow::Result; use clap::Parser; use log::{debug, info}; use std::{ collections::HashMap, io::{BufReader, BufWriter, Write}, net::{IpAddr, TcpListener, TcpStream}, sync::{ Arc, Mutex, mpsc::{Receiver, Sender, channel}, }, thread::spawn, }; use weareshared::{ packets::{Packet, ReadWrite}, store::ResourceStore, tree::SceneTree, }; #[derive(Parser, Debug)] struct Args { #[arg(short, long, default_value = "::0")] bind_addr: IpAddr, #[arg(short, long, default_value = "28555")] port: u16, } struct State { tx: HashMap>, store: ResourceStore, tree: SceneTree, } fn main() -> Result<()> { env_logger::init_from_env("LOG"); let args = Args::parse(); let listener = TcpListener::bind((args.bind_addr, args.port))?; info!("bound to {}", listener.local_addr()?); let state = Arc::new(Mutex::new(State::new()?)); for conn in 0.. { let (sock, addr) = listener.accept()?; info!("{addr} connected"); let (tx, rx) = channel(); let state2 = state.clone(); let sock2 = sock.try_clone().unwrap(); spawn(move || { for p in state2.lock().unwrap().tree.prime_client() { tx.send(p).unwrap(); } state2.lock().unwrap().tx.insert(conn, tx); let _ = handle_conn_read(conn, sock, state2.clone()); info!("{addr} disconnected"); state2.lock().unwrap().tx.remove(&conn); }); spawn(move || { let _ = handle_conn_write(conn, sock2, rx); }); } Ok(()) } fn handle_conn_read(conn: usize, sock: TcpStream, state: Arc>) -> Result<()> { let mut sock = BufReader::new(sock); loop { let packet = Packet::read(&mut sock)?; debug!("{conn} <- {packet:?}"); state.lock().unwrap().handle_packet(conn, packet)?; } } fn handle_conn_write(conn: usize, sock: TcpStream, rx: Receiver) -> Result<()> { let mut sock = BufWriter::new(sock); for packet in rx { debug!("{conn} -> {packet:?}"); packet.write(&mut sock)?; sock.flush()?; } Ok(()) } impl State { pub fn new() -> Result { Ok(Self { tx: HashMap::new(), store: ResourceStore::new_persistent( &xdg::BaseDirectories::with_prefix("weareserver")?.place_cache_file("resources")?, )?, tree: SceneTree::default(), }) } pub fn broadcast(&self, packet: Packet) -> Result<()> { for tx in self.tx.values() { tx.send(packet.clone())?; } Ok(()) } pub fn send(&self, conn: usize, packet: Packet) -> Result<()> { if let Some(tx) = self.tx.get(&conn) { tx.send(packet)?; } Ok(()) } pub fn handle_packet(&mut self, conn: usize, packet: Packet) -> Result<()> { self.tree.update(&packet); match packet { Packet::RequestResource(resource) => { if let Some(r) = self.store.get(resource)? { self.send(conn, Packet::RespondResource(r))?; } else { self.broadcast(Packet::RequestResource(resource))?; } } Packet::RespondResource(data) => { self.store.set(&data)?; self.broadcast(Packet::RespondResource(data))?; } Packet::Add(object, resource) => { self.broadcast(Packet::Add(object, resource))?; } Packet::Remove(object) => { self.broadcast(Packet::Remove(object))?; } Packet::Position(object, pos, rot) => { self.broadcast(Packet::Position(object, pos, rot))?; } Packet::Pose(object, vec) => { self.broadcast(Packet::Pose(object, vec))?; } Packet::Parent(parent, child) => { self.broadcast(Packet::Parent(parent, child))?; } Packet::Sound(object, vec) => { self.broadcast(Packet::Sound(object, vec))?; } } Ok(()) } }