Files
pmomusic/pmocontrol/src/errors.rs
Eric Coissac 9b5a028f3f 🎨 Improve mobile safe-area support and refine UPnP/Chromecast rendering
- Add viewport-fit=cover to HTML meta for iOS safe-area support
- Extend bottom drawers and tab bar into system navigation area using env(safe_area_inset_bottom)
- Adjust queue drawer transforms to account for safe-area padding
+ Add enrich_position_from_queue() helper and integrate across UPnP, Arylic TCP,
  LinkPlay & Chromecast backends to ensure queue-authoritative metadata
+ Add transient error retry logic for UPnP control actions (2 retries, 300ms delay)
+ Separate timeouts: short poll timeout for GetTransportInfo/GetPosition (3s),
  longer actiontimeout SetAVTURI/SetNext... for slow devices
+ Remove duplicate continuous-stream detection from play_uri() methods (now handled centrally)
- Bump version to 0.3.49
2026-04-13 04:14:18 +02:00

82 lines
3.1 KiB
Rust

use thiserror::Error;
#[derive(Error, Debug)]
pub enum ControlPointError {
// Utiliser par les DeviceItems dans leur conversion vers un media renderer
#[error("{0} is not a MediaRenderer")]
IsNotAMediaRender(String),
#[error("{0} is not a MediaServer")]
IsNotAMediaServer(String),
#[error("Cannot build MusicRendererBackend for {0}")]
MusicRendererBackendBuild(String),
#[error("{0}")]
ParsingError(String),
#[error("OpenHome Error: {0}")]
OpenHomeError(String),
#[error("OpenHome Product source list does not expose a Playlist entry")]
OpenHomeNoPlaylistEntry(),
#[error("MusicRendererBackend {0} exposes no OpenHome services")]
OpenHomeNotAValidDevice(String),
#[error("UpnpError Error: {0}")]
UpnpError(String),
#[error("MusicRenderer operation '{0}' is not supported by backend '{1}'")]
UpnpOperationNotSupported(String, String),
#[error("Missing {0} element in SOAP body")]
UpnpMissingReturnValue(String),
#[error("Invalid {0} value: {1}")]
UpnpBadReturnValue(String, String),
#[error("Soap Error: Upnp action call {0}")]
SoapAction(String),
#[error("{0} returned UPnP error {1}: {2} (HTTP status {3})")]
SoapUpnpParseError(String, u32, String, u32),
#[error("{0} failed with HTTP status {1} and body: {2}")]
SoapActionWrongBody(String, u32, String),
#[error("Soap Error: No envelop for action {0}")]
SoapNoEnvelop(String),
#[error("ArilycTcp Error: {0}")]
ArilycTcpError(String),
#[error("LinkPlay Error: {0}")]
LinkPlayError(String),
#[error("Chromecast Error: {0}")]
ChromecastError(String),
#[error("MediaServer Error: {0}")]
MediaServerError(String),
#[error("Queue Error: {0}")]
QueueError(String),
#[error("Invalid time format: {0}")]
InvalidTimeFormat(String),
#[error("Error on snapshot: {0}")]
SnapshotError(String),
#[error("Error on ControlPoint: {0}")]
ControlPoint(String),
#[error("Queue sync cancelled (superseded by a newer request)")]
SyncCancelled,
}
impl ControlPointError {
pub fn upnp_operation_not_supported(operation: &str, service: &str) -> Self {
ControlPointError::UpnpOperationNotSupported(operation.to_string(), service.to_string())
}
/// Returns true if the error is a transient transport-level failure that
/// may succeed on retry (TCP refused, connection reset, timeout).
///
/// Protocol-level errors (UPnP fault, HTTP 4xx/5xx with a valid body)
/// are **not** transient: the device understood the request and rejected it.
pub fn is_transient_soap_error(&self) -> bool {
matches!(self, ControlPointError::SoapAction(_))
}
pub fn upnp_missing_return_value(value: &str) -> Self {
ControlPointError::UpnpMissingReturnValue(value.to_string())
}
pub fn upnp_bad_return_value(name: &str, value: &str) -> Self {
ControlPointError::UpnpBadReturnValue(name.to_string(), value.to_string())
}
pub fn arilyc_tcp_error(message: &str) -> Self {
ControlPointError::ArilycTcpError(message.to_string())
}
}