Skip to main content

gosh_dl/protocol/
error.rs

1//! Serializable error type for IPC / RPC boundaries
2//!
3//! [`ProtocolError`] is a simplified, `Serialize`/`Deserialize` error type
4//! designed for use across process boundaries (JSON-RPC, gRPC, WebSocket APIs).
5//! It carries only string messages and hides internal implementation details.
6//!
7//! For direct Rust usage, prefer [`crate::EngineError`] which provides richer
8//! context (error kind enums, retryability flags) for pattern matching.
9//!
10//! Convert with: `let proto_err: ProtocolError = engine_err.into();`
11
12use serde::{Deserialize, Serialize};
13use std::fmt;
14
15/// Protocol-level error returned from engine operations
16///
17/// This is a simplified error type that hides internal engine details
18/// while providing actionable information to consumers.
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub enum ProtocolError {
21    /// Download was not found
22    NotFound {
23        /// The ID that was not found
24        id: String,
25    },
26
27    /// Invalid state for requested operation
28    InvalidState {
29        /// The action that was attempted
30        action: String,
31        /// The current state that prevented the action
32        current_state: String,
33    },
34
35    /// Invalid input provided
36    InvalidInput {
37        /// The field with invalid input
38        field: String,
39        /// Description of what's wrong
40        message: String,
41    },
42
43    /// Network error occurred
44    Network {
45        /// Error description
46        message: String,
47        /// Whether the operation can be retried
48        retryable: bool,
49    },
50
51    /// Storage/filesystem error
52    Storage {
53        /// Error description
54        message: String,
55    },
56
57    /// Engine is shutting down
58    Shutdown,
59
60    /// Internal engine error (opaque to consumer)
61    Internal {
62        /// Error description
63        message: String,
64    },
65}
66
67impl fmt::Display for ProtocolError {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        match self {
70            Self::NotFound { id } => write!(f, "Download not found: {}", id),
71            Self::InvalidState {
72                action,
73                current_state,
74            } => write!(f, "Cannot {} while {}", action, current_state),
75            Self::InvalidInput { field, message } => {
76                write!(f, "Invalid input for '{}': {}", field, message)
77            }
78            Self::Network { message, .. } => write!(f, "Network error: {}", message),
79            Self::Storage { message } => write!(f, "Storage error: {}", message),
80            Self::Shutdown => write!(f, "Engine is shutting down"),
81            Self::Internal { message } => write!(f, "Internal error: {}", message),
82        }
83    }
84}
85
86impl std::error::Error for ProtocolError {}
87
88impl ProtocolError {
89    /// Check if this error is retryable
90    pub fn is_retryable(&self) -> bool {
91        match self {
92            Self::Network { retryable, .. } => *retryable,
93            _ => false,
94        }
95    }
96}
97
98/// Result type for protocol operations
99pub type ProtocolResult<T> = std::result::Result<T, ProtocolError>;