libraries: PATCH /libraries/{id} with live-apply
Adds an HTTP mutation surface for `libraries.enabled` and `libraries.excluded_dirs`, replacing the SQL-only workflow noted in CLAUDE.md. Apollo's Settings panel calls this from the LIBRARIES section so the operator no longer has to ssh + sqlite3 to flip a library off or edit its excludes. Live-apply (no restart) via a new `live_libraries: Arc<RwLock<Vec< Library>>>` field on AppState. The existing immutable `libraries` Vec stays for hot-path handlers that only need stable id → root_path lookups, avoiding a 19-call-site refactor. The watcher and cleanup_orphaned_playlists now take the lock instead of a Vec snapshot and re-read at the top of each tick, so `enabled` / `excluded_dirs` changes are picked up within one WATCH_QUICK_INTERVAL_SECONDS. The GET /libraries handler also reads through the live view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
16
src/state.rs
16
src/state.rs
@@ -18,15 +18,25 @@ use crate::video::actors::{
|
||||
};
|
||||
use actix::{Actor, Addr};
|
||||
use std::env;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
pub struct AppState {
|
||||
pub stream_manager: Arc<Addr<StreamActor>>,
|
||||
pub playlist_manager: Arc<Addr<VideoPlaylistManager>>,
|
||||
pub preview_clip_generator: Arc<Addr<PreviewClipGenerator>>,
|
||||
/// All configured media libraries. Ordered by `id` ascending; the first
|
||||
/// entry is the primary library.
|
||||
/// entry is the primary library. Frozen at startup — handlers that
|
||||
/// only need stable lookup (id → name / root_path) read this. Mutable
|
||||
/// flags (`enabled`, `excluded_dirs`) reflect their startup values;
|
||||
/// for live state see [`AppState::live_libraries`].
|
||||
pub libraries: Vec<Library>,
|
||||
/// Live view of the libraries table, shared mutably between the
|
||||
/// watcher (which reads it at the top of each tick to honour the
|
||||
/// latest `enabled` / `excluded_dirs`) and the PATCH /libraries/{id}
|
||||
/// handler (which writes it on a successful mutation). The split
|
||||
/// from [`AppState::libraries`] is deliberate: handlers that only
|
||||
/// look up by id don't need to take a lock per request.
|
||||
pub live_libraries: Arc<RwLock<Vec<Library>>>,
|
||||
/// Per-library availability snapshot. Updated by the file watcher at
|
||||
/// the top of each tick via `libraries::refresh_health`. HTTP handlers
|
||||
/// read it (e.g. `/libraries` surfacing). See "Library availability
|
||||
@@ -112,11 +122,13 @@ impl AppState {
|
||||
);
|
||||
|
||||
let library_health = libraries::new_health_map(&libraries_vec);
|
||||
let live_libraries = Arc::new(RwLock::new(libraries_vec.clone()));
|
||||
Self {
|
||||
stream_manager,
|
||||
playlist_manager: Arc::new(video_playlist_manager.start()),
|
||||
preview_clip_generator: Arc::new(preview_clip_generator.start()),
|
||||
libraries: libraries_vec,
|
||||
live_libraries,
|
||||
library_health,
|
||||
base_path,
|
||||
thumbnail_path,
|
||||
|
||||
Reference in New Issue
Block a user