feat: New extension trait for websocket online users
Signed-off-by: Awiteb <a@4rs.nl>
This commit is contained in:
parent
6f43e44745
commit
cd2a9ea03e
1 changed files with 67 additions and 2 deletions
|
@ -18,10 +18,16 @@ use std::sync::Arc;
|
|||
|
||||
use chrono::Utc;
|
||||
use oxidetalis_config::Config;
|
||||
use salvo::Depot;
|
||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||
use salvo::{websocket::Message, Depot};
|
||||
use sea_orm::DatabaseConnection;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{routes::DEPOT_NONCE_CACHE_SIZE, NonceCache};
|
||||
use crate::{
|
||||
routes::DEPOT_NONCE_CACHE_SIZE,
|
||||
websocket::{OnlineUsers, ServerEvent, SocketUserData},
|
||||
NonceCache,
|
||||
};
|
||||
|
||||
/// Extension trait for the Depot.
|
||||
pub trait DepotExt {
|
||||
|
@ -42,6 +48,24 @@ pub trait NonceCacheExt {
|
|||
fn add_nonce(&self, nonce: &[u8; 16], limit: &usize) -> bool;
|
||||
}
|
||||
|
||||
/// Extension trait for online websocket users
|
||||
pub trait OnlineUsersExt {
|
||||
/// Add new user to the online users
|
||||
async fn add_user(&self, conn_id: &Uuid, data: SocketUserData);
|
||||
|
||||
/// Remove user from online users
|
||||
async fn remove_user(&self, conn_id: &Uuid);
|
||||
|
||||
/// Ping all online users
|
||||
async fn ping_all(&self);
|
||||
|
||||
/// Update user pong at time
|
||||
async fn update_pong(&self, conn_id: &Uuid);
|
||||
|
||||
/// Disconnect inactive users (who not respond for the ping event)
|
||||
async fn disconnect_inactive_users(&self);
|
||||
}
|
||||
|
||||
impl DepotExt for Depot {
|
||||
fn db_conn(&self) -> &DatabaseConnection {
|
||||
self.obtain::<Arc<DatabaseConnection>>()
|
||||
|
@ -91,3 +115,44 @@ impl NonceCacheExt for &NonceCache {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl OnlineUsersExt for OnlineUsers {
|
||||
async fn add_user(&self, conn_id: &Uuid, data: SocketUserData) {
|
||||
self.write().await.insert(*conn_id, data);
|
||||
}
|
||||
|
||||
async fn remove_user(&self, conn_id: &Uuid) {
|
||||
self.write().await.remove(conn_id);
|
||||
}
|
||||
|
||||
async fn ping_all(&self) {
|
||||
let now = Utc::now();
|
||||
self.write().await.par_iter_mut().for_each(|(_, u)| {
|
||||
u.pinged_at = now;
|
||||
let _ = u.sender.unbounded_send(Ok(Message::from(
|
||||
&ServerEvent::ping().sign(&u.shared_secret),
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
async fn update_pong(&self, conn_id: &Uuid) {
|
||||
if let Some(user) = self.write().await.get_mut(conn_id) {
|
||||
user.ponged_at = Utc::now()
|
||||
}
|
||||
}
|
||||
|
||||
async fn disconnect_inactive_users(&self) {
|
||||
let now = Utc::now().timestamp();
|
||||
let is_inactive =
|
||||
|u: &SocketUserData| u.pinged_at > u.ponged_at && now - u.pinged_at.timestamp() >= 5;
|
||||
self.read()
|
||||
.await
|
||||
.iter()
|
||||
.filter(|(_, u)| is_inactive(u))
|
||||
.for_each(|(_, u)| {
|
||||
log::info!("Disconnected from {}, inactive", u.public_key);
|
||||
u.sender.close_channel()
|
||||
});
|
||||
self.write().await.retain(|_, u| !is_inactive(u));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue