summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/Cargo.toml5
-rw-r--r--server/src/main.rs129
2 files changed, 132 insertions, 2 deletions
diff --git a/server/Cargo.toml b/server/Cargo.toml
index a504e65..3a091bd 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -5,3 +5,8 @@ edition = "2024"
[dependencies]
anyhow = "1.0.95"
+clap = { version = "4.5.23", features = ["derive"] }
+env_logger = "0.11.6"
+log = "0.4.22"
+weareshared = { path = "../shared" }
+xdg = "2.5.2"
diff --git a/server/src/main.rs b/server/src/main.rs
index e7a11a9..02ea03f 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -1,3 +1,128 @@
-fn main() {
- println!("Hello, world!");
+use anyhow::Result;
+use clap::Parser;
+use log::{debug, info};
+use std::{
+ collections::HashMap,
+ io::{BufReader, BufWriter},
+ net::{IpAddr, TcpListener, TcpStream},
+ sync::{
+ Arc, Mutex,
+ mpsc::{Receiver, Sender, channel},
+ },
+ thread::spawn,
+};
+use weareshared::{packets::Packet, 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<usize, Sender<Packet>>,
+ 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();
+ state.lock().unwrap().tx.insert(conn, tx);
+ let state2 = state.clone();
+ let sock2 = sock.try_clone().unwrap();
+ spawn(move || {
+ 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<Mutex<State>>) -> Result<()> {
+ let mut sock = BufReader::new(sock);
+ loop {
+ let packet = Packet::deserialize(&mut sock)?;
+ debug!("{conn} <- {packet:?}");
+ state.lock().unwrap().handle_packet(conn, packet)?;
+ }
+}
+fn handle_conn_write(conn: usize, sock: TcpStream, rx: Receiver<Packet>) -> Result<()> {
+ let mut sock = BufWriter::new(sock);
+ for packet in rx {
+ debug!("{conn} -> {packet:?}");
+ packet.serialize(&mut sock)?;
+ }
+ Ok(())
+}
+impl State {
+ pub fn new() -> Result<Self> {
+ Ok(Self {
+ tx: HashMap::new(),
+ store: ResourceStore::new(
+ &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(resource, r))?;
+ } else {
+ self.broadcast(Packet::RequestResource(resource))?;
+ }
+ }
+ Packet::RespondResource(resource, vec) => {
+ self.broadcast(Packet::RespondResource(resource, vec))?;
+ }
+ 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(())
+ }
}