use crate::user_handler::*; use crate::AppState; use axum::extract::ws::{CloseFrame, Message}; use lib::*; use serde_json::{from_str, to_string}; use std::net::SocketAddr; use std::sync::Arc; /// Handle incoming messages over the WebSocket pub struct MessageHandler { state: Arc, } impl MessageHandler { pub fn new(state: Arc) -> Self { MessageHandler { state } } pub async fn handle(&self, addr: SocketAddr, message: Message) { match message { Message::Text(text) => match text { _chat_message if let Ok(chat_message) = from_str::(&text) => { // This should be delegated to user handler and an outgoing message and/or chat handler let msg = format! {"{0}: {1}", self.state.online_users.read().unwrap().get(&addr).unwrap().read().unwrap().name, chat_message.text}; tracing::debug!("{msg}"); self.state .broadcast_tx .send(to_string::(&ChatMessage { text: msg }).unwrap()) .unwrap(); } _user_log_in if let Ok(user_log_in) = from_str::(&text) => { self.state .users_tx .send(UserHandlerMessage::UserLogIn { username: user_log_in.username, addr, }) .await .unwrap(); tracing::debug!("passed login to user handler"); } _ => tracing::debug!("Unhandled text from {}", addr), }, Message::Binary(data) => tracing::debug!("{} sent binary: {:?}", addr, data), Message::Close(close_frame) => { self.handle_close(close_frame, addr); } Message::Pong(ping) => { tracing::debug!("Pong received with: {:?}", ping); } Message::Ping(pong) => { tracing::debug!("Pong received with: {:?}", pong); } } } /// This runs when a connection closes fn handle_close(&self, close_frame: Option, addr: SocketAddr) { if let Some(cf) = close_frame { tracing::debug!( "Close received from {0} with code: {1} and reason: {2}", self.state .online_users .read() .unwrap() .get(&addr) .unwrap() .read() .unwrap() .name, cf.code, cf.reason ) } else { tracing::debug!("close received without close frame") } let msg = ChatMessage { text: format!( "{0} left.", self.state .online_users .read() .unwrap() .get(&addr) .unwrap() .read() .unwrap() .name ), }; tracing::debug!("{}", msg.text); self.state .broadcast_tx .send(to_string::(&msg).unwrap()) .unwrap(); // Move user to offline let name = self .state .online_users .read() .unwrap() .get(&addr) .unwrap() .read() .unwrap() .name .clone(); self.state.offline_users.write().unwrap().insert( name.clone(), self.state .online_users .write() .unwrap() .remove(&addr) .unwrap(), ); self.state .broadcast_tx .send(meta_server_summary_update(&self.state)) .unwrap(); self.state .broadcast_tx .send(meta_chat_update(&self.state)) .unwrap(); } }