summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-04 22:52:42 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-04 22:52:42 +0100
commit2707f03617478e2a5e521961c46c9c6511d5088d (patch)
treea3516660f36614b006ea44eecf92bb4ff709fa3b /server/src
parent2c1d8fdfd65ceb9361114f0105c23ff6a94bac2e (diff)
downloadweareserver-2707f03617478e2a5e521961c46c9c6511d5088d.tar
weareserver-2707f03617478e2a5e521961c46c9c6511d5088d.tar.bz2
weareserver-2707f03617478e2a5e521961c46c9c6511d5088d.tar.zst
a
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main.rs129
1 files changed, 127 insertions, 2 deletions
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(())
+ }
}