indicators
This commit is contained in:
parent
4358d49b48
commit
af46da77a7
6 changed files with 216 additions and 26 deletions
71
src/chat.rs
71
src/chat.rs
|
|
@ -6,10 +6,22 @@ use std::collections::HashMap;
|
|||
use tokio::sync::{RwLock, mpsc};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChatClient {
|
||||
tx: mpsc::UnboundedSender<ServerEvent>,
|
||||
is_idle: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct OnlineUser {
|
||||
pub user_id: Uuid,
|
||||
pub idle: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ChatHub {
|
||||
// user_id -> sender
|
||||
clients: RwLock<HashMap<Uuid, mpsc::UnboundedSender<ServerEvent>>>,
|
||||
// user_id -> client
|
||||
clients: RwLock<HashMap<Uuid, ChatClient>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
|
|
@ -26,6 +38,7 @@ pub enum ServerEvent {
|
|||
UserPresence {
|
||||
user_id: Uuid,
|
||||
online: bool,
|
||||
idle: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -34,12 +47,13 @@ pub enum ServerEvent {
|
|||
enum ClientEvent {
|
||||
// Currently no interactive client events for the general chat WS
|
||||
Ping,
|
||||
SetIdleStatus { is_idle: bool },
|
||||
}
|
||||
|
||||
impl ChatHub {
|
||||
pub async fn add_client(&self, user_id: Uuid, tx: mpsc::UnboundedSender<ServerEvent>) {
|
||||
let mut clients = self.clients.write().await;
|
||||
clients.insert(user_id, tx);
|
||||
clients.insert(user_id, ChatClient { tx, is_idle: false });
|
||||
}
|
||||
|
||||
pub async fn remove_client(&self, user_id: Uuid) {
|
||||
|
|
@ -47,33 +61,54 @@ impl ChatHub {
|
|||
clients.remove(&user_id);
|
||||
}
|
||||
|
||||
pub async fn get_online_users(&self) -> Vec<Uuid> {
|
||||
pub async fn get_online_users(&self) -> Vec<OnlineUser> {
|
||||
let clients = self.clients.read().await;
|
||||
clients.keys().cloned().collect()
|
||||
clients
|
||||
.iter()
|
||||
.map(|(id, client)| OnlineUser {
|
||||
user_id: *id,
|
||||
idle: client.is_idle,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn broadcast_all(&self, event: ServerEvent) {
|
||||
let clients = self.clients.read().await;
|
||||
for tx in clients.values() {
|
||||
let _ = tx.send(event.clone());
|
||||
for client in clients.values() {
|
||||
let _ = client.tx.send(event.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn broadcast_to_user(&self, user_id: Uuid, event: ServerEvent) {
|
||||
let clients = self.clients.read().await;
|
||||
if let Some(tx) = clients.get(&user_id) {
|
||||
let _ = tx.send(event);
|
||||
if let Some(client) = clients.get(&user_id) {
|
||||
let _ = client.tx.send(event);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn broadcast_to_many(&self, user_ids: Vec<Uuid>, event: ServerEvent) {
|
||||
let clients = self.clients.read().await;
|
||||
for user_id in user_ids {
|
||||
if let Some(tx) = clients.get(&user_id) {
|
||||
let _ = tx.send(event.clone());
|
||||
if let Some(client) = clients.get(&user_id) {
|
||||
let _ = client.tx.send(event.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_idle_status(&self, user_id: Uuid, is_idle: bool) {
|
||||
{
|
||||
let mut clients = self.clients.write().await;
|
||||
if let Some(client) = clients.get_mut(&user_id) {
|
||||
client.is_idle = is_idle;
|
||||
}
|
||||
}
|
||||
self.broadcast_all(ServerEvent::UserPresence {
|
||||
user_id,
|
||||
online: true,
|
||||
idle: is_idle,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_socket(state: AppState, socket: WebSocket, user_id: Uuid) {
|
||||
|
|
@ -86,6 +121,7 @@ pub async fn handle_socket(state: AppState, socket: WebSocket, user_id: Uuid) {
|
|||
.broadcast_all(ServerEvent::UserPresence {
|
||||
user_id,
|
||||
online: true,
|
||||
idle: false,
|
||||
})
|
||||
.await;
|
||||
|
||||
|
|
@ -101,8 +137,16 @@ pub async fn handle_socket(state: AppState, socket: WebSocket, user_id: Uuid) {
|
|||
});
|
||||
|
||||
while let Some(Ok(msg)) = ws_receiver.next().await {
|
||||
if let Message::Close(_) = msg {
|
||||
break;
|
||||
match msg {
|
||||
Message::Close(_) => break,
|
||||
Message::Text(text) => {
|
||||
if let Ok(ClientEvent::SetIdleStatus { is_idle }) =
|
||||
serde_json::from_str::<ClientEvent>(&text)
|
||||
{
|
||||
state.chat.set_idle_status(user_id, is_idle).await;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +157,7 @@ pub async fn handle_socket(state: AppState, socket: WebSocket, user_id: Uuid) {
|
|||
.broadcast_all(ServerEvent::UserPresence {
|
||||
user_id,
|
||||
online: false,
|
||||
idle: false,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue