let user handler handle user things

This commit is contained in:
Adam 2024-10-12 01:21:42 -04:00
parent a95deceef9
commit 3fb3d2f521
6 changed files with 110 additions and 107 deletions

View file

@ -7,11 +7,12 @@ use thaw::*;
#[component]
pub fn Debug() -> impl IntoView {
let websocket = expect_context::<WebSocketContext>();
let state_summary = expect_context::<ReadSignal<Option<ServerStateSummary>>>();
let server_online_users = expect_context::<ReadSignal<Option<ServerOnlineUsers>>>();
let server_active_games = expect_context::<ReadSignal<Option<ServerActiveGames>>>();
// Signals
let (online_users, set_online_users) = signal(0);
let (active_games, set_active_games) = signal(0);
let user_count = RwSignal::new(0);
let game_count = RwSignal::new(0);
// Websocket stuff
let status = move || websocket.ready_state.get().to_string();
@ -27,17 +28,24 @@ pub fn Debug() -> impl IntoView {
let close_connection = move |_| {
(websocket.close)();
set_online_users(0);
set_active_games(0);
user_count.set(0);
game_count.set(0);
};
// Update server info -> move this to a new component
// Update data on incoming updates
Effect::new(move |_| {
state_summary.with(move |state_summary| {
if let Some(state_summary) = state_summary {
set_online_users(state_summary.online_users);
set_active_games(state_summary.active_games);
}
server_online_users.with(move |server_online_users| {
if let Some(online_users) = server_online_users {
user_count.set(online_users.online_users);
};
})
});
Effect::new(move |_| {
server_active_games.with(move |server_active_games| {
if let Some(active_games) = server_active_games {
game_count.set(active_games.active_games);
};
})
});
@ -45,8 +53,8 @@ pub fn Debug() -> impl IntoView {
<div class="my-2 w-auto">
<h2 class="p-1 text-2xl">Debug:</h2>
<p class="p-1">"Connection Status: " {status}</p>
<p class="p-1">"Users Online: " {online_users}</p>
<p class="p-1">"Active Games: " {active_games}</p>
<p class="p-1">"Users Online: " {user_count}</p>
<p class="p-1">"Active Games: " {game_count}</p>
<div class="p-1">
<Button on_click=open_connection disabled=connected>
"Connect"

View file

@ -68,7 +68,8 @@ pub fn Websocket() -> impl IntoView {
// Contexts for message handler
// TODO: This context stuff can probably be done better
let (state_summary, set_state_summary) = signal::<Option<ServerStateSummary>>(Option::None);
let (users_count, set_users_count) = signal::<Option<ServerOnlineUsers>>(Option::None);
let (games_count, set_games_count) = signal::<Option<ServerActiveGames>>(Option::None);
let (active_games, set_active_games) = signal::<Vec<GameBrowserMeta>>(vec![]);
let (user_update, set_user_update) = signal::<Option<UserUpdate>>(Option::None);
let (chat_update, set_chat_update) = signal::<Option<ChatUpdate>>(Option::None);
@ -102,14 +103,17 @@ pub fn Websocket() -> impl IntoView {
provide_context::<ReadSignal<Vec<GameBrowserMeta>>>(active_games);
provide_context::<ReadSignal<Option<GameMeta>>>(game_meta);
provide_context::<ReadSignal<Option<GameStateMeta>>>(game_state);
provide_context::<ReadSignal<Option<ServerStateSummary>>>(state_summary);
provide_context::<ReadSignal<Option<ServerOnlineUsers>>>(users_count);
provide_context::<ReadSignal<Option<ServerActiveGames>>>(games_count);
// Message handler
Effect::new(move |_| {
message.with(move |message_raw| {
if let Some(message) = message_raw {
if let Ok(state_summary) = from_str::<ServerStateSummary>(message) {
set_state_summary(Some(state_summary));
if let Ok(users_count) = from_str::<ServerOnlineUsers>(message) {
set_users_count(Some(users_count));
} else if let Ok(games_count) = from_str::<ServerActiveGames>(message) {
set_games_count(Some(games_count));
} else if let Ok(chat_message) = from_str::<ChatMessage>(message) {
set_chat_message(Some(chat_message));
} else if let Ok(user_update) = from_str::<UserUpdate>(message) {

View file

@ -126,10 +126,15 @@ pub struct ChatMessage {
pub text: String,
}
/// Server state summary
/// Server user count
#[derive(Serialize, Deserialize, Debug)]
pub struct ServerStateSummary {
pub struct ServerOnlineUsers {
pub online_users: usize,
}
/// Server games count
#[derive(Serialize, Deserialize, Debug)]
pub struct ServerActiveGames {
pub active_games: usize,
}

View file

@ -1,5 +1,4 @@
use crate::game::*;
use crate::user_handler::*;
use crate::AppState;
use crate::DmUserMethod::*;
use crate::GameHandlerMessage::*;
@ -202,17 +201,8 @@ impl GameHandler {
// Send updates for all players
self.send_game_meta_update(vec![game_id.clone()]);
// Update games list
self.broadcast_game_browser_update();
// Broadcast server meta update
if let Err(e) = self
.state
.broadcast_tx
.send(meta_server_summary_update(&self.state))
{
tracing::error!("Could not broadcast server meta update: {}", e);
};
self.broadcast_game_count();
}
/// Send game meta update for all players of a game
@ -384,17 +374,8 @@ impl GameHandler {
self.send_game_state_update_all(vec![game_id.clone()]);
self.send_game_meta_update(vec![game_id]);
// Update games list
self.broadcast_game_browser_update();
// Broadcast server meta update
let msg = meta_server_summary_update(&self.state);
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(msg) {
tracing::error!("Could not broadcast server meta update: {}", e);
}
});
self.broadcast_game_count();
} else {
tracing::error!("Attempted to create game for nonexistent player!");
}
@ -427,4 +408,12 @@ impl GameHandler {
}
});
}
/// Broadcast updated game count
fn broadcast_game_count(&self) {
let tx = self.state.broadcast_tx.clone();
let active_games = self.state.games.read().unwrap().len();
let msg = to_string(&ServerActiveGames { active_games }).unwrap();
tokio::spawn(async move { tx.send(msg) });
}
}

View file

@ -151,68 +151,19 @@ impl MessageHandler {
/// This runs when a connection closes
fn handle_close(&self, close_frame: Option<CloseFrame>, addr: SocketAddr) {
// TODO: this is user handler's job
let user_name = self
.state
.online_users
.read()
.unwrap()
.get(&addr)
.unwrap()
.read()
.unwrap()
.name
.clone();
// Announce User left in chat
let msg = ChatMessage {
text: format!("{0} left.", &user_name),
};
let chat_message = to_string::<ChatMessage>(&msg).unwrap();
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(chat_message) {
tracing::error!("Error broadcasting user leave message: {}", e)
}
});
let msg = UserHandlerMessage::Cleanup(addr);
let tx = self.state.users_tx.clone();
tokio::spawn(async move { tx.send(msg).await });
// Process close frame
if let Some(cf) = close_frame {
tracing::info!(
"Close received from {0} with code: {1} and reason: {2}",
&user_name,
"Close received with code: {} and reason: {}",
cf.code,
cf.reason
)
} else {
tracing::info!("close received without close frame")
}
// Move user to offline
// TODO: This is user handler's job
self.state.offline_users.write().unwrap().insert(
user_name,
self.state
.online_users
.write()
.unwrap()
.remove(&addr)
.unwrap(),
);
// Send client updates
let msg = meta_server_summary_update(&self.state);
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(msg) {
tracing::error!("Error broadcasting server summary update: {}", e)
}
});
let msg = meta_chat_update(&self.state);
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(msg) {
tracing::error!("Error broadcasting chat update: {}", e)
}
});
}
}

View file

@ -26,6 +26,7 @@ pub enum UserHandlerMessage {
NewUser(User, SocketAddr),
UserLogIn(UserLogInRequest, SocketAddr),
DmUser(SendUserMessage, DmUserMethod),
Cleanup(SocketAddr),
}
/// Types of messages that can be sent to a user as a DM
@ -51,6 +52,7 @@ impl UserHandler {
}
UserLogIn(request, addr) => self.login(request, addr).await,
DmUser(message, method) => self.dm_user(message, method).await,
Cleanup(addr) => self.user_cleanup(addr),
}
}
@ -148,9 +150,8 @@ impl UserHandler {
let msg = meta_announce_user_join(&self.state, &addr);
tokio::spawn(async move { tx.send(msg) });
let tx = self.state.broadcast_tx.clone();
let msg = meta_server_summary_update(&self.state);
tokio::spawn(async move { tx.send(msg) });
self.broadcast_user_count();
let tx = self.state.broadcast_tx.clone();
let msg = meta_chat_update(&self.state);
tokio::spawn(async move { tx.send(msg) });
@ -310,6 +311,62 @@ impl UserHandler {
let msg = meta_chat_update(&self.state);
tokio::spawn(async move { tx.send(msg) });
}
/// Broadcast updated user count
fn broadcast_user_count(&self) {
let tx = self.state.broadcast_tx.clone();
let online_users = self.state.online_users.read().unwrap().len();
let msg = to_string(&ServerOnlineUsers { online_users }).unwrap();
tokio::spawn(async move { tx.send(msg) });
}
/// Clean up after a user when they disconnect
fn user_cleanup(&self, addr: SocketAddr) {
let user_name = self
.state
.online_users
.read()
.unwrap()
.get(&addr)
.unwrap()
.read()
.unwrap()
.name
.clone();
// Announce User left in chat
let msg = ChatMessage {
text: format!("{0} left.", &user_name),
};
let chat_message = to_string::<ChatMessage>(&msg).unwrap();
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(chat_message) {
tracing::error!("Error broadcasting user leave message: {}", e)
}
});
// Move user to offline
self.state.offline_users.write().unwrap().insert(
user_name,
self.state
.online_users
.write()
.unwrap()
.remove(&addr)
.unwrap(),
);
self.broadcast_user_count();
let msg = meta_chat_update(&self.state);
let tx = self.state.broadcast_tx.clone();
tokio::spawn(async move {
if let Err(e) = tx.send(msg) {
tracing::error!("Error broadcasting chat update: {}", e)
}
});
}
}
/// Generate message to notify client of user changes
@ -361,14 +418,3 @@ pub fn meta_motd() -> String {
})
.unwrap()
}
/// Generate server summary update - mostly debug stuff
pub fn meta_server_summary_update(state: &Arc<AppState>) -> String {
let online_users = state.online_users.read().unwrap().len();
let active_games = state.games.read().unwrap().len();
to_string::<ServerStateSummary>(&ServerStateSummary {
online_users,
active_games,
})
.unwrap()
}