use bytes::Bytes;
use clasp_core::{Message, WelcomeMessage, PROTOCOL_VERSION};
use clasp_transport::TransportSender;
use parking_lot::RwLock;
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Instant;
use uuid::Uuid;
pub type SessionId = String;
pub struct Session {
pub id: SessionId,
pub name: String,
pub features: Vec<String>,
sender: Arc<dyn TransportSender>,
subscriptions: RwLock<HashSet<u32>>,
pub created_at: Instant,
pub last_activity: RwLock<Instant>,
pub authenticated: bool,
pub token: Option<String>,
}
impl Session {
pub fn new(sender: Arc<dyn TransportSender>, name: String, features: Vec<String>) -> Self {
let now = Instant::now();
Self {
id: Uuid::new_v4().to_string(),
name,
features,
sender,
subscriptions: RwLock::new(HashSet::new()),
created_at: now,
last_activity: RwLock::new(now),
authenticated: false,
token: None,
}
}
pub async fn send(&self, data: Bytes) -> Result<(), clasp_transport::TransportError> {
self.sender.send(data).await?;
*self.last_activity.write() = Instant::now();
Ok(())
}
pub async fn send_message(&self, message: &Message) -> Result<(), clasp_core::Error> {
let data = clasp_core::codec::encode(message)?;
self.send(data)
.await
.map_err(|e| clasp_core::Error::ConnectionError(e.to_string()))?;
Ok(())
}
pub fn welcome_message(&self, server_name: &str, server_features: &[String]) -> Message {
Message::Welcome(WelcomeMessage {
version: PROTOCOL_VERSION,
session: self.id.clone(),
name: server_name.to_string(),
features: server_features.to_vec(),
time: clasp_core::time::now(),
token: None,
})
}
pub fn add_subscription(&self, id: u32) {
self.subscriptions.write().insert(id);
}
pub fn remove_subscription(&self, id: u32) -> bool {
self.subscriptions.write().remove(&id)
}
pub fn subscriptions(&self) -> Vec<u32> {
self.subscriptions.read().iter().cloned().collect()
}
pub fn is_connected(&self) -> bool {
self.sender.is_connected()
}
pub fn touch(&self) {
*self.last_activity.write() = Instant::now();
}
pub fn idle_duration(&self) -> std::time::Duration {
self.last_activity.read().elapsed()
}
}
impl std::fmt::Debug for Session {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Session")
.field("id", &self.id)
.field("name", &self.name)
.field("features", &self.features)
.field("authenticated", &self.authenticated)
.finish()
}
}