//! Session database operations use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use uuid::Uuid; /// Session record from database #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct DbSession { pub id: Uuid, pub machine_id: Option, pub started_at: DateTime, pub ended_at: Option>, pub duration_secs: Option, pub is_support_session: bool, pub support_code: Option, pub status: String, } /// Create a new session record pub async fn create_session( pool: &PgPool, session_id: Uuid, machine_id: Uuid, is_support_session: bool, support_code: Option<&str>, ) -> Result { sqlx::query_as::<_, DbSession>( r#" INSERT INTO connect_sessions (id, machine_id, is_support_session, support_code, status) VALUES ($1, $2, $3, $4, 'active') RETURNING * "#, ) .bind(session_id) .bind(machine_id) .bind(is_support_session) .bind(support_code) .fetch_one(pool) .await } /// End a session pub async fn end_session( pool: &PgPool, session_id: Uuid, status: &str, // 'ended' or 'disconnected' or 'timeout' ) -> Result<(), sqlx::Error> { sqlx::query( r#" UPDATE connect_sessions SET ended_at = NOW(), duration_secs = EXTRACT(EPOCH FROM (NOW() - started_at))::INTEGER, status = $1 WHERE id = $2 "#, ) .bind(status) .bind(session_id) .execute(pool) .await?; Ok(()) } /// Get session by ID pub async fn get_session(pool: &PgPool, session_id: Uuid) -> Result, sqlx::Error> { sqlx::query_as::<_, DbSession>("SELECT * FROM connect_sessions WHERE id = $1") .bind(session_id) .fetch_optional(pool) .await } /// Get active sessions for a machine pub async fn get_active_sessions_for_machine( pool: &PgPool, machine_id: Uuid, ) -> Result, sqlx::Error> { sqlx::query_as::<_, DbSession>( "SELECT * FROM connect_sessions WHERE machine_id = $1 AND status = 'active' ORDER BY started_at DESC" ) .bind(machine_id) .fetch_all(pool) .await } /// Get recent sessions (for dashboard) pub async fn get_recent_sessions( pool: &PgPool, limit: i64, ) -> Result, sqlx::Error> { sqlx::query_as::<_, DbSession>( "SELECT * FROM connect_sessions ORDER BY started_at DESC LIMIT $1" ) .bind(limit) .fetch_all(pool) .await } /// Get all sessions for a machine (for history export) pub async fn get_sessions_for_machine( pool: &PgPool, machine_id: Uuid, ) -> Result, sqlx::Error> { sqlx::query_as::<_, DbSession>( "SELECT * FROM connect_sessions WHERE machine_id = $1 ORDER BY started_at DESC" ) .bind(machine_id) .fetch_all(pool) .await }