2025-07-19 15:32:30 +02:00
|
|
|
use crate::api::model::streams::shared_stream_manager::SharedStreamManager;
|
2025-05-04 10:59:08 +02:00
|
|
|
use crate::model::Config;
|
2025-07-19 15:32:30 +02:00
|
|
|
use crate::model::ProxyUserCredentials;
|
|
|
|
|
use dashmap::DashMap;
|
2025-04-17 15:43:26 +02:00
|
|
|
use jsonwebtoken::get_current_timestamp;
|
2025-04-17 20:09:29 +02:00
|
|
|
use log::{debug, info};
|
2025-07-19 15:32:30 +02:00
|
|
|
use shared::model::UserConnectionPermission;
|
|
|
|
|
use shared::utils::{current_time_secs, default_grace_period_millis, default_grace_period_timeout_secs, sanitize_sensitive_info};
|
2025-06-24 12:31:38 +02:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
2025-06-09 13:23:27 +02:00
|
|
|
use std::sync::Arc;
|
2025-07-19 15:32:30 +02:00
|
|
|
use crate::api::model::active_provider_manager::ActiveProviderManager;
|
2025-02-06 20:31:51 +01:00
|
|
|
|
2025-06-24 12:31:38 +02:00
|
|
|
macro_rules! active_user_manager_shared_impl {
|
|
|
|
|
() => {
|
|
|
|
|
#[inline]
|
2025-07-19 15:32:30 +02:00
|
|
|
fn get_active_connections(user: &Arc<DashMap<String, UserConnectionData>>) -> usize {
|
|
|
|
|
user.iter().map(|c| c.connections as usize).sum()
|
2025-06-24 12:31:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn log_active_user(&self) {
|
2025-07-21 22:17:57 +02:00
|
|
|
let user = Arc::clone(&self.user);
|
|
|
|
|
let user_connection_count = Self::get_active_connections(&user);
|
|
|
|
|
let user_count = user.len();
|
|
|
|
|
let _= self.active_user_change_tx.send((user_count, user_connection_count));
|
2025-06-24 12:31:38 +02:00
|
|
|
if self.is_log_user_enabled() {
|
2025-07-21 22:17:57 +02:00
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
info!("Active Users: {user_count}, Active User Connections: {user_connection_count}");
|
2025-06-24 12:31:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-07-15 12:28:25 +02:00
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn remove_connection(&self, addr: &str) {
|
|
|
|
|
let username_opt = self.user_by_addr.get(addr).as_deref().cloned();
|
2025-07-15 12:28:25 +02:00
|
|
|
if let Some(username) = username_opt {
|
2025-07-19 15:32:30 +02:00
|
|
|
self.user_by_addr.remove(addr);
|
|
|
|
|
let mut remove_user = false;
|
|
|
|
|
if let Some(mut entry) = self.user.get_mut(&username) {
|
|
|
|
|
let connection_data = &mut *entry;
|
2025-07-15 12:28:25 +02:00
|
|
|
if connection_data.connections > 0 {
|
|
|
|
|
connection_data.connections -= 1;
|
|
|
|
|
}
|
2025-07-19 15:32:30 +02:00
|
|
|
|
2025-07-15 12:28:25 +02:00
|
|
|
if connection_data.connections == 0 {
|
2025-07-19 15:32:30 +02:00
|
|
|
remove_user = true;
|
2025-07-15 12:28:25 +02:00
|
|
|
} else if connection_data.connections < connection_data.max_connections {
|
|
|
|
|
connection_data.granted_grace = false;
|
|
|
|
|
connection_data.grace_ts = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-19 15:32:30 +02:00
|
|
|
if remove_user {
|
|
|
|
|
self.user.remove(&username);
|
|
|
|
|
}
|
2025-07-15 12:28:25 +02:00
|
|
|
}
|
2025-07-19 15:32:30 +02:00
|
|
|
self.shared_stream_manager.release_connection(addr);
|
|
|
|
|
self.provider_manager.release_connection(addr);
|
2025-07-15 12:28:25 +02:00
|
|
|
self.log_active_user();
|
|
|
|
|
}
|
2025-06-24 12:31:38 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-06 12:19:37 +02:00
|
|
|
const USER_CON_TTL: u64 = 10_800; // 3 hours
|
2025-06-09 13:23:27 +02:00
|
|
|
const USER_SESSION_LIMIT: usize = 50;
|
2025-05-06 12:19:37 +02:00
|
|
|
|
2025-06-24 12:31:38 +02:00
|
|
|
fn get_grace_options(config: &Config) -> (u64, u64) {
|
|
|
|
|
let (grace_period_millis, grace_period_timeout_secs) = config.reverse_proxy.as_ref()
|
|
|
|
|
.and_then(|r| r.stream.as_ref())
|
|
|
|
|
.map_or_else(|| (default_grace_period_millis(), default_grace_period_timeout_secs()), |s| (s.grace_period_millis, s.grace_period_timeout_secs));
|
|
|
|
|
(grace_period_millis, grace_period_timeout_secs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct ConnectionGuardUserManager {
|
|
|
|
|
log_active_user: bool,
|
2025-07-19 15:32:30 +02:00
|
|
|
user: Arc<DashMap<String, UserConnectionData>>,
|
|
|
|
|
user_by_addr: Arc<DashMap<String, String>>,
|
|
|
|
|
shared_stream_manager: Arc<SharedStreamManager>,
|
|
|
|
|
provider_manager: Arc<ActiveProviderManager>,
|
2025-07-21 22:17:57 +02:00
|
|
|
active_user_change_tx: tokio::sync::broadcast::Sender<(usize, usize)>,
|
2025-06-24 12:31:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ConnectionGuardUserManager {
|
|
|
|
|
active_user_manager_shared_impl!();
|
2025-07-19 15:32:30 +02:00
|
|
|
fn is_log_user_enabled(&self) -> bool {
|
2025-06-24 12:31:38 +02:00
|
|
|
self.log_active_user
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-13 16:02:55 +02:00
|
|
|
pub struct UserConnectionGuard {
|
2025-06-24 12:31:38 +02:00
|
|
|
manager: Arc<ConnectionGuardUserManager>,
|
2025-07-15 12:28:25 +02:00
|
|
|
// username: String,
|
|
|
|
|
addr: String,
|
2025-04-13 16:02:55 +02:00
|
|
|
}
|
|
|
|
|
impl Drop for UserConnectionGuard {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
let manager = self.manager.clone();
|
2025-07-15 12:28:25 +02:00
|
|
|
let addr = self.addr.clone();
|
2025-07-19 15:32:30 +02:00
|
|
|
manager.remove_connection(&addr);
|
2025-04-13 16:02:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 09:55:08 +02:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct UserSession {
|
2025-06-05 17:51:03 +02:00
|
|
|
pub token: String,
|
2025-04-30 09:55:08 +02:00
|
|
|
pub virtual_id: u32,
|
|
|
|
|
pub provider: String,
|
|
|
|
|
pub stream_url: String,
|
2025-07-17 09:15:41 +02:00
|
|
|
pub addr: String,
|
2025-04-30 09:55:08 +02:00
|
|
|
pub ts: u64,
|
|
|
|
|
pub permission: UserConnectionPermission,
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-17 15:43:26 +02:00
|
|
|
struct UserConnectionData {
|
2025-04-28 19:52:59 +02:00
|
|
|
max_connections: u32,
|
2025-04-17 15:43:26 +02:00
|
|
|
connections: u32,
|
2025-04-27 13:26:21 +02:00
|
|
|
granted_grace: bool,
|
2025-04-17 15:43:26 +02:00
|
|
|
grace_ts: u64,
|
2025-04-30 09:55:08 +02:00
|
|
|
sessions: Vec<UserSession>,
|
2025-04-17 15:43:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UserConnectionData {
|
2025-04-30 11:04:01 +02:00
|
|
|
fn new(connections: u32, max_connections: u32) -> Self {
|
2025-04-17 15:43:26 +02:00
|
|
|
Self {
|
2025-04-30 09:55:08 +02:00
|
|
|
max_connections,
|
2025-04-30 11:04:01 +02:00
|
|
|
connections,
|
2025-04-27 13:26:21 +02:00
|
|
|
granted_grace: false,
|
2025-04-17 15:43:26 +02:00
|
|
|
grace_ts: 0,
|
2025-04-30 09:55:08 +02:00
|
|
|
sessions: Vec::new(),
|
2025-04-17 15:43:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-06-09 13:23:27 +02:00
|
|
|
|
|
|
|
|
fn add_session(&mut self, session: UserSession) {
|
|
|
|
|
self.gc();
|
|
|
|
|
self.sessions.push(session);
|
|
|
|
|
}
|
|
|
|
|
fn gc(&mut self) {
|
|
|
|
|
if self.sessions.len() > USER_SESSION_LIMIT {
|
|
|
|
|
self.sessions.sort_by_key(|e| std::cmp::Reverse(e.ts));
|
|
|
|
|
self.sessions.truncate(USER_SESSION_LIMIT);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-17 15:43:26 +02:00
|
|
|
}
|
|
|
|
|
|
2025-02-06 20:31:51 +01:00
|
|
|
pub struct ActiveUserManager {
|
2025-06-24 12:31:38 +02:00
|
|
|
grace_period_millis: AtomicU64,
|
|
|
|
|
grace_period_timeout_secs: AtomicU64,
|
|
|
|
|
log_active_user: AtomicBool,
|
2025-07-19 15:32:30 +02:00
|
|
|
user: Arc<DashMap<String, UserConnectionData>>,
|
|
|
|
|
user_by_addr: Arc<DashMap<String, String>>,
|
2025-04-30 11:04:01 +02:00
|
|
|
gc_ts: Option<AtomicU64>,
|
2025-07-17 09:15:41 +02:00
|
|
|
close_signal_tx: tokio::sync::broadcast::Sender<String>,
|
2025-07-19 15:32:30 +02:00
|
|
|
shared_stream_manager: Arc<SharedStreamManager>,
|
|
|
|
|
provider_manager: Arc<ActiveProviderManager>,
|
2025-07-21 22:17:57 +02:00
|
|
|
active_user_change_tx: tokio::sync::broadcast::Sender<(usize, usize)>,
|
2025-02-06 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ActiveUserManager {
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn new(config: &Config, shared_stream_manager: &Arc<SharedStreamManager>, provider_manager: &Arc<ActiveProviderManager>) -> Self {
|
2025-04-27 15:23:22 +02:00
|
|
|
let log_active_user = config.log.as_ref().is_some_and(|l| l.log_active_user);
|
2025-06-24 12:31:38 +02:00
|
|
|
let (grace_period_millis, grace_period_timeout_secs) = get_grace_options(config);
|
2025-07-17 09:15:41 +02:00
|
|
|
let (close_signal_tx, _) = tokio::sync::broadcast::channel(10);
|
2025-07-21 22:17:57 +02:00
|
|
|
let (active_user_change_tx, _) = tokio::sync::broadcast::channel(10);
|
2025-02-06 20:31:51 +01:00
|
|
|
Self {
|
2025-07-19 15:32:30 +02:00
|
|
|
grace_period_millis: AtomicU64::new(grace_period_millis),
|
2025-06-24 12:31:38 +02:00
|
|
|
grace_period_timeout_secs: AtomicU64::new(grace_period_timeout_secs),
|
|
|
|
|
log_active_user: AtomicBool::new(log_active_user),
|
2025-07-19 15:32:30 +02:00
|
|
|
user: Arc::new(DashMap::new()),
|
|
|
|
|
user_by_addr: Arc::new(DashMap::new()),
|
2025-04-30 11:04:01 +02:00
|
|
|
gc_ts: Some(AtomicU64::new(current_time_secs())),
|
2025-07-19 15:32:30 +02:00
|
|
|
close_signal_tx,
|
|
|
|
|
shared_stream_manager: Arc::clone(shared_stream_manager),
|
|
|
|
|
provider_manager: Arc::clone(provider_manager),
|
2025-07-21 22:17:57 +02:00
|
|
|
active_user_change_tx,
|
2025-02-06 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
active_user_manager_shared_impl!();
|
|
|
|
|
|
2025-06-24 12:31:38 +02:00
|
|
|
pub fn update_config(&self, config: &Config) {
|
|
|
|
|
let log_active_user = config.log.as_ref().is_some_and(|l| l.log_active_user);
|
|
|
|
|
let (grace_period_millis, grace_period_timeout_secs) = get_grace_options(config);
|
|
|
|
|
self.grace_period_millis.store(grace_period_millis, Ordering::Relaxed);
|
|
|
|
|
self.grace_period_timeout_secs.store(grace_period_timeout_secs, Ordering::Relaxed);
|
|
|
|
|
self.log_active_user.store(log_active_user, Ordering::Relaxed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn clone_inner(&self) -> ConnectionGuardUserManager {
|
|
|
|
|
ConnectionGuardUserManager {
|
|
|
|
|
log_active_user: self.log_active_user.load(Ordering::Relaxed),
|
2025-04-16 20:28:02 +02:00
|
|
|
user: Arc::clone(&self.user),
|
2025-07-15 12:28:25 +02:00
|
|
|
user_by_addr: Arc::clone(&self.user_by_addr),
|
2025-07-19 15:32:30 +02:00
|
|
|
shared_stream_manager: Arc::clone(&self.shared_stream_manager),
|
|
|
|
|
provider_manager: Arc::clone(&self.provider_manager),
|
2025-07-21 22:17:57 +02:00
|
|
|
active_user_change_tx: self.active_user_change_tx.clone(),
|
2025-04-16 20:28:02 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn user_connections(&self, username: &str) -> u32 {
|
|
|
|
|
if let Some(connection_data) = self.user.get(username) {
|
2025-04-17 15:43:26 +02:00
|
|
|
return connection_data.connections;
|
2025-02-06 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
0
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-30 11:04:01 +02:00
|
|
|
fn check_connection_permission(&self, username: &str, connection_data: &mut UserConnectionData) -> UserConnectionPermission {
|
|
|
|
|
let current_connections = connection_data.connections;
|
2025-04-30 09:55:08 +02:00
|
|
|
|
2025-04-30 11:04:01 +02:00
|
|
|
if current_connections < connection_data.max_connections {
|
2025-07-15 12:28:25 +02:00
|
|
|
// Reset grace period because the user is back under max_connections
|
2025-04-30 11:04:01 +02:00
|
|
|
connection_data.granted_grace = false;
|
|
|
|
|
connection_data.grace_ts = 0;
|
|
|
|
|
return UserConnectionPermission::Allowed;
|
|
|
|
|
}
|
2025-04-30 09:55:08 +02:00
|
|
|
|
2025-04-30 11:04:01 +02:00
|
|
|
let now = get_current_timestamp();
|
2025-07-15 12:28:25 +02:00
|
|
|
// Check if user already used a grace period
|
2025-04-30 11:04:01 +02:00
|
|
|
if connection_data.granted_grace {
|
2025-06-24 12:31:38 +02:00
|
|
|
if current_connections > connection_data.max_connections && now - connection_data.grace_ts <= self.grace_period_timeout_secs.load(Ordering::Relaxed) {
|
2025-07-15 12:28:25 +02:00
|
|
|
// Grace timeout, still active, deny connection
|
2025-04-30 11:04:01 +02:00
|
|
|
debug!("User access denied, grace exhausted, too many connections: {username}");
|
|
|
|
|
return UserConnectionPermission::Exhausted;
|
2025-04-30 09:55:08 +02:00
|
|
|
}
|
2025-04-30 11:04:01 +02:00
|
|
|
// Grace timeout expired, reset grace counters
|
|
|
|
|
connection_data.granted_grace = false;
|
|
|
|
|
connection_data.grace_ts = 0;
|
|
|
|
|
}
|
2025-04-30 09:55:08 +02:00
|
|
|
|
2025-06-24 12:31:38 +02:00
|
|
|
if self.grace_period_millis.load(Ordering::Relaxed) > 0 && current_connections == connection_data.max_connections {
|
2025-07-15 12:28:25 +02:00
|
|
|
// Allow a grace period once
|
2025-04-30 11:04:01 +02:00
|
|
|
connection_data.granted_grace = true;
|
|
|
|
|
connection_data.grace_ts = now;
|
2025-07-15 12:28:25 +02:00
|
|
|
debug!("Granted a grace period for user access: {username}");
|
2025-04-30 11:04:01 +02:00
|
|
|
return UserConnectionPermission::GracePeriod;
|
|
|
|
|
}
|
2025-04-30 09:55:08 +02:00
|
|
|
|
2025-04-30 11:04:01 +02:00
|
|
|
// Too many connections, no grace allowed
|
|
|
|
|
debug!("User access denied, too many connections: {username}");
|
|
|
|
|
UserConnectionPermission::Exhausted
|
2025-04-30 09:55:08 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn connection_permission(
|
2025-04-27 13:26:21 +02:00
|
|
|
&self,
|
|
|
|
|
username: &str,
|
|
|
|
|
max_connections: u32,
|
|
|
|
|
) -> UserConnectionPermission {
|
2025-04-27 15:23:22 +02:00
|
|
|
if max_connections > 0 {
|
2025-07-19 15:32:30 +02:00
|
|
|
if let Some(mut entry) = self.user.get_mut(username) {
|
|
|
|
|
return self.check_connection_permission(username, &mut entry);
|
2025-04-27 15:23:22 +02:00
|
|
|
}
|
2025-03-28 23:54:10 +01:00
|
|
|
}
|
|
|
|
|
UserConnectionPermission::Allowed
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn active_users(&self) -> usize {
|
|
|
|
|
self.user.len()
|
2025-02-06 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn active_connections(&self) -> usize {
|
|
|
|
|
Self::get_active_connections(&self.user)
|
2025-05-06 12:19:37 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn add_connection(&self, username: &str, max_connections: u32, addr: &str) -> UserConnectionGuard {
|
|
|
|
|
self.user
|
|
|
|
|
.entry(username.to_string())
|
|
|
|
|
.and_modify(|connection_data| {
|
|
|
|
|
connection_data.connections += 1;
|
|
|
|
|
connection_data.max_connections = max_connections;
|
|
|
|
|
})
|
|
|
|
|
.or_insert_with(|| UserConnectionData::new(1, max_connections));
|
|
|
|
|
|
|
|
|
|
self.user_by_addr.insert(addr.to_string(), username.to_string());
|
2025-04-13 16:02:55 +02:00
|
|
|
|
2025-05-06 12:19:37 +02:00
|
|
|
self.log_active_user();
|
2025-04-13 16:02:55 +02:00
|
|
|
|
|
|
|
|
UserConnectionGuard {
|
|
|
|
|
manager: Arc::new(self.clone_inner()),
|
2025-07-15 12:28:25 +02:00
|
|
|
// username: username.to_string(),
|
|
|
|
|
addr: addr.to_string(),
|
2025-04-13 16:02:55 +02:00
|
|
|
}
|
2025-02-06 20:31:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
fn is_log_user_enabled(&self) -> bool {
|
2025-06-24 12:31:38 +02:00
|
|
|
self.log_active_user.load(Ordering::Relaxed)
|
2025-04-13 16:02:55 +02:00
|
|
|
}
|
|
|
|
|
|
2025-06-05 17:51:03 +02:00
|
|
|
fn find_user_session<'a>(token: &'a str, sessions: &'a [UserSession]) -> Option<&'a UserSession> {
|
|
|
|
|
sessions.iter().find(|&session| session.token.eq(token))
|
2025-04-30 11:04:01 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-17 09:15:41 +02:00
|
|
|
fn new_user_session(session_token: &str, virtual_id: u32, provider: &str, stream_url: &str, addr: &str,
|
|
|
|
|
connection_permission: UserConnectionPermission) -> UserSession {
|
2025-04-30 11:04:01 +02:00
|
|
|
UserSession {
|
2025-06-05 17:51:03 +02:00
|
|
|
token: session_token.to_string(),
|
2025-04-30 11:04:01 +02:00
|
|
|
virtual_id,
|
|
|
|
|
provider: provider.to_string(),
|
|
|
|
|
stream_url: stream_url.to_string(),
|
2025-07-17 09:15:41 +02:00
|
|
|
addr: addr.to_string(),
|
2025-04-30 11:04:01 +02:00
|
|
|
ts: current_time_secs(),
|
|
|
|
|
permission: connection_permission,
|
2025-04-30 09:55:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-17 09:15:41 +02:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn create_user_session(&self, user: &ProxyUserCredentials, session_token: &str, virtual_id: u32,
|
|
|
|
|
provider: &str, stream_url: &str, addr: &str,
|
|
|
|
|
connection_permission: UserConnectionPermission) -> String {
|
|
|
|
|
self.gc();
|
|
|
|
|
let entry = self.user.entry(user.username.to_string());
|
|
|
|
|
let mut connection_data = entry.or_insert_with(|| {
|
2025-06-11 10:11:23 +02:00
|
|
|
debug!("Creating session for user {} with token {session_token} {}", user.username, sanitize_sensitive_info(stream_url));
|
2025-07-19 15:32:30 +02:00
|
|
|
let mut data = UserConnectionData::new(0, user.max_connections);
|
2025-07-17 09:15:41 +02:00
|
|
|
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, addr, connection_permission);
|
2025-07-19 15:32:30 +02:00
|
|
|
data.add_session(session);
|
|
|
|
|
data
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// If a session exists, update it
|
|
|
|
|
for session in &mut connection_data.sessions {
|
|
|
|
|
if session.token == session_token {
|
|
|
|
|
session.ts = current_time_secs();
|
|
|
|
|
if session.stream_url != stream_url {
|
|
|
|
|
session.stream_url = stream_url.to_string();
|
|
|
|
|
}
|
|
|
|
|
if session.provider != provider {
|
|
|
|
|
session.provider = provider.to_string();
|
|
|
|
|
}
|
|
|
|
|
session.permission = connection_permission;
|
|
|
|
|
debug!("Using session for user {} with token {session_token} {}", user.username, sanitize_sensitive_info(stream_url));
|
|
|
|
|
return session.token.clone();
|
|
|
|
|
}
|
2025-04-28 19:52:59 +02:00
|
|
|
}
|
2025-07-19 15:32:30 +02:00
|
|
|
|
|
|
|
|
// If not session exists, create one
|
|
|
|
|
debug!("Creating session for user {} with token {session_token} {}", user.username, sanitize_sensitive_info(stream_url));
|
|
|
|
|
let session = Self::new_user_session(session_token, virtual_id, provider, stream_url, addr, connection_permission);
|
|
|
|
|
let token = session.token.clone();
|
|
|
|
|
connection_data.add_session(session);
|
|
|
|
|
token
|
2025-04-30 09:55:08 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn update_session_addr(&self, username: &str, token: &str, addr: &str) {
|
|
|
|
|
let drop_addr = self.user.get_mut(username).and_then(|mut entry| {
|
|
|
|
|
let connection_data = &mut *entry;
|
|
|
|
|
connection_data.sessions.iter_mut().find_map(|session| {
|
|
|
|
|
if session.token == token {
|
|
|
|
|
let old_addr = session.addr.clone();
|
2025-07-17 09:15:41 +02:00
|
|
|
session.addr = addr.to_string();
|
2025-07-19 15:32:30 +02:00
|
|
|
Some(old_addr)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
2025-07-17 09:15:41 +02:00
|
|
|
}
|
2025-07-19 15:32:30 +02:00
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if let Some(session_addr) = drop_addr {
|
|
|
|
|
self.drop_connection(&session_addr);
|
2025-07-17 09:15:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn drop_connection(&self, addr: &str) {
|
|
|
|
|
let _ = self.close_signal_tx.send(addr.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_close_connection_channel(&self) -> tokio::sync::broadcast::Receiver<String> {
|
|
|
|
|
self.close_signal_tx.subscribe()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-21 22:17:57 +02:00
|
|
|
pub fn get_active_user_change_channel(&self) -> tokio::sync::broadcast::Receiver<(usize, usize)> {
|
|
|
|
|
self.active_user_change_tx.subscribe()
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
pub fn get_user_session(&self, username: &str, token: &str) -> Option<UserSession> {
|
|
|
|
|
self.update_user_session(username, token)
|
2025-04-28 19:52:59 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
fn update_user_session(&self, username: &str, token: &str) -> Option<UserSession> {
|
|
|
|
|
if let Some(mut entry) = self.user.get_mut(username) {
|
|
|
|
|
let connection_data = &mut *entry;
|
|
|
|
|
|
2025-04-30 09:55:08 +02:00
|
|
|
if connection_data.max_connections == 0 {
|
|
|
|
|
return Self::find_user_session(token, &connection_data.sessions).cloned();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Separate mutable borrow of the session
|
|
|
|
|
let mut found_session_index = None;
|
|
|
|
|
for (i, session) in connection_data.sessions.iter().enumerate() {
|
|
|
|
|
if session.token == token {
|
|
|
|
|
found_session_index = Some(i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(index) = found_session_index {
|
2025-05-26 13:57:29 +02:00
|
|
|
let session_permission = connection_data.sessions[index].permission;
|
2025-04-30 09:55:08 +02:00
|
|
|
if session_permission == UserConnectionPermission::GracePeriod {
|
2025-04-30 11:04:01 +02:00
|
|
|
let new_permission = self.check_connection_permission(username, connection_data);
|
2025-04-30 09:55:08 +02:00
|
|
|
connection_data.sessions[index].permission = new_permission;
|
|
|
|
|
}
|
|
|
|
|
return Some(connection_data.sessions[index].clone());
|
|
|
|
|
}
|
2025-04-28 19:52:59 +02:00
|
|
|
}
|
2025-04-30 09:55:08 +02:00
|
|
|
None
|
2025-04-28 19:52:59 +02:00
|
|
|
}
|
|
|
|
|
|
2025-07-19 15:32:30 +02:00
|
|
|
fn gc(&self) {
|
2025-04-30 11:04:01 +02:00
|
|
|
if let Some(gc_ts) = &self.gc_ts {
|
2025-06-09 13:23:27 +02:00
|
|
|
let ts = gc_ts.load(Ordering::Acquire);
|
2025-05-06 12:19:37 +02:00
|
|
|
let now = current_time_secs();
|
2025-06-09 13:23:27 +02:00
|
|
|
if now - ts > USER_CON_TTL {
|
2025-07-19 15:32:30 +02:00
|
|
|
for mut entry in self.user.iter_mut() {
|
|
|
|
|
let connection_data = &mut *entry;
|
2025-06-09 13:23:27 +02:00
|
|
|
connection_data.sessions.retain(|s| now - s.ts < USER_CON_TTL);
|
2025-04-30 11:04:01 +02:00
|
|
|
}
|
2025-06-09 13:23:27 +02:00
|
|
|
gc_ts.store(now, Ordering::Release);
|
2025-04-30 11:04:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-21 15:56:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// mod tests {
|
|
|
|
|
// use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
|
|
|
|
|
// use std::time::Instant;
|
|
|
|
|
// use std::thread;
|
|
|
|
|
//
|
|
|
|
|
// fn benchmark(ordering: Ordering, iterations: usize) -> u128 {
|
|
|
|
|
// let counter = Arc::new(AtomicUsize::new(0));
|
|
|
|
|
// let start = Instant::now();
|
|
|
|
|
//
|
|
|
|
|
// let handles: Vec<_> = (0..32)
|
|
|
|
|
// .map(|_| {
|
|
|
|
|
// let counter_ref = Arc::clone(&counter);
|
|
|
|
|
// thread::spawn(move || {
|
|
|
|
|
// for _ in 0..iterations {
|
|
|
|
|
// counter_ref.fetch_add(1, ordering);
|
|
|
|
|
// }
|
|
|
|
|
// })
|
|
|
|
|
// })
|
|
|
|
|
// .collect();
|
|
|
|
|
//
|
2025-04-28 20:28:33 +02:00
|
|
|
|
|
|
|
|
|
2025-03-21 15:56:30 +01:00
|
|
|
// for handle in handles {
|
|
|
|
|
// handle.join().unwrap();
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// let duration = start.elapsed();
|
|
|
|
|
// duration.as_millis()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// #[test]
|
|
|
|
|
// fn test_ordering() {
|
|
|
|
|
// let iterations = 1_000_000;
|
|
|
|
|
//
|
|
|
|
|
// let time_acqrel = benchmark(Ordering::SeqCst, iterations);
|
|
|
|
|
// println!("AcqRel: {} ms", time_acqrel);
|
|
|
|
|
//
|
|
|
|
|
// let time_seqcst = benchmark(Ordering::SeqCst, iterations);
|
|
|
|
|
// println!("SeqCst: {} ms", time_seqcst);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// }
|