Skip to main content

jellytau_lib/download/
events.rs

1//! Download events for progress tracking and status updates
2
3use serde::{Deserialize, Serialize};
4
5/// Events emitted during download operations
6#[derive(Debug, Clone, Serialize, Deserialize)]
7#[serde(tag = "type", rename_all = "camelCase")]
8pub enum DownloadEvent {
9    /// Download has been queued
10    #[serde(rename_all = "camelCase")]
11    Queued { download_id: i64, item_id: String },
12    /// Download has started
13    #[serde(rename_all = "camelCase")]
14    Started { download_id: i64, item_id: String },
15    /// Download progress update
16    #[serde(rename_all = "camelCase")]
17    Progress {
18        download_id: i64,
19        item_id: String,
20        bytes_downloaded: i64,
21        total_bytes: Option<i64>,
22        progress: f64, // 0.0 to 1.0
23    },
24    /// Download completed successfully
25    #[serde(rename_all = "camelCase")]
26    Completed {
27        download_id: i64,
28        item_id: String,
29        file_path: String,
30    },
31    /// Download failed with error
32    #[serde(rename_all = "camelCase")]
33    Failed {
34        download_id: i64,
35        item_id: String,
36        error: String,
37    },
38    /// Download paused
39    #[serde(rename_all = "camelCase")]
40    Paused { download_id: i64, item_id: String },
41    /// Download cancelled
42    #[serde(rename_all = "camelCase")]
43    Cancelled { download_id: i64, item_id: String },
44    /// The queue is holding: WiFi-only is enabled and the current network is
45    /// metered/cellular. Pending rows stay pending and resume on network change.
46    ///
47    /// TRACES: UR-053 | DR-074
48    WaitingForNetwork,
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn test_download_event_serialization_roundtrip() {
57        let event = DownloadEvent::Progress {
58            download_id: 1,
59            item_id: "test123".to_string(),
60            bytes_downloaded: 1024,
61            total_bytes: Some(2048),
62            progress: 0.5,
63        };
64
65        let json = serde_json::to_string(&event).unwrap();
66        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();
67
68        match deserialized {
69            DownloadEvent::Progress {
70                download_id,
71                item_id,
72                progress,
73                ..
74            } => {
75                assert_eq!(download_id, 1);
76                assert_eq!(item_id, "test123");
77                assert_eq!(progress, 0.5);
78            }
79            _ => panic!("Wrong variant"),
80        }
81    }
82
83    #[test]
84    fn test_download_event_completed() {
85        let event = DownloadEvent::Completed {
86            download_id: 42,
87            item_id: "song456".to_string(),
88            file_path: "/path/to/file.mp3".to_string(),
89        };
90
91        let json = serde_json::to_string(&event).unwrap();
92        assert!(json.contains("\"type\":\"completed\""));
93        // Verify camelCase field names
94        assert!(
95            json.contains("\"downloadId\":42"),
96            "Expected downloadId (camelCase), got: {}",
97            json
98        );
99        assert!(
100            json.contains("\"itemId\":\"song456\""),
101            "Expected itemId (camelCase), got: {}",
102            json
103        );
104        assert!(
105            json.contains("\"filePath\":"),
106            "Expected filePath (camelCase), got: {}",
107            json
108        );
109
110        // Verify roundtrip
111        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();
112        match deserialized {
113            DownloadEvent::Completed { file_path, .. } => {
114                assert_eq!(file_path, "/path/to/file.mp3");
115            }
116            _ => panic!("Wrong variant"),
117        }
118    }
119
120    #[test]
121    fn test_download_event_failed() {
122        let event = DownloadEvent::Failed {
123            download_id: 10,
124            item_id: "failed_item".to_string(),
125            error: "Network timeout".to_string(),
126        };
127
128        let json = serde_json::to_string(&event).unwrap();
129        assert!(json.contains("\"type\":\"failed\""));
130
131        // Verify roundtrip
132        let deserialized: DownloadEvent = serde_json::from_str(&json).unwrap();
133        match deserialized {
134            DownloadEvent::Failed { error, .. } => {
135                assert_eq!(error, "Network timeout");
136            }
137            _ => panic!("Wrong variant"),
138        }
139    }
140}