- 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
82 lines
3.1 KiB
Rust
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())
|
|
}
|
|
}
|