1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub enum ErrorCode {
6 Ddp1001InvalidFrame,
7 Ddp1002UnsupportedVersion,
8 Ddp1003UnknownCriticalExtension,
9 Ddp1004UnsupportedHash,
10 Ddp1005BadIdentifier,
11 Ddp1006LimitExceeded,
12 Ddp1007Expired,
13 Ddp1008NotRecipient,
14 Ddp1009Sealed,
15 Dds2001StoreFull,
16 Dds2002CorruptChunk,
17 Dds2003MissingChunk,
18 Dds2004CorruptMetadata,
19 Dda3001AuthFailed,
20 Dda3002Replay,
21 Ddr4001RouteUnavailable,
22 Ddr4002ReplicationExhausted,
23 Ddi5001UnknownContact,
24 Ddc6001Crypto,
25 Ddi7001Io,
26 Ddx0000Internal,
27}
28
29impl ErrorCode {
30 pub fn as_str(self) -> &'static str {
31 match self {
32 Self::Ddp1001InvalidFrame => "DDP1001_INVALID_FRAME",
33 Self::Ddp1002UnsupportedVersion => "DDP1002_UNSUPPORTED_VERSION",
34 Self::Ddp1003UnknownCriticalExtension => "DDP1003_UNKNOWN_CRITICAL_EXTENSION",
35 Self::Ddp1004UnsupportedHash => "DDP1004_UNSUPPORTED_HASH",
36 Self::Ddp1005BadIdentifier => "DDP1005_BAD_IDENTIFIER",
37 Self::Ddp1006LimitExceeded => "DDP1006_LIMIT_EXCEEDED",
38 Self::Ddp1007Expired => "DDP1007_EXPIRED",
39 Self::Ddp1008NotRecipient => "DDP1008_NOT_RECIPIENT",
40 Self::Ddp1009Sealed => "DDP1009_SEALED",
41 Self::Dds2001StoreFull => "DDS2001_STORE_FULL",
42 Self::Dds2002CorruptChunk => "DDS2002_CORRUPT_CHUNK",
43 Self::Dds2003MissingChunk => "DDS2003_MISSING_CHUNK",
44 Self::Dds2004CorruptMetadata => "DDS2004_CORRUPT_METADATA",
45 Self::Dda3001AuthFailed => "DDA3001_AUTH_FAILED",
46 Self::Dda3002Replay => "DDA3002_REPLAY",
47 Self::Ddr4001RouteUnavailable => "DDR4001_ROUTE_UNAVAILABLE",
48 Self::Ddr4002ReplicationExhausted => "DDR4002_REPLICATION_EXHAUSTED",
49 Self::Ddi5001UnknownContact => "DDI5001_UNKNOWN_CONTACT",
50 Self::Ddc6001Crypto => "DDC6001_CRYPTO",
51 Self::Ddi7001Io => "DDI7001_IO",
52 Self::Ddx0000Internal => "DDX0000_INTERNAL",
53 }
54 }
55
56 pub fn category(self) -> &'static str {
57 match self {
58 Self::Ddp1001InvalidFrame
59 | Self::Ddp1002UnsupportedVersion
60 | Self::Ddp1003UnknownCriticalExtension
61 | Self::Ddp1004UnsupportedHash
62 | Self::Ddp1005BadIdentifier
63 | Self::Ddp1006LimitExceeded
64 | Self::Ddp1007Expired
65 | Self::Ddp1008NotRecipient
66 | Self::Ddp1009Sealed => "protocol",
67 Self::Dds2001StoreFull
68 | Self::Dds2002CorruptChunk
69 | Self::Dds2003MissingChunk
70 | Self::Dds2004CorruptMetadata => "store",
71 Self::Dda3001AuthFailed | Self::Dda3002Replay => "auth",
72 Self::Ddr4001RouteUnavailable | Self::Ddr4002ReplicationExhausted => "routing",
73 Self::Ddi5001UnknownContact => "identity",
74 Self::Ddc6001Crypto => "crypto",
75 Self::Ddi7001Io => "io",
76 Self::Ddx0000Internal => "internal",
77 }
78 }
79
80 pub fn retryable(self) -> bool {
81 matches!(
82 self,
83 Self::Dds2001StoreFull | Self::Ddr4001RouteUnavailable | Self::Ddi7001Io
84 )
85 }
86}
87
88impl fmt::Display for ErrorCode {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 f.write_str(self.as_str())
91 }
92}
93
94#[derive(Debug, thiserror::Error)]
95pub enum DdError {
96 #[error("{code}: {message}")]
97 Coded {
98 code: ErrorCode,
99 message: String,
100 context: Option<String>,
101 },
102 #[error(transparent)]
103 Io(#[from] std::io::Error),
104}
105
106impl DdError {
107 pub fn protocol(code: ErrorCode, message: impl Into<String>) -> Self {
108 Self::Coded {
109 code,
110 message: message.into(),
111 context: None,
112 }
113 }
114
115 pub fn with_context(mut self, ctx: impl Into<String>) -> Self {
116 if let Self::Coded { context, .. } = &mut self {
117 *context = Some(ctx.into());
118 }
119 self
120 }
121
122 pub fn code(&self) -> ErrorCode {
123 match self {
124 Self::Coded { code, .. } => *code,
125 Self::Io(_) => ErrorCode::Ddi7001Io,
126 }
127 }
128
129 pub fn retryable(&self) -> bool {
130 self.code().retryable()
131 }
132
133 pub fn crypto(msg: impl Into<String>) -> Self {
134 Self::protocol(ErrorCode::Ddc6001Crypto, msg)
135 }
136
137 pub fn invalid_frame(msg: impl Into<String>) -> Self {
138 Self::protocol(ErrorCode::Ddp1001InvalidFrame, msg)
139 }
140}