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>;