diff --git a/Cargo.lock b/Cargo.lock index c4b7a81..0ed3d7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,55 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -44,21 +93,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.7.2" @@ -71,30 +105,64 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "collarmc" version = "0.1.0" dependencies = [ + "clap", "dashmap", "futures-util", - "serde", - "serde_json", - "serde_repr", "tokio", - "tokio-tungstenite", "tracing", "tracing-subscriber", "uuid", ] [[package]] -name = "cpufeatures" -version = "0.2.14" +name = "colorchoice" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" -dependencies = [ - "libc", -] +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "crossbeam-utils" @@ -102,16 +170,6 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "dashmap" version = "6.1.0" @@ -126,28 +184,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "futures-core" version = "0.3.30" @@ -165,12 +201,6 @@ dependencies = [ "syn", ] -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - [[package]] name = "futures-task" version = "0.3.30" @@ -185,23 +215,12 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-macro", - "futures-sink", "futures-task", "pin-project-lite", "pin-utils", "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -225,6 +244,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -232,27 +257,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] -name = "http" -version = "1.1.0" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "lazy_static" @@ -384,15 +392,6 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - [[package]] name = "proc-macro2" version = "1.0.86" @@ -411,36 +410,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - [[package]] name = "redox_syscall" version = "0.5.7" @@ -456,12 +425,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - [[package]] name = "scopeguard" version = "1.2.0" @@ -488,40 +451,6 @@ dependencies = [ "syn", ] -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -565,6 +494,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.79" @@ -576,26 +511,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "thiserror" -version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "thread_local" version = "1.1.8" @@ -635,18 +550,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - [[package]] name = "tracing" version = "0.1.40" @@ -704,30 +607,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicode-ident" version = "1.0.13" @@ -735,10 +614,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] -name = "utf-8" -version = "0.7.6" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -756,12 +635,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -862,24 +735,3 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index 20204e5..6d74192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,13 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] +clap = { version = "4.5.19", features = ["derive"] } dashmap = "6.1.0" futures-util = "0.3.30" -serde = { version = "1.0.210", features = ["derive"] } -serde_json = "1.0.128" -serde_repr = "0.1.19" tokio = { version = "1.40", features = ["full"] } -tokio-tungstenite = "0.24" tracing = "0.1.40" tracing-subscriber = "0.3.18" uuid = { version = "1.10.0", features = ["serde", "v4"] } diff --git a/src/main.rs b/src/main.rs index 96f3a89..2f0a222 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,43 @@ -use std::{env, io::Error, sync::OnceLock}; +use std::{io::Error, net::SocketAddr, sync::{Arc, OnceLock}}; +use clap::Parser; use futures_util::{stream::SplitSink, SinkExt, StreamExt}; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::{TcpListener, TcpStream, UdpSocket}; use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; +#[derive(Parser)] +struct Cli { + /// address to bind to + #[arg(long, short, default_value = "127.0.0.1:25580")] + addr: String, + + /// how many worker threads to spawn to handle packets + #[arg(long, short, default_value_t = 1)] + workers: u32, +} + #[repr(i8)] -#[derive(Debug, serde_repr::Deserialize_repr, serde_repr::Serialize_repr)] +#[derive(Debug)] enum Dimension { End = 1, Overworld = 0, Nether = -1, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] +impl Dimension { + fn n(self) -> u8 { + match self { + Self::End => 1, + Self::Overworld => 0, + Self::Nether => 255, + } + } +} + +type Secret = [u8; 256]; + +#[derive(Debug)] struct UserPosition { + secret: Secret, id: uuid::Uuid, dimension: Dimension, x: f64, @@ -20,19 +45,43 @@ struct UserPosition { z: f64, } -#[derive(Debug, serde::Deserialize, serde::Serialize)] -struct UserJoin { - id: uuid::Uuid, - secret: String, +const PACKET_SIZE : usize = std::mem::size_of::(); + +impl UserPosition { + fn pack(self) -> Vec { + let mut out = Vec::new(); + out.copy_from_slice(&self.secret); + out.copy_from_slice(&self.id.as_u128().to_be_bytes()); + out.push(self.dimension.n()); + out.copy_from_slice(&self.x.to_be_bytes()); + out.copy_from_slice(&self.y.to_be_bytes()); + out.copy_from_slice(&self.z.to_be_bytes()); + + out + } + + fn unpack(data: &[u8; PACKET_SIZE]) -> Self { + let secret = data.; + + + Self { + secret, + id, + dimension, + x, + y, + z, + } + } } #[derive(Debug)] struct Peer { id: uuid::Uuid, - tx: SplitSink, Message>, + addr: SocketAddr, } -type Store = dashmap::DashMap>; +type Store = dashmap::DashMap>; fn store() -> &'static Store { static STORE: OnceLock = OnceLock::new(); @@ -43,106 +92,28 @@ fn store() -> &'static Store { async fn main() -> Result<(), Error> { tracing_subscriber::fmt().init(); - tracing::info!("some uuid: {}", uuid::Uuid::new_v4()); - tracing::info!("some packet: {}", serde_json::to_string(&UserPosition { - id: uuid::Uuid::new_v4(), - dimension: Dimension::Overworld, - x: 0.0, - y: 0.0, - z: 0.0, - }).unwrap()); + let args = Cli::parse(); - let addr = env::args().nth(1).unwrap_or_else(|| "127.0.0.1:8080".to_string()); + tracing::info!("Listening on: {}", args.addr); + let socket = Arc::new(UdpSocket::bind(args.addr).await?); - // Create the event loop and TCP listener we'll accept connections on. - let try_socket = TcpListener::bind(&addr).await; - let listener = try_socket.expect("Failed to bind"); - tracing::info!("Listening on: {}", addr); - - while let Ok((stream, _)) = listener.accept().await { - tokio::spawn(accept_connection(stream)); + for i in 0..args.workers { + tokio::spawn(handle_packets(i, socket.clone())); } Ok(()) } -async fn accept_connection(stream: TcpStream) { - let addr = stream.peer_addr().expect("connected streams should have a peer address"); - tracing::info!("Peer address: {}", addr); - - let ws_stream = tokio_tungstenite::accept_async(stream) - .await - .expect("Error during the websocket handshake occurred"); - - tracing::info!("New WebSocket connection: {}", addr); - - let (write, mut read) = ws_stream.split(); - - // TODO can we get the secret from http headers or maybe request path? this is super annoying - - let Some(Ok(msg)) = read.next().await else { - tracing::warn!("peer didn't send join packet, dropping {addr}"); - return; - }; - - let Message::Text(txt) = msg else { - tracing::warn!("join packet isn't a text message, dropping {addr}"); - return; - }; - - let Ok(join_packet) = serde_json::from_str::(&txt) else { - tracing::error!("failed parsing join packet, dropping {addr}"); - return; - }; - - let peer = Peer { - id: join_packet.id, - tx: write, - }; - - match store().get_mut(&join_packet.secret) { - Some(mut v) => v.value_mut().push(peer), - None => { store().insert(join_packet.secret.clone(), vec![peer]); }, - } - - while let Some(res) = read.next().await { - match res { - Ok(msg) => { - let Message::Text(ref txt) = msg else { - tracing::error!("peer {addr} sent non-json packet, dropping"); - break; - }; - - // just validate incoming packet - let Ok(_packet) = serde_json::from_str::(txt) else { - tracing::error!("peer {addr} sent invalid json, dropping.\n{txt}"); - break; - }; - - let Some(mut others) = store().get_mut(&join_packet.secret) else { - tracing::error!("session closed, dropping peer {addr}"); - break; - }; - - for usr in others.value_mut() { - if usr.id == join_packet.id { continue } // dont send back to self - if let Err(e) = usr.tx.send(msg.clone()).await { - tracing::error!("failed sending position to {}: {e}", usr.id); - } - } - }, +async fn handle_packets(worker_id: u32, sock: Arc) { + let mut buffer = [0u8; PACKET_SIZE]; + let x = 10u64; + loop { + match sock.recv_from(&mut buffer).await { + Ok((count, addr)) => {}, Err(e) => { - tracing::error!("error receiving from peer {addr}: {e}"); + tracing::error!("worker #{worker_id} failed receiving from socket: {e}"); break; }, } } - - tracing::info!("peer {addr} disconnected"); - - if let Some(mut store) = store().get_mut(&join_packet.secret) { - store.value_mut().retain(|x| x.id != join_packet.id); - } else { - tracing::error!("failed accessing store to drop {addr}'s channel"); - } }