strike48_connector/
error.rs1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, ConnectorError>;
5
6#[derive(Error, Debug)]
8pub enum ConnectorError {
9 #[error("Connection error: {0}")]
10 ConnectionError(String),
11
12 #[error("Not connected to Strike48 server")]
13 NotConnected,
14
15 #[error("Connector not registered")]
16 NotRegistered,
17
18 #[error("Stream error: {0}")]
19 StreamError(String),
20
21 #[error("Registration error: {0}")]
22 RegistrationError(String),
23
24 #[error("Invalid configuration: {0}")]
25 InvalidConfig(String),
26
27 #[error("Serialization error: {0}")]
28 SerializationError(String),
29
30 #[error("Deserialization error: {0}")]
31 DeserializationError(String),
32
33 #[error("Unsupported encoding: {0}")]
34 UnsupportedEncoding(String),
35
36 #[error("Timeout: {0}")]
37 Timeout(String),
38
39 #[error("Invoke failed: {0}")]
40 InvokeFailed(String),
41
42 #[error("Connector not running")]
43 NotRunning,
44
45 #[error("Already running")]
46 AlreadyRunning,
47
48 #[error("IO error: {0}")]
49 Io(#[source] Box<std::io::Error>),
50
51 #[error("gRPC error: {0}")]
52 Grpc(#[source] Box<tonic::Status>),
53
54 #[error("JSON error: {0}")]
55 Json(#[source] Box<serde_json::Error>),
56
57 #[error("Not implemented: {0}")]
58 NotImplemented(String),
59
60 #[error("Other error: {0}")]
61 Other(String),
62}
63
64impl From<std::io::Error> for ConnectorError {
65 fn from(e: std::io::Error) -> Self {
66 ConnectorError::Io(Box::new(e))
67 }
68}
69
70impl From<tonic::Status> for ConnectorError {
71 fn from(e: tonic::Status) -> Self {
72 ConnectorError::Grpc(Box::new(e))
73 }
74}
75
76impl From<serde_json::Error> for ConnectorError {
77 fn from(e: serde_json::Error) -> Self {
78 ConnectorError::Json(Box::new(e))
79 }
80}
81
82impl ConnectorError {
83 pub fn code(&self) -> &'static str {
84 match self {
85 ConnectorError::ConnectionError(_) => "CONNECTION_ERROR",
86 ConnectorError::NotConnected => "NOT_CONNECTED",
87 ConnectorError::NotRegistered => "NOT_REGISTERED",
88 ConnectorError::StreamError(_) => "STREAM_ERROR",
89 ConnectorError::RegistrationError(_) => "REGISTRATION_ERROR",
90 ConnectorError::InvalidConfig(_) => "INVALID_CONFIG",
91 ConnectorError::SerializationError(_) => "SERIALIZATION_ERROR",
92 ConnectorError::DeserializationError(_) => "DESERIALIZATION_ERROR",
93 ConnectorError::UnsupportedEncoding(_) => "UNSUPPORTED_ENCODING",
94 ConnectorError::Timeout(_) => "TIMEOUT",
95 ConnectorError::InvokeFailed(_) => "INVOKE_FAILED",
96 ConnectorError::NotRunning => "NOT_RUNNING",
97 ConnectorError::AlreadyRunning => "ALREADY_RUNNING",
98 ConnectorError::Io(_) => "IO_ERROR",
99 ConnectorError::Grpc(_) => "GRPC_ERROR",
100 ConnectorError::Json(_) => "JSON_ERROR",
101 ConnectorError::NotImplemented(_) => "NOT_IMPLEMENTED",
102 ConnectorError::Other(_) => "OTHER",
103 }
104 }
105
106 pub fn is_recoverable(&self) -> bool {
112 match self {
113 ConnectorError::ConnectionError(_)
114 | ConnectorError::NotConnected
115 | ConnectorError::StreamError(_)
116 | ConnectorError::Timeout(_)
117 | ConnectorError::Io(_)
118 | ConnectorError::Grpc(_) => true,
119
120 ConnectorError::RegistrationError(msg) => {
121 let lower = msg.to_lowercase();
122 let permanent = lower.contains("not enabled")
124 || lower.contains("not supported")
125 || lower.contains("disabled")
126 || lower.contains("invalid connector")
127 || lower.contains("permission denied")
128 || lower.contains("not allowed");
129 !permanent
134 }
135
136 ConnectorError::InvalidConfig(_)
137 | ConnectorError::NotRegistered
138 | ConnectorError::SerializationError(_)
139 | ConnectorError::DeserializationError(_)
140 | ConnectorError::UnsupportedEncoding(_)
141 | ConnectorError::NotImplemented(_)
142 | ConnectorError::NotRunning
143 | ConnectorError::AlreadyRunning
144 | ConnectorError::Json(_) => false,
145
146 ConnectorError::InvokeFailed(_) | ConnectorError::Other(_) => true,
147 }
148 }
149}