refactor(cast): move CastState and DlnaState to dedicated state modules

Relocates CastState (struct + impl) from cast/commands.rs to
cast/state.rs, and DlnaState (struct + impl) from
cast/dlna/commands.rs to cast/dlna/state.rs.

Both types are consumed by commands_v2/library.rs (and the legacy
Tauri commands themselves) via the existing re-exports in
cast/mod.rs and cast/dlna/mod.rs. The re-exports are updated to
source from the new state modules, and each commands.rs re-exports
its state type so historical
crate::cast::commands::CastState / crate::cast::dlna::commands::DlnaState
paths continue to compile.

This unblocks future deletion of cast/commands.rs and
cast/dlna/commands.rs in a later cleanup step (the
#[tauri::command] functions in those files are already
unregistered and have zero Rust call sites).

cc
This commit is contained in:
vicrodh committed 2026-04-26 17:19:21 -06:00
1 parent e0dc464a65
commit ac44b8a713
6 files changed
+102 -73

No files matched your search

+4 -36
View File
@@ -1,49 +1,17 @@
//! Tauri commands for Chromecast casting
use std::sync::Arc;
use tauri::State;
use tokio::sync::Mutex;
use crate::api::models::Quality;
use crate::cast::chromecast_thread::ChromecastHandle;
use crate::cast::{
CastError, CastPositionInfo, CastStatus, DeviceDiscovery, DiscoveredDevice, MediaMetadata,
MediaServer,
CastError, CastPositionInfo, CastStatus, DiscoveredDevice, MediaMetadata,
};
use crate::library::{AudioFormat, LibraryState};
use crate::AppState;
/// Cast state shared across commands
/// Uses a dedicated thread for Chromecast operations since rust_cast is not thread-safe
pub struct CastState {
pub discovery: Arc<Mutex<DeviceDiscovery>>,
pub chromecast: ChromecastHandle,
/// Media server is lazily initialized on first cast operation to save CPU when not casting
pub media_server: Arc<Mutex<Option<MediaServer>>>,
pub connected_device_ip: Arc<Mutex<Option<String>>>,
}
impl CastState {
pub fn new() -> Result<Self, CastError> {
Ok(Self {
discovery: Arc::new(Mutex::new(DeviceDiscovery::new())),
chromecast: ChromecastHandle::new(),
// Don't start media server until needed - saves CPU when not casting
media_server: Arc::new(Mutex::new(None)),
connected_device_ip: Arc::new(Mutex::new(None)),
})
}
/// Get or create the media server (lazy initialization)
pub async fn get_or_create_media_server(&self) -> Result<(), CastError> {
let mut server_guard = self.media_server.lock().await;
if server_guard.is_none() {
log::info!("Starting media server on demand (lazy init)");
*server_guard = Some(MediaServer::start()?);
}
Ok(())
}
}
// CastState lives in `super::state`; re-export from commands so any
// historical `crate::cast::commands::CastState` paths continue to compile.
pub use super::state::CastState;
// === Discovery ===
+5 -34
View File
@@ -1,46 +1,17 @@
//! Tauri commands for DLNA/UPnP casting
use std::sync::Arc;
use tauri::State;
use tokio::sync::Mutex;
use crate::api::models::Quality;
use crate::cast::dlna::{
DiscoveredDlnaDevice, DlnaConnection, DlnaDiscovery, DlnaError, DlnaMetadata, DlnaPositionInfo,
DlnaStatus,
DiscoveredDlnaDevice, DlnaConnection, DlnaError, DlnaMetadata, DlnaPositionInfo, DlnaStatus,
};
use crate::cast::MediaServer;
use crate::AppState;
/// DLNA state shared across commands
pub struct DlnaState {
pub discovery: Arc<Mutex<DlnaDiscovery>>,
pub connection: Arc<Mutex<Option<DlnaConnection>>>,
/// Shared media server (lazily initialized)
pub media_server: Arc<Mutex<Option<MediaServer>>>,
}
impl DlnaState {
pub fn new(media_server: Arc<Mutex<Option<MediaServer>>>) -> Result<Self, DlnaError> {
Ok(Self {
discovery: Arc::new(Mutex::new(DlnaDiscovery::new())),
connection: Arc::new(Mutex::new(None)),
media_server,
})
}
/// Ensure media server is started (lazy initialization)
pub async fn ensure_media_server(&self) -> Result<(), DlnaError> {
let mut server_guard = self.media_server.lock().await;
if server_guard.is_none() {
log::info!("Starting media server on demand for DLNA");
*server_guard = Some(MediaServer::start().map_err(|e| {
DlnaError::Connection(format!("Failed to start media server: {}", e))
})?);
}
Ok(())
}
}
// DlnaState lives in `super::state`; re-export from commands so any
// historical `crate::cast::dlna::commands::DlnaState` paths continue
// to compile.
pub use super::state::DlnaState;
// === Discovery ===
+2 -1
View File
@@ -3,6 +3,7 @@
//! Core functionality is in qbz-cast crate, this module provides Tauri commands.
pub mod commands;
pub mod state;
// Re-export from qbz-cast
pub use qbz_cast::{
@@ -11,4 +12,4 @@ pub use qbz_cast::{
};
// Re-export Tauri command state
pub use commands::DlnaState;
pub use state::DlnaState;
+42
View File
@@ -0,0 +1,42 @@
//! Shared state types for the DLNA/UPnP cast module.
//!
//! Originally co-located with the Tauri commands in
//! `cast/dlna/commands.rs`. Relocated here so the type surface
//! remains available after the legacy `#[tauri::command]` definitions
//! in `commands.rs` are eventually removed.
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::cast::dlna::{DlnaConnection, DlnaDiscovery, DlnaError};
use crate::cast::MediaServer;
/// DLNA state shared across commands
pub struct DlnaState {
pub discovery: Arc<Mutex<DlnaDiscovery>>,
pub connection: Arc<Mutex<Option<DlnaConnection>>>,
/// Shared media server (lazily initialized)
pub media_server: Arc<Mutex<Option<MediaServer>>>,
}
impl DlnaState {
pub fn new(media_server: Arc<Mutex<Option<MediaServer>>>) -> Result<Self, DlnaError> {
Ok(Self {
discovery: Arc::new(Mutex::new(DlnaDiscovery::new())),
connection: Arc::new(Mutex::new(None)),
media_server,
})
}
/// Ensure media server is started (lazy initialization)
pub async fn ensure_media_server(&self) -> Result<(), DlnaError> {
let mut server_guard = self.media_server.lock().await;
if server_guard.is_none() {
log::info!("Starting media server on demand for DLNA");
*server_guard = Some(MediaServer::start().map_err(|e| {
DlnaError::Connection(format!("Failed to start media server: {}", e))
})?);
}
Ok(())
}
}
+3 -2
View File
@@ -10,6 +10,7 @@ pub mod discovery;
pub mod dlna;
pub mod errors;
pub mod media_server;
pub mod state;
// Re-export from qbz-cast for internal use
pub use qbz_cast::{
@@ -20,5 +21,5 @@ pub use qbz_cast::{
};
// Re-export Tauri command states
pub use commands::CastState;
pub use dlna::commands::DlnaState;
pub use state::CastState;
pub use dlna::state::DlnaState;
+46
View File
@@ -0,0 +1,46 @@
//! Shared state types for the cast (Chromecast) module.
//!
//! Originally co-located with the Tauri commands in `cast/commands.rs`.
//! Relocated here so the type surface remains available after the
//! legacy `#[tauri::command]` definitions in `commands.rs` are
//! eventually removed.
use std::sync::Arc;
use tokio::sync::Mutex;
use crate::cast::chromecast_thread::ChromecastHandle;
use crate::cast::{CastError, DeviceDiscovery, MediaServer};
/// Cast state shared across commands.
///
/// Uses a dedicated thread for Chromecast operations since rust_cast
/// is not thread-safe.
pub struct CastState {
pub discovery: Arc<Mutex<DeviceDiscovery>>,
pub chromecast: ChromecastHandle,
/// Media server is lazily initialized on first cast operation to save CPU when not casting
pub media_server: Arc<Mutex<Option<MediaServer>>>,
pub connected_device_ip: Arc<Mutex<Option<String>>>,
}
impl CastState {
pub fn new() -> Result<Self, CastError> {
Ok(Self {
discovery: Arc::new(Mutex::new(DeviceDiscovery::new())),
chromecast: ChromecastHandle::new(),
// Don't start media server until needed - saves CPU when not casting
media_server: Arc::new(Mutex::new(None)),
connected_device_ip: Arc::new(Mutex::new(None)),
})
}
/// Get or create the media server (lazy initialization)
pub async fn get_or_create_media_server(&self) -> Result<(), CastError> {
let mut server_guard = self.media_server.lock().await;
if server_guard.is_none() {
log::info!("Starting media server on demand (lazy init)");
*server_guard = Some(MediaServer::start()?);
}
Ok(())
}
}