Skip to main content

kino_core/
error.rs

1//! Error types for Kino Core
2
3use thiserror::Error;
4
5/// Result type alias for player operations
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Player error types
9#[derive(Error, Debug)]
10pub enum Error {
11    // Manifest errors
12    #[error("Failed to fetch manifest: {0}")]
13    ManifestFetch(String),
14
15    #[error("Failed to parse manifest: {0}")]
16    ManifestParse(String),
17
18    #[error("Invalid manifest format: {0}")]
19    InvalidManifest(String),
20
21    #[error("No suitable rendition found")]
22    NoSuitableRendition,
23
24    // Segment errors
25    #[error("Failed to fetch segment: {url}")]
26    SegmentFetch { url: String, source: reqwest::Error },
27
28    #[error("Segment timeout: {url}")]
29    SegmentTimeout { url: String },
30
31    #[error("Segment decryption failed")]
32    SegmentDecryption,
33
34    // Buffer errors
35    #[error("Buffer underrun")]
36    BufferUnderrun,
37
38    #[error("Buffer overflow")]
39    BufferOverflow,
40
41    #[error("Buffer seek failed: position {position}s not buffered")]
42    BufferSeekFailed { position: f64 },
43
44    // DRM errors
45    #[error("DRM not supported: {system}")]
46    DrmNotSupported { system: String },
47
48    #[error("License acquisition failed: {0}")]
49    LicenseAcquisition(String),
50
51    #[error("License expired")]
52    LicenseExpired,
53
54    #[error("Content key not found")]
55    ContentKeyNotFound,
56
57    // Playback errors
58    #[error("Playback stalled")]
59    PlaybackStalled,
60
61    #[error("Invalid playback state transition: {from} -> {to}")]
62    InvalidStateTransition { from: String, to: String },
63
64    #[error("Codec not supported: {codec}")]
65    CodecNotSupported { codec: String },
66
67    // Network errors
68    #[error("Network error: {0}")]
69    Network(#[from] reqwest::Error),
70
71    #[error("Connection timeout")]
72    ConnectionTimeout,
73
74    // Configuration errors
75    #[error("Invalid configuration: {0}")]
76    InvalidConfig(String),
77
78    // Internal errors
79    #[error("Internal error: {0}")]
80    Internal(String),
81
82    #[error("IO error: {0}")]
83    Io(#[from] std::io::Error),
84}
85
86impl Error {
87    /// Create a DRM error
88    pub fn drm(msg: impl Into<String>) -> Self {
89        Error::LicenseAcquisition(msg.into())
90    }
91
92    /// Returns true if this error is recoverable
93    pub fn is_recoverable(&self) -> bool {
94        matches!(
95            self,
96            Error::SegmentFetch { .. }
97                | Error::SegmentTimeout { .. }
98                | Error::BufferUnderrun
99                | Error::Network(_)
100                | Error::ConnectionTimeout
101        )
102    }
103
104    /// Returns the error code for analytics
105    pub fn error_code(&self) -> &'static str {
106        match self {
107            Error::ManifestFetch(_) => "MANIFEST_FETCH",
108            Error::ManifestParse(_) => "MANIFEST_PARSE",
109            Error::InvalidManifest(_) => "INVALID_MANIFEST",
110            Error::NoSuitableRendition => "NO_RENDITION",
111            Error::SegmentFetch { .. } => "SEGMENT_FETCH",
112            Error::SegmentTimeout { .. } => "SEGMENT_TIMEOUT",
113            Error::SegmentDecryption => "SEGMENT_DECRYPT",
114            Error::BufferUnderrun => "BUFFER_UNDERRUN",
115            Error::BufferOverflow => "BUFFER_OVERFLOW",
116            Error::BufferSeekFailed { .. } => "BUFFER_SEEK",
117            Error::DrmNotSupported { .. } => "DRM_UNSUPPORTED",
118            Error::LicenseAcquisition(_) => "LICENSE_ACQUIRE",
119            Error::LicenseExpired => "LICENSE_EXPIRED",
120            Error::ContentKeyNotFound => "KEY_NOT_FOUND",
121            Error::PlaybackStalled => "PLAYBACK_STALLED",
122            Error::InvalidStateTransition { .. } => "INVALID_STATE",
123            Error::CodecNotSupported { .. } => "CODEC_UNSUPPORTED",
124            Error::Network(_) => "NETWORK",
125            Error::ConnectionTimeout => "TIMEOUT",
126            Error::InvalidConfig(_) => "INVALID_CONFIG",
127            Error::Internal(_) => "INTERNAL",
128            Error::Io(_) => "IO",
129        }
130    }
131}