summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJomar Milan <jomarm@jomarm.com>2026-06-02 21:15:27 -0700
committerJomar Milan <jomarm@jomarm.com>2026-06-02 21:15:27 -0700
commitec2097b11f93ad968e171c0e961e0e06652ce44b (patch)
treed404d2b7a021b57e19d2f668ae463ff311b4a988 /src
parenta2e55df0eeea9709175dd0a26c1e09bdaa60841a (diff)
Implement play websocket handshake
Diffstat (limited to 'src')
-rw-r--r--src/main.rs10
-rw-r--r--src/play.rs67
2 files changed, 69 insertions, 8 deletions
diff --git a/src/main.rs b/src/main.rs
index 32e5d58..b157b71 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,10 +1,11 @@
+mod play;
mod session;
mod template;
+use crate::play::handle_play;
use crate::session::{HandObject, Session};
use crate::template::{IndexTemplate, SessionTemplate};
use askama::Template;
-use axum::extract::ws::WebSocket;
use axum::extract::{Path, Query, State, WebSocketUpgrade};
use axum::http::{StatusCode, header};
use axum::response::{Html, IntoResponse, Response};
@@ -145,10 +146,3 @@ async fn update_hands(
async fn upgrade_play(ws: WebSocketUpgrade, State(state): State<Arc<AppState>>) -> Response {
ws.on_upgrade(|socket| handle_play(socket, state))
}
-
-#[allow(unused_variables)]
-async fn handle_play(mut socket: WebSocket, state: Arc<AppState>) {
- while let Some(msg) = socket.recv().await {
- todo!()
- }
-}
diff --git a/src/play.rs b/src/play.rs
new file mode 100644
index 0000000..e88ae7e
--- /dev/null
+++ b/src/play.rs
@@ -0,0 +1,67 @@
+use crate::AppState;
+use axum::extract::ws::{Message, Utf8Bytes, WebSocket};
+use serde::{Deserialize, Serialize};
+use std::error::Error;
+use std::sync::Arc;
+
+#[derive(Deserialize)]
+enum IncomingPlayMessage {
+ Initialize { id: String },
+}
+
+#[derive(Serialize)]
+enum OutgoingPlayMessage<'a> {
+ Initialize { colors: Vec<&'a String> },
+}
+
+struct PlayState {
+ id: Option<String>,
+}
+
+pub async fn handle_play(mut socket: WebSocket, app_state: Arc<AppState>) {
+ let mut play_state = PlayState { id: None };
+
+ while let Some(msg) = socket.recv().await {
+ let mut process = async |msg: Result<Message, axum::Error>| -> Result<(), Box<dyn Error>> {
+ let msg: IncomingPlayMessage = serde_json::from_str(msg?.to_text()?)?;
+ match msg {
+ IncomingPlayMessage::Initialize { id } => {
+ // Blocked so that the mutex guard is dropped after cloning the color names,
+ // preventing a potential deadlock when using .await after sending something
+ // through the socket, which would be possible if using tokio::sync::Mutex.
+ // Of course, the sessions Mutex is std::sync::Mutex instead, which does not
+ // allow locking the mutex through .await anyway.
+ let colors: Vec<String> = {
+ let sessions = app_state.sessions.lock().unwrap();
+ // TODO: Non-string Error might be useful
+ let session = sessions.get(&id).ok_or("Session did not exist")?;
+
+ session.hands.keys().cloned().collect()
+ };
+
+ play_state.id = Some(id);
+
+ let response = OutgoingPlayMessage::Initialize {
+ colors: colors.iter().collect(),
+ };
+ socket
+ .send(Message::Text(Utf8Bytes::from(serde_json::to_string(
+ &response,
+ )?)))
+ .await?;
+ }
+ }
+ Ok(())
+ };
+
+ if let Ok(Message::Text(_)) = msg
+ && let Err(err) = process(msg).await
+ {
+ eprintln!(
+ "Encountered an error while handling a message from a player: {}",
+ err
+ );
+ break;
+ }
+ }
+}