Add PostgreSQL database persistence
- Add connect_machines, connect_sessions, connect_session_events, connect_support_codes tables - Implement db module with connection pooling (sqlx) - Add machine persistence across server restarts - Add audit logging for session/viewer events - Support codes now persisted to database 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
107
server/src/db/events.rs
Normal file
107
server/src/db/events.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
//! Audit event logging
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
use sqlx::PgPool;
|
||||
use std::net::IpAddr;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Session event record from database
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct SessionEvent {
|
||||
pub id: i64,
|
||||
pub session_id: Uuid,
|
||||
pub event_type: String,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub viewer_id: Option<String>,
|
||||
pub viewer_name: Option<String>,
|
||||
pub details: Option<JsonValue>,
|
||||
pub ip_address: Option<String>,
|
||||
}
|
||||
|
||||
/// Event types for session audit logging
|
||||
pub struct EventTypes;
|
||||
|
||||
impl EventTypes {
|
||||
pub const SESSION_STARTED: &'static str = "session_started";
|
||||
pub const SESSION_ENDED: &'static str = "session_ended";
|
||||
pub const SESSION_TIMEOUT: &'static str = "session_timeout";
|
||||
pub const VIEWER_JOINED: &'static str = "viewer_joined";
|
||||
pub const VIEWER_LEFT: &'static str = "viewer_left";
|
||||
pub const STREAMING_STARTED: &'static str = "streaming_started";
|
||||
pub const STREAMING_STOPPED: &'static str = "streaming_stopped";
|
||||
}
|
||||
|
||||
/// Log a session event
|
||||
pub async fn log_event(
|
||||
pool: &PgPool,
|
||||
session_id: Uuid,
|
||||
event_type: &str,
|
||||
viewer_id: Option<&str>,
|
||||
viewer_name: Option<&str>,
|
||||
details: Option<JsonValue>,
|
||||
ip_address: Option<IpAddr>,
|
||||
) -> Result<i64, sqlx::Error> {
|
||||
let ip_str = ip_address.map(|ip| ip.to_string());
|
||||
|
||||
let result = sqlx::query_scalar::<_, i64>(
|
||||
r#"
|
||||
INSERT INTO connect_session_events
|
||||
(session_id, event_type, viewer_id, viewer_name, details, ip_address)
|
||||
VALUES ($1, $2, $3, $4, $5, $6::inet)
|
||||
RETURNING id
|
||||
"#,
|
||||
)
|
||||
.bind(session_id)
|
||||
.bind(event_type)
|
||||
.bind(viewer_id)
|
||||
.bind(viewer_name)
|
||||
.bind(details)
|
||||
.bind(ip_str)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Get events for a session
|
||||
pub async fn get_session_events(
|
||||
pool: &PgPool,
|
||||
session_id: Uuid,
|
||||
) -> Result<Vec<SessionEvent>, sqlx::Error> {
|
||||
sqlx::query_as::<_, SessionEvent>(
|
||||
"SELECT id, session_id, event_type, timestamp, viewer_id, viewer_name, details, ip_address::text as ip_address FROM connect_session_events WHERE session_id = $1 ORDER BY timestamp"
|
||||
)
|
||||
.bind(session_id)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get recent events (for dashboard)
|
||||
pub async fn get_recent_events(
|
||||
pool: &PgPool,
|
||||
limit: i64,
|
||||
) -> Result<Vec<SessionEvent>, sqlx::Error> {
|
||||
sqlx::query_as::<_, SessionEvent>(
|
||||
"SELECT id, session_id, event_type, timestamp, viewer_id, viewer_name, details, ip_address::text as ip_address FROM connect_session_events ORDER BY timestamp DESC LIMIT $1"
|
||||
)
|
||||
.bind(limit)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Get events by type
|
||||
pub async fn get_events_by_type(
|
||||
pool: &PgPool,
|
||||
event_type: &str,
|
||||
limit: i64,
|
||||
) -> Result<Vec<SessionEvent>, sqlx::Error> {
|
||||
sqlx::query_as::<_, SessionEvent>(
|
||||
"SELECT id, session_id, event_type, timestamp, viewer_id, viewer_name, details, ip_address::text as ip_address FROM connect_session_events WHERE event_type = $1 ORDER BY timestamp DESC LIMIT $2"
|
||||
)
|
||||
.bind(event_type)
|
||||
.bind(limit)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
}
|
||||
Reference in New Issue
Block a user