diff --git a/Cargo.lock b/Cargo.lock index 3f22ffc..974a491 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", "zerocopy", @@ -64,9 +63,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -93,7 +92,7 @@ dependencies = [ "sync_wrapper 1.0.1", "tokio", "tokio-tungstenite", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -101,9 +100,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -114,7 +113,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -137,9 +136,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -185,9 +184,12 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.104" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -195,6 +197,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -369,9 +380,14 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "fastrand" @@ -449,6 +465,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -469,6 +496,7 @@ checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -516,21 +544,18 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -649,6 +674,8 @@ dependencies = [ "hyper", "pin-project-lite", "tokio", + "tower 0.4.13", + "tower-service", ] [[package]] @@ -826,9 +853,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -1004,6 +1031,8 @@ name = "open_tavern" version = "0.1.0" dependencies = [ "axum", + "futures-util", + "parking_lot", "serde", "serde_json", "sqlx", @@ -1011,6 +1040,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1318,6 +1353,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1351,6 +1392,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1393,9 +1437,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "93334716a037193fac19df402f8571269c84a00852f6a7066b5d2616dcd64d3e" dependencies = [ "sqlx-core", "sqlx-macros", @@ -1406,11 +1450,10 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "d4d8060b456358185f7d50c55d9b5066ad956956fddec42ee2e8567134a8936e" dependencies = [ - "ahash", "atoi", "byteorder", "bytes", @@ -1423,6 +1466,7 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", + "hashbrown", "hashlink", "hex", "indexmap", @@ -1445,22 +1489,22 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "cac0692bcc9de3b073e8d747391827297e075c7710ff6276d9f7a1f3d58c6657" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.68", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "1804e8a7c7865599c9c79be146dc8a9fd8cc86935fa641d3ea58e5f0688abaa5" dependencies = [ "dotenvy", "either", @@ -1474,8 +1518,9 @@ dependencies = [ "sha2", "sqlx-core", "sqlx-mysql", + "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.68", "tempfile", "tokio", "url", @@ -1483,9 +1528,9 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "64bb4714269afa44aef2755150a0fc19d756fb580a67db8885608cf02f47d06a" dependencies = [ "atoi", "base64", @@ -1525,9 +1570,9 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "6fa91a732d854c5d7726349bb4bb879bb9478993ceb764247660aee25f67c2f8" dependencies = [ "atoi", "base64", @@ -1563,9 +1608,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "d5b2cf34a45953bfd3daaf3db0f7a7878ab9b7a6b91b422d24a7a9e4c857b680" dependencies = [ "atoi", "flume", @@ -1578,10 +1623,10 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", ] [[package]] @@ -1768,9 +1813,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", @@ -1791,20 +1836,35 @@ dependencies = [ "tokio", "tower-layer", "tower-service", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", "tracing", ] [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -1840,9 +1900,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", @@ -1853,7 +1913,6 @@ dependencies = [ "rand", "sha1", "thiserror", - "url", "utf-8", ] @@ -1890,12 +1949,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -1913,12 +1966,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf-8" version = "0.7.6" diff --git a/Cargo.toml b/Cargo.toml index a4c20ea..3a205d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,11 @@ version = "0.1.0" edition = "2021" [dependencies] -axum = { version = "0.7.5", features = ["ws"] } +axum = { version = "0.7.7", features = ["ws"] } serde = "1.*.*" serde_json = "1.*.*" tokio = { version = "1.*.*", features = ["full"] } -sqlx = { version = "0.7.4", features = ["runtime-tokio", "sqlite"] } +sqlx = { version = "0.8.2", features = ["runtime-tokio", "sqlite"] } tavern_macros = { version = "0.1.0", path = "tavern_macros" } +parking_lot = "0.12.3" +futures-util = "0.3.30" diff --git a/readme.md b/readme.md index de85f0c..7fbfff7 100644 --- a/readme.md +++ b/readme.md @@ -1,77 +1,23 @@ # WTF how do i implement a game??? -## Things you need from a game +## Client todo -Characters and character sheet: - [x] Stats and items: get/set/display - [ ] Actions (broken into different tabs, aka: `(&self) -> Vec`) - [ ] Token status: status icons (with tooltip ffs)/light produced/vision distance(in light level) - [ ] Apply Action `(&mut self, InteractionResult) -> ()` -Spells and items +[ ] implement tavern functions +[ ] token drag & drop +[ ] Chat + [ ] Send new chat messages + [ ] recv new chat messages +[ ] roll a die when chat message requests that +[ ] figure out how to zoom on the mouse instead of the center of the div +[ ] data reqs -[ ]Turn based combat callbakcs: - [ ] Start of turn - `(&mut self) -> Vec` - [ ] End of turn - - -InteractionDef -> Player uses -> Interaction in chat (with actions) -> Rolls some dice -> Interaction - -Shoot arrow def -> - player A shoots B (rolls attack) -> I - nteraction in chat (with Roll damage button) -> - InteractionResult (damage/double/block/heal actions) -> - Apply InteractionResult () - -```rust -trait Action {} -trait CS { - - fn can_use_action(&self, action: &A) -> bool; -} -struct Game<'dec, 'dea, C: CS + Serialize + Deserialize<'dec>, A: Action + Serialize + Deserialize<'dea>> { - _a: std::marker::PhantomData<&'dea A>, - _c: std::marker::PhantomData<&'dec C>, -} -impl<'dec, 'dea, C: CS + Serialize + Deserialize<'dec>, A: Action + Serialize + Deserialize<'dea>> Game<'dec, 'dea, C, A> { - fn read_spell(s: &'dea str) -> A { - serde_json::de::from_str::(s).unwrap() - } -} - -#[derive(Serialize, Deserialize)] -struct Spell { - pub mana: i32, -} -impl Action for Spell {} - -#[derive(Serialize, Deserialize)] -struct Sheet; -impl CS for Sheet { - fn can_use_action(&self, action: &Spell) -> bool { - action.mana > 10 - } -} -fn stupid() { - let game = Game::<'_, '_, Sheet, Spell>::read_spell("aaaaaaaa"); -} -``` -^^^ this looks mad isnt it, but it defines 3 traits, Action, Character sheet and game(which should be a trait actually) - -1. Player connects -2. Player gets character data (including all the relevant actions and such) -3. Player acts - -1. Player does action -2. Action is printed to chat (with rolls and such) -3. Action button is pressed (optional rolls) - -fn use_action(&mut self, entry: &Entry, action: &Action) -> ChatMessage - -```rust -struct Action { - pub name: String, - pub roll_result: i32, -} - -``` +## Server todo +[ ] impl different requests +[ ] actual normal login +[ ] allow sending of old info +[ ] chat history +[ ] send texture (map/token/image) +[ ] force show something +[ ] mouse ping (ideally multiple types) +[ ] data reqs \ No newline at end of file diff --git a/src/api/login.rs b/src/api/login.rs index 835d19a..f7a28b7 100644 --- a/src/api/login.rs +++ b/src/api/login.rs @@ -6,7 +6,7 @@ pub struct LoginRequest { pub password: String, } -#[derive(Serialize)] +#[derive(Serialize, Clone)] pub struct LoginResult { pub success: bool, // TODO: Figure out what the user needs on successful login to reduce traffic diff --git a/src/api/mod.rs b/src/api/mod.rs index f5c92a0..08061d7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -4,21 +4,30 @@ pub mod map_actions; use serde::{Deserialize, Serialize}; +use crate::game::chat_message::ChatMessage; + #[derive(Serialize, Deserialize, Default, Debug)] #[serde(rename_all = "snake_case")] pub enum Request { #[default] Error, - Login(login::LoginRequest) + Login(login::LoginRequest), + Message(ChatMessage), + Quit, + Shutdown } -#[derive(Serialize)] +#[derive(Serialize, Clone)] #[serde(rename_all = "snake_case")] pub enum Response { Error(RequestError), - Login(login::LoginResult) + Login(login::LoginResult), + Message(ChatMessage), + Quit { id: String }, + Shutdown, + } -#[derive(Serialize, Debug)] +#[derive(Serialize, Debug, Clone)] #[serde(rename_all = "snake_case")] pub enum RequestError { InvalidRequest, diff --git a/src/game/chat_message.rs b/src/game/chat_message.rs index 0c13f81..586c7d0 100644 --- a/src/game/chat_message.rs +++ b/src/game/chat_message.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct ChatMessage { /// message text, `{item}` can be used to refer to items and such, where item is of the path such as `items/sword` or `spells/fireball` pub text: String, @@ -17,7 +17,7 @@ pub struct ChatMessage { pub targets: Option> } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct RollDialogOption { /// Field name pub name: String, diff --git a/src/lib.rs b/src/lib.rs index ef6e5d3..37474ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,34 @@ +use game::{Game, GameImpl}; +use tokio::sync::{broadcast, mpsc}; + pub mod user; pub mod table; pub mod api; pub mod game; -pub mod pathfinder2r_impl; \ No newline at end of file +pub mod pathfinder2r_impl; + +pub struct GameServer { + game: Game +} +impl GameServer { + pub fn new() -> Self { + Self { + game: Game::new(), + } + } + + pub async fn server_loop(mut self, mut msgs: mpsc::Receiver<(String, api::Request)>, mut broadcast: broadcast::Sender) { + while let Some(req) = msgs.recv().await { + // TODO: do stuff yo! + let (id, req) = req; + match req { + api::Request::Error => {}, + api::Request::Login(_) => {}, + api::Request::Message(msg) => { _ = broadcast.send(api::Response::Message(msg)); }, + api::Request::Quit => { _ = broadcast.send(api::Response::Quit { id })}, + api::Request::Shutdown => todo!(), + } + } + _ = broadcast.send(api::Response::Shutdown); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index f256a77..fb15575 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,61 +1,110 @@ use axum::{ extract::ws::{self,Message}, response, routing, Router }; +use futures_util::{stream::{SplitSink, SplitStream}, SinkExt, StreamExt}; use open_tavern::api::{Request, RequestError, Response}; +use tokio::sync::{broadcast, mpsc}; #[tokio::main] async fn main() { + let (bsend, _) = broadcast::channel(10); + let (msend, mrecv) = mpsc::channel(50); + let bsend2 = bsend.clone(); let app = Router::new() .route("/", routing::get(root)) .route("/socket.js", routing::get(socket)) - .route("/ws", routing::get(ws_handler)) - ; + .route("/ws", routing::get(move |w| ws_handler(w, msend, bsend2.clone().subscribe()))); let listener = tokio::net::TcpListener::bind("0.0.0.0:3001").await.unwrap(); - axum::serve(listener, app).await.unwrap(); + let game = open_tavern::GameServer::new(); + tokio::spawn(game.server_loop(mrecv, bsend)); + + axum::serve(listener, app).await.expect("axum server crashed, yaaaaay (unless i crashed him that yay)"); } -async fn ws_handler(ws: ws::WebSocketUpgrade) -> impl axum::response::IntoResponse { - ws.on_upgrade(handle_socket) +async fn ws_handler(ws: ws::WebSocketUpgrade, msend: mpsc::Sender<(String, Request)>, brecv: broadcast::Receiver) -> impl axum::response::IntoResponse { + ws.on_upgrade(|w| handle_socket(w, msend, brecv)) } -async fn handle_socket(mut socket: ws::WebSocket) { - let mut logged_in = false; - println!("Got a new socket"); +async fn socket_receiver(mut recv: SplitStream, msend: mpsc::Sender<(String, Request)>, id: String) { + while let Some(msg) = recv.next().await { + if let Ok(msg) = msg { + match msg { + Message::Text(t) => { + let req = serde_json::from_str::(&t).unwrap_or_default(); + println!("Got message: {:?}", t); + let erred = msend.send((id.clone(), req)).await.is_err(); + if erred { + break; + } + } + ws::Message::Binary(_) => todo!(), + ws::Message::Ping(_) => todo!(), + ws::Message::Pong(_) => todo!(), + ws::Message::Close(_) => { + // dont care if we fail the send as we are quitting regardless + _ = msend.send((id.clone(), open_tavern::api::Request::Quit)).await; + break; + }, + } + } + } +} + +async fn socket_sender(mut send: SplitSink, mut brecv: broadcast::Receiver) { + while let Ok(msg) = brecv.recv().await { + let err = send.send(ws::Message::Text(serde_json::to_string(&msg).unwrap())).await.is_err(); + if err { + break; + } + } +} + +async fn handle_socket(mut socket: ws::WebSocket, msend: mpsc::Sender<(String, Request)>, brecv: broadcast::Receiver) { + let mut id: Option = None; loop { if let Some(msg) = socket.recv().await { if let Ok(msg) = msg { - let response: Message = match msg { + match msg { Message::Text(t) => { let req = serde_json::from_str::(&t).unwrap_or_default(); println!("Got message: {:?}", t); match req { - Request::Error => Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap()), - Request::Login(r) => if !logged_in { - if r.username == "rusty" { - logged_in = true; - Message::Text(serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: true })).unwrap()) - } - else { - Message::Text(serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: false })).unwrap()) - } - } else { - Message::Text(serde_json::to_string(&Response::Error(open_tavern::api::RequestError::AlreadyLoggedIn)).unwrap()) + // TODO: Actual signing in mechanism with multiple ids :) + Request::Login(r) => if r.username == "rusty" { + _ = socket.send(Message::Text( + serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: true })).unwrap() + )).await; + id = Some(String::from("rusty")); + break; + } + else { + _ = socket.send(Message::Text( + serde_json::to_string(&Response::Login(open_tavern::api::login::LoginResult { success: false })).unwrap() + )).await; }, - } + _ => { + _ = socket.send(Message::Text(serde_json::to_string(&Response::Error(RequestError::InvalidRequest)).unwrap())).await; + }, + } } ws::Message::Binary(_) => todo!(), ws::Message::Ping(_) => todo!(), ws::Message::Pong(_) => todo!(), ws::Message::Close(_) => break, }; - socket.send(response).await.expect("failed sending to socket"); } } else { break; } } + if let Some(id) = id { + println!("Got id for socket: {}", &id); + let (send, recv) = socket.split(); + tokio::spawn(socket_receiver(recv, msend, id)); + tokio::spawn(socket_sender(send, brecv)); + } println!("Done with so-cat"); } diff --git a/src/pathfinder2r_impl/mod.rs b/src/pathfinder2r_impl/mod.rs index 0534e7f..da55e8b 100644 --- a/src/pathfinder2r_impl/mod.rs +++ b/src/pathfinder2r_impl/mod.rs @@ -1,10 +1,11 @@ use crate::game::{action::{ActionDefinition, ActionResult, GameEntry}, character_sheet::*, chat_message::{ChatMessage, RollDialogOption}}; +use serde::Serialize; use tavern_macros::CharacterSheet; pub mod entry; use entry::{PEntry, Weapon}; -#[derive(Default, CharacterSheet)] +#[derive(Default, CharacterSheet, Serialize)] pub struct Pathfinder2rCharacterSheet { // Genral stuff #[Input("Name")]