server/src/session_history.h
Rama main · réplica de lectura del repositorio original.
/**
* @file src/session_history.h
* @brief Declarations for the session history persistence module.
*
* Provides SQLite-backed storage of streaming session metadata, periodic
* performance samples, and discrete events. A dedicated writer thread
* serializes all mutations; read queries use a separate read-only connection.
*
* Computed metrics (actual FPS, actual bitrate, frame-interval jitter) are
* maintained in a private per-session aggregator inside this module and are
* NOT added to session_t::stats or session_info_t.
*/
#pragma once
// standard includes
#include <chrono>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
namespace session_history {
// ── Types ──────────────────────────────────────────────────────────
struct session_metadata_t {
std::string uuid;
std::string protocol; // "rtsp" or "webrtc"
std::string client_name;
std::string device_name;
std::string app_name;
int width = 0;
int height = 0;
int target_fps = 0;
int encoder_bitrate_kbps = 0;
int requested_bitrate_kbps = 0;
std::string codec;
bool hdr = false;
bool yuv444 = false;
int audio_channels = 0;
std::string server_version;
// Static host identification captured at session start.
std::string host_cpu_model;
std::string host_gpu_model;
std::string stream_gpu_model;
};
struct session_sample_t {
std::string session_uuid;
double timestamp_unix = 0;
std::uint64_t bytes_sent_total = 0;
std::uint64_t packets_sent_video = 0;
std::uint64_t frames_sent = 0;
std::int64_t last_frame_index = 0;
std::uint64_t video_dropped = 0;
std::uint64_t audio_dropped = 0;
std::int64_t client_reported_losses = 0;
std::uint32_t idr_requests = 0;
std::uint32_t ref_invalidations = 0;
double encode_latency_ms = 0;
// Computed by the history module's aggregator (not from atomics)
double actual_fps = 0;
double actual_bitrate_kbps = 0;
double frame_interval_jitter_ms = 0;
// Host system snapshot. -1 indicates "not available on this platform".
double host_cpu_percent = -1;
double host_gpu_percent = -1;
double host_gpu_encoder_percent = -1;
double host_ram_percent = -1;
double host_vram_percent = -1;
double host_cpu_temp_c = -1;
double host_gpu_temp_c = -1;
double host_net_rx_bps = -1;
double host_net_tx_bps = -1;
};
struct session_event_t {
std::string session_uuid;
double timestamp_unix = 0;
std::string event_type;
std::string payload; // JSON or empty
};
struct session_summary_t {
std::string uuid;
std::string protocol;
std::string client_name;
std::string device_name;
std::string app_name;
int width = 0;
int height = 0;
int target_fps = 0;
int encoder_bitrate_kbps = 0;
int requested_bitrate_kbps = 0;
std::string codec;
bool hdr = false;
bool yuv444 = false;
int audio_channels = 0;
double start_time_unix = 0;
double end_time_unix = 0;
double duration_seconds = 0;
std::string verdict; // "healthy", "degraded", "failed", "unknown"
std::string server_version;
std::string host_cpu_model;
std::string host_gpu_model;
std::string stream_gpu_model;
};
struct session_detail_t {
session_summary_t summary;
std::size_t total_samples = 0;
std::size_t total_events = 0;
bool samples_truncated = false;
bool events_truncated = false;
std::vector<session_sample_t> samples;
std::vector<session_event_t> events;
};
struct history_status_t {
bool available = false;
bool degraded = false;
std::uint64_t dropped_samples = 0;
std::uint64_t failed_writes = 0;
std::size_t pending_control_commands = 0;
std::size_t pending_priority_commands = 0;
std::size_t pending_regular_commands = 0;
std::size_t pending_samples = 0;
};
struct active_session_t {
std::string uuid;
std::string protocol;
std::string client_name;
std::string device_name;
std::string app_name;
int width = 0;
int height = 0;
int target_fps = 0;
int encoder_bitrate_kbps = 0;
int requested_bitrate_kbps = 0;
std::string codec;
bool hdr = false;
bool yuv444 = false;
std::string stream_gpu_model;
double uptime_seconds = 0;
// Latest computed metrics
double actual_fps = 0;
double actual_bitrate_kbps = 0;
double encode_latency_ms = 0;
double frame_interval_jitter_ms = 0;
// Cumulative counters
std::uint64_t frames_sent = 0;
std::uint64_t bytes_sent = 0;
std::int64_t client_reported_losses = 0;
std::uint32_t idr_requests = 0;
};
// ── Lifecycle ──────────────────────────────────────────────────────
/**
* @brief Initialize the session history module.
* @param db_path Filesystem path for the SQLite database file.
*
* Opens/creates the database, applies schema migrations, and starts the
* writer thread. Must be called once during startup.
*/
void init(const std::string &db_path);
/**
* @brief Shut down the session history module.
*
* Stops the sampling timer and writer thread, flushes pending writes,
* and closes database connections.
*/
void shutdown();
/**
* @brief Reload session history runtime settings from config::sunshine.
*
* Used by config hot-apply so persistence enablement and retention/quota
* changes take effect without restarting Sunshine.
*/
void reload_settings();
// ── Session lifecycle (called from stream.cpp / webrtc_stream.cpp) ─
void begin_session(const session_metadata_t &metadata);
void end_session(const std::string &uuid);
// ── Event recording ───────────────────────────────────────────────
void record_event(const std::string &uuid, const std::string &event_type, const std::string &payload = "");
// ── Read API (called from confighttp.cpp) ──────────────────────────
std::vector<session_summary_t> list_sessions(int limit = 25, int offset = 0);
std::optional<session_detail_t> get_session_detail(const std::string &uuid, bool include_all = false);
std::vector<active_session_t> get_active_sessions();
history_status_t get_history_status();
enum class delete_result_e {
deleted,
not_found,
active_session,
unavailable,
timeout,
failed
};
/**
* @brief Delete a persisted session and its child rows.
*
* The delete is executed on the dedicated writer thread and this call blocks
* until that delete transaction has committed.
*
* @return Detailed outcome for HTTP/API callers.
*/
delete_result_e delete_session(const std::string &uuid);
#ifdef SUNSHINE_TESTS
bool record_sample_for_tests(const session_sample_t &sample);
bool set_session_end_time_for_tests(const std::string &uuid, double end_time_unix);
void configure_retention_for_tests(bool enabled, int ttl_days, std::uint64_t max_db_size_bytes);
bool prune_now_for_tests();
bool force_write_failure_for_tests();
void configure_queue_limits_for_tests(
std::size_t priority_limit,
std::size_t regular_limit,
std::size_t sample_limit,
std::size_t sample_batch_size);
void reset_queue_limits_for_tests();
#endif
} // namespace session_history