alopex_chirps_file_transfer/
error.rs1use crate::{ChunkIndex, TransferSessionId};
2use thiserror::Error;
3
4#[derive(Debug, Error)]
6pub enum FileTransferError {
7 #[error("session not found: {0}")]
9 SessionNotFound(TransferSessionId),
10 #[error("session already exists: {0}")]
11 SessionAlreadyExists(TransferSessionId),
12 #[error("invalid session state")]
13 InvalidState { expected: String, actual: String },
14
15 #[error("file not found: {0}")]
17 FileNotFound(String),
18 #[error("file already exists: {0}")]
19 FileAlreadyExists(String),
20 #[error("permission denied: {0}")]
21 PermissionDenied(String),
22 #[error("disk full")]
23 DiskFull,
24 #[error("path traversal attack detected: {0}")]
25 PathTraversal(String),
26
27 #[error("chunk checksum mismatch at index {index}")]
29 ChunkChecksumMismatch { index: ChunkIndex },
30 #[error("file hash mismatch")]
31 FileHashMismatch,
32 #[error("transfer timeout")]
33 Timeout,
34 #[error("transfer cancelled")]
35 Cancelled,
36 #[error("max retries exceeded for chunk {index}")]
37 MaxRetriesExceeded { index: ChunkIndex },
38
39 #[error("sync conflict: {path}")]
41 SyncConflict { path: String },
42
43 #[error("io error: {0}")]
45 Io(#[from] std::io::Error),
46 #[error("transport error: {0}")]
47 Transport(String),
48 #[error("peer rejected: {0}")]
49 Rejected(String),
50 #[error("serialization error: {0}")]
51 Serialization(String),
52 #[error("compression error: {0}")]
53 Compression(String),
54 #[error("internal error: {0}")]
55 Internal(String),
56}
57
58impl FileTransferError {
59 pub fn code(&self) -> u32 {
64 match self {
65 FileTransferError::SessionNotFound(_) => 1001,
66 FileTransferError::SessionAlreadyExists(_) => 1002,
67 FileTransferError::InvalidState { .. } => 1003,
68 FileTransferError::FileNotFound(_) => 2001,
69 FileTransferError::FileAlreadyExists(_) => 2002,
70 FileTransferError::PermissionDenied(_) => 2003,
71 FileTransferError::DiskFull => 2004,
72 FileTransferError::PathTraversal(_) => 2005,
73 FileTransferError::ChunkChecksumMismatch { .. } => 3001,
74 FileTransferError::FileHashMismatch => 3002,
75 FileTransferError::Timeout => 3003,
76 FileTransferError::Cancelled => 3004,
77 FileTransferError::MaxRetriesExceeded { .. } => 3005,
78 FileTransferError::SyncConflict { .. } => 4001,
79 FileTransferError::Io(_)
80 | FileTransferError::Transport(_)
81 | FileTransferError::Rejected(_)
82 | FileTransferError::Serialization(_)
83 | FileTransferError::Compression(_)
84 | FileTransferError::Internal(_) => 9001,
85 }
86 }
87
88 pub fn is_recoverable(&self) -> bool {
93 matches!(
94 self,
95 FileTransferError::ChunkChecksumMismatch { .. }
96 | FileTransferError::Timeout
97 | FileTransferError::Transport(_)
98 )
99 }
100}