Skip to main content

ferrex_model/
events.rs

1use std::{fmt, str::FromStr};
2
3use crate::media_events::MediaEvent;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
8pub enum ScanSseEventType {
9    Started,
10    Progress,
11    Quiescing,
12    Completed,
13    Failed,
14}
15
16impl ScanSseEventType {
17    pub const fn event_name(self) -> &'static str {
18        match self {
19            Self::Started => "scan.started",
20            Self::Progress => "scan.progress",
21            Self::Quiescing => "scan.quiescing",
22            Self::Completed => "scan.completed",
23            Self::Failed => "scan.failed",
24        }
25    }
26}
27
28impl fmt::Display for ScanSseEventType {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.write_str(self.event_name())
31    }
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct ParseScanSseEventTypeError {
36    invalid_value: String,
37}
38
39impl ParseScanSseEventTypeError {
40    pub fn new(value: &str) -> Self {
41        Self {
42            invalid_value: value.to_string(),
43        }
44    }
45}
46
47impl fmt::Display for ParseScanSseEventTypeError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "invalid scan SSE event type: {}", self.invalid_value)
50    }
51}
52
53impl std::error::Error for ParseScanSseEventTypeError {}
54
55impl FromStr for ScanSseEventType {
56    type Err = ParseScanSseEventTypeError;
57
58    fn from_str(value: &str) -> Result<Self, Self::Err> {
59        match value {
60            "scan.started" => Ok(Self::Started),
61            "scan.progress" => Ok(Self::Progress),
62            "scan.quiescing" => Ok(Self::Quiescing),
63            "scan.completed" => Ok(Self::Completed),
64            "scan.failed" => Ok(Self::Failed),
65            other => Err(ParseScanSseEventTypeError::new(other)),
66        }
67    }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
73pub enum MediaSseEventType {
74    MovieAdded,
75    MovieBatchFinalized,
76    SeriesAdded,
77    SeriesBundleFinalized,
78    SeasonAdded,
79    EpisodeAdded,
80    MovieUpdated,
81    SeriesUpdated,
82    SeasonUpdated,
83    EpisodeUpdated,
84    MediaDeleted,
85    Scan(ScanSseEventType),
86}
87
88impl MediaSseEventType {
89    pub const fn event_name(self) -> &'static str {
90        match self {
91            Self::MovieAdded => "media.movie_added",
92            Self::MovieBatchFinalized => "media.movie_batch_finalized",
93            Self::SeriesAdded => "media.series_added",
94            Self::SeriesBundleFinalized => "media.series_bundle_finalized",
95            Self::SeasonAdded => "media.season_added",
96            Self::EpisodeAdded => "media.episode_added",
97            Self::MovieUpdated => "media.movie_updated",
98            Self::SeriesUpdated => "media.series_updated",
99            Self::SeasonUpdated => "media.season_updated",
100            Self::EpisodeUpdated => "media.episode_updated",
101            Self::MediaDeleted => "media.deleted",
102            Self::Scan(kind) => kind.event_name(),
103        }
104    }
105}
106
107impl fmt::Display for MediaSseEventType {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        f.write_str(self.event_name())
110    }
111}
112
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub struct ParseMediaSseEventTypeError {
115    invalid_value: String,
116}
117
118impl ParseMediaSseEventTypeError {
119    pub fn new(value: &str) -> Self {
120        Self {
121            invalid_value: value.to_string(),
122        }
123    }
124}
125
126impl fmt::Display for ParseMediaSseEventTypeError {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        write!(f, "invalid media SSE event type: {}", self.invalid_value)
129    }
130}
131
132impl std::error::Error for ParseMediaSseEventTypeError {}
133
134impl FromStr for MediaSseEventType {
135    type Err = ParseMediaSseEventTypeError;
136
137    fn from_str(value: &str) -> Result<Self, Self::Err> {
138        match value {
139            "media.movie_added" => Ok(Self::MovieAdded),
140            "media.movie_batch_finalized" => Ok(Self::MovieBatchFinalized),
141            "media.series_added" => Ok(Self::SeriesAdded),
142            "media.series_bundle_finalized" => Ok(Self::SeriesBundleFinalized),
143            "media.season_added" => Ok(Self::SeasonAdded),
144            "media.episode_added" => Ok(Self::EpisodeAdded),
145            "media.movie_updated" => Ok(Self::MovieUpdated),
146            "media.series_updated" => Ok(Self::SeriesUpdated),
147            "media.season_updated" => Ok(Self::SeasonUpdated),
148            "media.episode_updated" => Ok(Self::EpisodeUpdated),
149            "media.deleted" => Ok(Self::MediaDeleted),
150            other => match ScanSseEventType::from_str(other) {
151                Ok(kind) => Ok(Self::Scan(kind)),
152                Err(_) => Err(ParseMediaSseEventTypeError::new(other)),
153            },
154        }
155    }
156}
157
158impl MediaEvent {
159    pub fn sse_event_type(&self) -> MediaSseEventType {
160        match self {
161            MediaEvent::MovieAdded { .. } => MediaSseEventType::MovieAdded,
162            MediaEvent::MovieBatchFinalized { .. } => {
163                MediaSseEventType::MovieBatchFinalized
164            }
165            MediaEvent::SeriesBundleFinalized { .. } => {
166                MediaSseEventType::SeriesBundleFinalized
167            }
168            MediaEvent::SeriesAdded { .. } => MediaSseEventType::SeriesAdded,
169            MediaEvent::MovieUpdated { .. } => MediaSseEventType::MovieUpdated,
170            MediaEvent::SeriesUpdated { .. } => {
171                MediaSseEventType::SeriesUpdated
172            }
173            MediaEvent::MediaDeleted { .. } => MediaSseEventType::MediaDeleted,
174            MediaEvent::ScanStarted { .. } => {
175                MediaSseEventType::Scan(ScanSseEventType::Started)
176            }
177            MediaEvent::ScanProgress { .. } => {
178                MediaSseEventType::Scan(ScanSseEventType::Progress)
179            }
180            MediaEvent::ScanCompleted { .. } => {
181                MediaSseEventType::Scan(ScanSseEventType::Completed)
182            }
183            MediaEvent::ScanFailed { .. } => {
184                MediaSseEventType::Scan(ScanSseEventType::Failed)
185            }
186        }
187    }
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
192#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
193pub enum ImageSseEventType {
194    Ready,
195}
196
197impl ImageSseEventType {
198    pub const fn event_name(self) -> &'static str {
199        match self {
200            Self::Ready => "image.ready",
201        }
202    }
203}
204
205impl fmt::Display for ImageSseEventType {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        f.write_str(self.event_name())
208    }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq)]
212pub struct ParseImageSseEventTypeError {
213    invalid_value: String,
214}
215
216impl ParseImageSseEventTypeError {
217    pub fn new(value: &str) -> Self {
218        Self {
219            invalid_value: value.to_string(),
220        }
221    }
222}
223
224impl fmt::Display for ParseImageSseEventTypeError {
225    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226        write!(f, "invalid image SSE event type: {}", self.invalid_value)
227    }
228}
229
230impl std::error::Error for ParseImageSseEventTypeError {}
231
232impl FromStr for ImageSseEventType {
233    type Err = ParseImageSseEventTypeError;
234
235    fn from_str(value: &str) -> Result<Self, Self::Err> {
236        match value {
237            "image.ready" => Ok(Self::Ready),
238            other => Err(ParseImageSseEventTypeError::new(other)),
239        }
240    }
241}
242
243#[cfg(test)]
244mod tests {
245    use super::{ImageSseEventType, MediaSseEventType, ScanSseEventType};
246    use std::str::FromStr;
247
248    #[test]
249    fn scan_event_name_roundtrip() {
250        for (name, value) in [
251            ("scan.started", ScanSseEventType::Started),
252            ("scan.progress", ScanSseEventType::Progress),
253            ("scan.quiescing", ScanSseEventType::Quiescing),
254            ("scan.completed", ScanSseEventType::Completed),
255            ("scan.failed", ScanSseEventType::Failed),
256        ] {
257            assert_eq!(value.event_name(), name);
258            assert_eq!(ScanSseEventType::from_str(name).unwrap(), value);
259        }
260    }
261
262    #[test]
263    fn media_event_name_roundtrip() {
264        for (name, value) in [
265            ("media.movie_added", MediaSseEventType::MovieAdded),
266            (
267                "media.movie_batch_finalized",
268                MediaSseEventType::MovieBatchFinalized,
269            ),
270            ("media.series_added", MediaSseEventType::SeriesAdded),
271            (
272                "media.series_bundle_finalized",
273                MediaSseEventType::SeriesBundleFinalized,
274            ),
275            ("media.season_added", MediaSseEventType::SeasonAdded),
276            ("media.episode_added", MediaSseEventType::EpisodeAdded),
277            ("media.movie_updated", MediaSseEventType::MovieUpdated),
278            ("media.series_updated", MediaSseEventType::SeriesUpdated),
279            ("media.season_updated", MediaSseEventType::SeasonUpdated),
280            ("media.episode_updated", MediaSseEventType::EpisodeUpdated),
281            ("media.deleted", MediaSseEventType::MediaDeleted),
282            (
283                "scan.started",
284                MediaSseEventType::Scan(ScanSseEventType::Started),
285            ),
286            (
287                "scan.progress",
288                MediaSseEventType::Scan(ScanSseEventType::Progress),
289            ),
290            (
291                "scan.quiescing",
292                MediaSseEventType::Scan(ScanSseEventType::Quiescing),
293            ),
294            (
295                "scan.completed",
296                MediaSseEventType::Scan(ScanSseEventType::Completed),
297            ),
298            (
299                "scan.failed",
300                MediaSseEventType::Scan(ScanSseEventType::Failed),
301            ),
302        ] {
303            assert_eq!(value.event_name(), name);
304            assert_eq!(MediaSseEventType::from_str(name).unwrap(), value);
305        }
306    }
307
308    #[test]
309    fn image_event_name_roundtrip() {
310        {
311            let (name, value) = ("image.ready", ImageSseEventType::Ready);
312            assert_eq!(value.event_name(), name);
313            assert_eq!(ImageSseEventType::from_str(name).unwrap(), value);
314        }
315    }
316}