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}