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,66 +35,100 @@ 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 {
format!(
"{:#?} Card packs loaded\n\
{:#?} Current active games",
state.all_cards.lock().unwrap().len(),
state.games.lock().unwrap().len(),
)
}
pub async fn websocket(stream: WebSocket, state: Arc<AppState>, who: SocketAddr) {
// By splitting, we can send and receive at the same time. // By splitting, we can send and receive at the same time.
let (mut sender, mut receiver) = stream.split(); let (mut sender, mut receiver) = stream.split();
let _greeting = sender let _greeting = sender.send(Message::Text(greeting(&state))).await;
.send(Message::Text(format!(
"Greetings! \n\
{:#?} Card packs loaded\n\
{:#?} Current active games",
state.all_cards.lock().unwrap().len(),
state.games.lock().unwrap().len(),
)))
.await;
// Loop until a text message is found. // subscribe to channel
while let Some(Ok(message)) = receiver.next().await { let mut rx = state.tx.subscribe();
match message {
Message::Text(text) => {
tracing::debug!("Text: {}", text);
if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&text) { // broadcast join
tracing::debug!("{:#?}", &new_game); let msg = format!("{who} is here bitches");
// create game tracing::debug!("{msg}");
if let Ok(new_game_object) = CAHGame::new(new_game) { let _ = state.tx.send(msg);
state.games.lock().unwrap().push(new_game_object);
} else { let mut send_task = tokio::spawn(async move {
let _res = sender while let Ok(msg) = rx.recv().await {
.send(Message::Text(format!("error creating game"))) if sender.send(Message::Text(msg)).await.is_err() {
.await; break;
}
} else {
// just echo
let _res = sender.send(Message::Text(text)).await;
}
}
Message::Binary(data) => {
tracing::debug!("Binary: {:?}", data)
}
Message::Close(c) => {
if let Some(cf) = c {
tracing::debug!(
"Close received with code: {} and reason: {}",
cf.code,
cf.reason
)
} else {
tracing::debug!("close received without close frame")
}
}
Message::Pong(ping) => {
tracing::debug!("Pong received with: {:?}", ping);
}
Message::Ping(pong) => {
tracing::debug!("Pong received with: {:?}", pong);
} }
} }
} });
// 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 {
match message {
Message::Text(text) => {
tracing::debug!("{who}: {}", text);
if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&text) {
tracing::debug!("{:#?}", &new_game);
// create game
if let Ok(new_game_object) = CAHGame::new(new_game) {
state.games.lock().unwrap().push(new_game_object);
let _update = tx.send(greeting(&state));
} else {
let _res = tx.send(format!("error creating game"));
}
} else {
// just echo
let msg = format!{"{who}: {text}"};
tracing::debug!("{msg}");
let _res = tx.send(msg);
}
}
Message::Binary(data) => {
tracing::debug!("Binary: {:?}", data)
}
Message::Close(c) => {
if let Some(cf) = c {
tracing::debug!(
"Close received from {who} with code: {} and reason: {}",
cf.code,
cf.reason
)
} else {
tracing::debug!("close received without close frame")
}
let msg = format!("{name} left.");
tracing::debug!("{msg}");
let _ = tx.send(msg);
}
Message::Pong(ping) => {
tracing::debug!("Pong received with: {:?}", ping);
}
Message::Ping(pong) => {
tracing::debug!("Pong received with: {:?}", pong);
}
}
}
});
// 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;
@ -70,52 +69,52 @@
}; };
function createGame() { function createGame() {
let CAHPlayer = { let CAHPlayer = {
name: username.value, name: username.value,
role: 'Host', role: 'Host',
white: [], white: [],
black: [], black: [],
}; };
let NewGameRequest = { let NewGameRequest = {
name: gamename.value, name: gamename.value,
host: CAHPlayer, host: CAHPlayer,
packs: [0], packs: [0],
}; };
socket.send(JSON.stringify(NewGameRequest)); socket.send(JSON.stringify(NewGameRequest));
}; };
function joinGame() { function joinGame() {
console.log('not done yet'); console.log('not done yet');
} }
socket.onopen = function() { socket.onopen = function() {
console.log("connection opened",socket.extensions, socket.protocol, socket.readyState); console.log("connection opened",socket.extensions, socket.protocol, socket.readyState);
document.getElementById("status").innerHTML = '<p><em>Connected!</em></p>'; document.getElementById("status").innerHTML = '<p><em>Connected!</em></p>';
} }
socket.onclose = function() { socket.onclose = function() {
console.log("connection closed"); console.log("connection closed");
document.getElementById("status").innerHTML = '<p><em>Disconnected...</em></p>'; document.getElementById("status").innerHTML = '<p><em>Disconnected...</em></p>';
document.getElementById("chat-history").value = ""; document.getElementById("chat-history").value = "";
} }
socket.onmessage = function(e) { socket.onmessage = function(e) {
const history = document.getElementById("chat-history") const history = document.getElementById("chat-history")
console.log("received message: "+e.data); console.log("received message: "+e.data);
history.value += e.data+"\r"; history.value += e.data+"\r";
history.scrollTop = history.scrollHeight; history.scrollTop = history.scrollHeight;
} }
function chatSubmit() { function chatSubmit() {
let input = document.getElementById("chat-input"); let input = document.getElementById("chat-input");
socket.send(input.value); socket.send(input.value);
input.value = ""; input.value = "";
}; };
socket.addEventListener("error", (event) => { socket.addEventListener("error", (event) => {
console.log("WebSocket error: ", event); console.log("WebSocket error: ", event);
}); });
</script> </script>
</body> </body>