damnit, i changed again

This commit is contained in:
Adam 2024-05-03 23:17:39 -04:00
parent e595bd2d1b
commit e01e8370fe
3 changed files with 121 additions and 82 deletions

View file

@ -1,5 +1,6 @@
use crate::AppState;
use crate::gamemaster::*; use crate::gamemaster::*;
use crate::AppState;
use axum::extract::ConnectInfo;
use axum::{ use axum::{
extract::{ extract::{
ws::{Message, WebSocket, WebSocketUpgrade}, ws::{Message, WebSocket, WebSocketUpgrade},
@ -9,7 +10,7 @@ use axum::{
}; };
use futures::{sink::SinkExt, stream::StreamExt}; use futures::{sink::SinkExt, stream::StreamExt};
use serde::Deserialize; use serde::Deserialize;
use std::sync::Arc; use std::{net::SocketAddr, sync::Arc};
/// New game request structure /// New game request structure
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -34,44 +35,68 @@ pub struct GameJoinRequest {
pub async fn websocket_handler( pub async fn websocket_handler(
ws: WebSocketUpgrade, ws: WebSocketUpgrade,
// user_agent: Option<TypedHeader<headers::UserAgent>>,
ConnectInfo(addr): ConnectInfo<SocketAddr>,
State(state): State<Arc<AppState>>, State(state): State<Arc<AppState>>,
) -> impl IntoResponse { ) -> impl IntoResponse {
ws.on_upgrade(|socket| websocket(socket, state)) tracing::debug!("New connection from {addr}");
ws.on_upgrade(move |socket| websocket(socket, state, addr))
} }
pub async fn websocket(stream: WebSocket, state: Arc<AppState>) { fn greeting(state: &Arc<AppState>) -> String {
// By splitting, we can send and receive at the same time. format!(
let (mut sender, mut receiver) = stream.split(); "{:#?} Card packs loaded\n\
let _greeting = sender
.send(Message::Text(format!(
"Greetings! \n\
{:#?} Card packs loaded\n\
{:#?} Current active games", {:#?} Current active games",
state.all_cards.lock().unwrap().len(), state.all_cards.lock().unwrap().len(),
state.games.lock().unwrap().len(), state.games.lock().unwrap().len(),
))) )
.await; }
pub async fn websocket(stream: WebSocket, state: Arc<AppState>, who: SocketAddr) {
// By splitting, we can send and receive at the same time.
let (mut sender, mut receiver) = stream.split();
// Loop until a text message is found. let _greeting = sender.send(Message::Text(greeting(&state))).await;
// subscribe to channel
let mut rx = state.tx.subscribe();
// broadcast join
let msg = format!("{who} is here bitches");
tracing::debug!("{msg}");
let _ = state.tx.send(msg);
let mut send_task = tokio::spawn(async move {
while let Ok(msg) = rx.recv().await {
if sender.send(Message::Text(msg)).await.is_err() {
break;
}
}
});
// clone things for receiving task
let tx = state.tx.clone();
let name = who.clone();
let mut recv_task = tokio::spawn(async move {
while let Some(Ok(message)) = receiver.next().await { while let Some(Ok(message)) = receiver.next().await {
match message { match message {
Message::Text(text) => { Message::Text(text) => {
tracing::debug!("Text: {}", text); tracing::debug!("{who}: {}", text);
if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&text) { if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&text) {
tracing::debug!("{:#?}", &new_game); tracing::debug!("{:#?}", &new_game);
// create game // create game
if let Ok(new_game_object) = CAHGame::new(new_game) { if let Ok(new_game_object) = CAHGame::new(new_game) {
state.games.lock().unwrap().push(new_game_object); state.games.lock().unwrap().push(new_game_object);
let _update = tx.send(greeting(&state));
} else { } else {
let _res = sender let _res = tx.send(format!("error creating game"));
.send(Message::Text(format!("error creating game")))
.await;
} }
} else { } else {
// just echo // just echo
let _res = sender.send(Message::Text(text)).await; let msg = format!{"{who}: {text}"};
tracing::debug!("{msg}");
let _res = tx.send(msg);
} }
} }
Message::Binary(data) => { Message::Binary(data) => {
@ -80,13 +105,16 @@ pub async fn websocket(stream: WebSocket, state: Arc<AppState>) {
Message::Close(c) => { Message::Close(c) => {
if let Some(cf) = c { if let Some(cf) = c {
tracing::debug!( tracing::debug!(
"Close received with code: {} and reason: {}", "Close received from {who} with code: {} and reason: {}",
cf.code, cf.code,
cf.reason cf.reason
) )
} else { } else {
tracing::debug!("close received without close frame") tracing::debug!("close received without close frame")
} }
let msg = format!("{name} left.");
tracing::debug!("{msg}");
let _ = tx.send(msg);
} }
Message::Pong(ping) => { Message::Pong(ping) => {
tracing::debug!("Pong received with: {:?}", ping); tracing::debug!("Pong received with: {:?}", ping);
@ -96,4 +124,11 @@ pub async fn websocket(stream: WebSocket, state: Arc<AppState>) {
} }
} }
} }
});
// if either task completes then abort the other
tokio::select! {
_ = (&mut send_task) => recv_task.abort(),
_ = (&mut recv_task) => send_task.abort(),
};
} }

View file

@ -1,6 +1,7 @@
use axum::{response::Html, routing::get, Router}; use axum::{response::Html, routing::get, Router, ServiceExt};
use std::{ use std::{
collections::HashSet, collections::HashSet,
net::SocketAddr,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use std::{error::Error, fs, result::Result}; use std::{error::Error, fs, result::Result};
@ -120,7 +121,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
let listener = tokio::net::TcpListener::bind("0.0.0.0:3030").await?; let listener = tokio::net::TcpListener::bind("0.0.0.0:3030").await?;
tracing::debug!("listening on {}", listener.local_addr()?); tracing::debug!("listening on {}", listener.local_addr()?);
axum::serve(listener, app).await?; axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await?;
Ok(()) Ok(())
} }

View file

@ -37,7 +37,7 @@
<div id="chat"> <div id="chat">
<form id="chat" onsubmit="chatSubmit();return false"> <form id="chat" onsubmit="chatSubmit();return false">
<textarea id="chat-history" readonly="true" wrap="soft" style="display:block; width:30rem; height:10rem; box-sizing: border-box" cols="30" rows="10"></textarea> <textarea id="chat-history" readonly="true" wrap="soft" style="display:block; width:30rem; height:10rem; box-sizing: border-box" cols="30" rows="10"></textarea>
<input id="chat-input" type="text" style="width: 30rem;" placeholder="chat" /> <input id="chat-input" type="text" style="width: 30rem;" placeholder="talk shit" />
</form> </form>
</div> </div>
<hr /> <hr />
@ -61,7 +61,6 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
socket = new WebSocket("ws://localhost:3030/websocket"); socket = new WebSocket("ws://localhost:3030/websocket");
socket.binaryType = "ArrayBuffer";
function socketTest() { function socketTest() {
let code = testCloseCode.value; let code = testCloseCode.value;