cards/server/src/websocket.rs

105 lines
3.2 KiB
Rust
Raw Normal View History

2024-08-07 06:23:27 -04:00
use crate::user_handler::*;
2024-05-04 02:23:40 -04:00
use crate::AppState;
use crate::User;
2024-08-05 01:55:05 -04:00
use axum::{
extract::{
ws::{Message, WebSocket},
ConnectInfo, State, WebSocketUpgrade,
},
response::IntoResponse,
};
use futures::{SinkExt, StreamExt};
use rand::prelude::SliceRandom;
use std::collections::HashMap;
2024-08-08 05:29:32 -04:00
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::mpsc;
2024-07-30 03:22:32 -04:00
2024-08-05 01:55:05 -04:00
/// Establish the WebSocket connection
pub async fn websocket_connection_handler(
ws: WebSocketUpgrade,
// user_agent: Option<TypedHeader<headers::UserAgent>>,
ConnectInfo(addr): ConnectInfo<SocketAddr>,
State(state): State<Arc<AppState>>,
) -> impl IntoResponse {
ws.on_upgrade(move |socket| websocket_on_connection(socket, state, addr))
}
/// This runs right after a WebSocket connection is established
pub async fn websocket_on_connection(stream: WebSocket, state: Arc<AppState>, addr: SocketAddr) {
// Split channels to send and receive asynchronously.
let (mut sender, mut receiver) = stream.split();
2024-08-06 02:26:57 -04:00
// Create channel for direct messages
2024-10-11 00:26:24 -04:00
let (dm_tx, mut dm_rx) = mpsc::channel(1000000);
let mut map = HashMap::new();
map.insert(addr, dm_tx.clone());
2024-10-09 01:50:25 -04:00
// Roll for username and re-roll if taken
let mut username;
loop {
username = format!(
"{} {}",
state.first_names.choose(&mut rand::thread_rng()).unwrap(),
state.last_names.choose(&mut rand::thread_rng()).unwrap(),
);
if !state.reserved_names.read().unwrap().contains(&username) {
break;
}
}
2024-10-11 00:26:24 -04:00
let tx = state.users_tx.clone();
let msg = UserHandlerMessage::NewUser(User::new(username, dm_tx.clone()), addr);
tokio::spawn(async move { tx.send(msg).await.expect("User handler is down") });
2024-08-05 01:55:05 -04:00
// Subscribe to receive from global broadcast channel
let mut rx = state.broadcast_tx.subscribe();
2024-08-05 01:55:05 -04:00
// Send messages to this client
let mut send_task = tokio::spawn(async move {
2024-08-07 05:30:30 -04:00
let mut broadcast = None;
let mut dm = None;
loop {
2024-08-07 05:30:30 -04:00
tokio::select! {
b = rx.recv() => broadcast = Some(b.unwrap()),
d = dm_rx.recv() => dm = d,
};
if let Some(msg) = &dm {
if sender.send(Message::Text(msg.to_string())).await.is_err() {
break;
2024-08-07 05:30:30 -04:00
} else {
dm = Option::None;
}
2024-08-07 05:30:30 -04:00
} else if let Some(msg) = &broadcast {
if sender.send(Message::Text(msg.to_string())).await.is_err() {
} else {
broadcast = Option::None;
}
2024-08-05 01:55:05 -04:00
}
}
});
// Receive messages from this client
let mut recv_task = tokio::spawn(async move {
while let Some(Ok(message)) = receiver.next().await {
2024-10-10 01:19:52 -04:00
if let Err(e) = state
.messages_tx
.send((addr.clone(), message.clone()))
.await
2024-10-10 01:19:52 -04:00
{
tracing::error!("Error relaying received message: {}", e)
};
2024-08-05 01:55:05 -04:00
}
});
// If either task completes then abort the other
tokio::select! {
_ = (&mut send_task) => recv_task.abort(),
_ = (&mut recv_task) => send_task.abort(),
};
}