switchgear_service/components/pool/
error.rs

1use crate::api::service::{HasServiceErrorSource, ServiceErrorSource};
2use std::borrow::Cow;
3use std::fmt::{Display, Formatter};
4use thiserror::Error;
5
6#[derive(Error, Debug)]
7pub enum LnPoolErrorSourceKind {
8    #[error("CLN tonic gRPC error: {0}")]
9    ClnTonicError(crate::components::pool::cln::grpc::client::tonic::Status),
10    #[error("LND tonic gRPC error: {0}")]
11    LndTonicError(crate::components::pool::lnd::grpc::client::tonic::Status),
12    #[error("CLN transport connection error: {0}")]
13    ClnTransportError(crate::components::pool::cln::grpc::client::tonic::transport::Error),
14    #[error("LND transport connection error: {0}")]
15    LndTransportError(crate::components::pool::lnd::grpc::client::tonic::transport::Error),
16    #[error("LND connection error: {0}")]
17    LndConnectError(fedimint_tonic_lnd::ConnectError),
18    #[error("Generic Lightning pool operation failed")]
19    Generic,
20    #[error("invalid configuration for: {0}")]
21    InvalidConfiguration(String),
22    #[error("invalid credentials for {0}")]
23    InvalidCredentials(String),
24    #[error("invalid endpoint URI: {0}")]
25    InvalidEndpointUri(
26        crate::components::pool::cln::grpc::client::tonic::codegen::http::uri::InvalidUri,
27    ),
28    #[error("operation timed out")]
29    Timeout,
30}
31
32#[derive(Error, Debug)]
33pub struct LnPoolError {
34    context: Cow<'static, str>,
35    #[source]
36    source: LnPoolErrorSourceKind,
37    esource: ServiceErrorSource,
38}
39
40impl Display for LnPoolError {
41    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42        write!(
43            f,
44            "LnPoolError: while {}: {}",
45            self.context.as_ref(),
46            self.source
47        )
48    }
49}
50
51impl LnPoolError {
52    pub fn new<C: Into<Cow<'static, str>>>(
53        source: LnPoolErrorSourceKind,
54        esource: ServiceErrorSource,
55        context: C,
56    ) -> Self {
57        Self {
58            context: context.into(),
59            source,
60            esource,
61        }
62    }
63
64    pub fn from_invalid_configuration<C: Into<Cow<'static, str>>>(
65        source: C,
66        esource: ServiceErrorSource,
67        context: C,
68    ) -> Self {
69        Self::new(
70            LnPoolErrorSourceKind::InvalidConfiguration(source.into().to_string()),
71            esource,
72            context.into(),
73        )
74    }
75
76    pub fn from_invalid_credentials<C: Into<Cow<'static, str>>>(
77        source: C,
78        esource: ServiceErrorSource,
79        context: C,
80    ) -> Self {
81        Self::new(
82            LnPoolErrorSourceKind::InvalidCredentials(source.into().to_string()),
83            esource,
84            context.into(),
85        )
86    }
87
88    pub fn from_cln_invalid_endpoint_uri<C: Into<Cow<'static, str>>>(
89        invalid_uri: crate::components::pool::cln::grpc::client::tonic::codegen::http::uri::InvalidUri,
90        esource: ServiceErrorSource,
91        context: C,
92    ) -> Self {
93        Self::new(
94            LnPoolErrorSourceKind::InvalidEndpointUri(invalid_uri),
95            esource,
96            context.into(),
97        )
98    }
99
100    pub fn from_cln_tonic_error<C: Into<Cow<'static, str>>>(
101        source: crate::components::pool::cln::grpc::client::tonic::Status,
102        context: C,
103    ) -> Self {
104        let esource = Self::from_cln_tonic_code(source.code());
105        Self::new(
106            LnPoolErrorSourceKind::ClnTonicError(source),
107            esource,
108            context,
109        )
110    }
111
112    pub fn from_cln_tonic_error_with_esource<C: Into<Cow<'static, str>>>(
113        source: crate::components::pool::cln::grpc::client::tonic::Status,
114        esource: ServiceErrorSource,
115        context: C,
116    ) -> Self {
117        Self::new(
118            LnPoolErrorSourceKind::ClnTonicError(source),
119            esource,
120            context,
121        )
122    }
123
124    pub fn from_lnd_tonic_error<C: Into<Cow<'static, str>>>(
125        source: crate::components::pool::lnd::grpc::client::tonic::Status,
126        context: C,
127    ) -> Self {
128        let esource = Self::from_lnd_tonic_code(source.code());
129
130        Self::new(
131            LnPoolErrorSourceKind::LndTonicError(source),
132            esource,
133            context,
134        )
135    }
136
137    pub fn from_lnd_tonic_error_with_esource<C: Into<Cow<'static, str>>>(
138        source: crate::components::pool::lnd::grpc::client::tonic::Status,
139        esource: ServiceErrorSource,
140        context: C,
141    ) -> Self {
142        Self::new(
143            LnPoolErrorSourceKind::LndTonicError(source),
144            esource,
145            context,
146        )
147    }
148
149    pub fn from_cln_transport_error<C: Into<Cow<'static, str>>>(
150        source: crate::components::pool::cln::grpc::client::tonic::transport::Error,
151        esource: ServiceErrorSource,
152        context: C,
153    ) -> Self {
154        Self::new(
155            LnPoolErrorSourceKind::ClnTransportError(source),
156            esource,
157            context,
158        )
159    }
160
161    pub fn from_lnd_connect_error<C: Into<Cow<'static, str>>>(
162        source: fedimint_tonic_lnd::ConnectError,
163        esource: ServiceErrorSource,
164        context: C,
165    ) -> Self {
166        Self::new(
167            LnPoolErrorSourceKind::LndConnectError(source),
168            esource,
169            context,
170        )
171    }
172
173    pub fn from_timeout_error<C: Into<Cow<'static, str>>>(
174        esource: ServiceErrorSource,
175        context: C,
176    ) -> Self {
177        Self::new(LnPoolErrorSourceKind::Timeout, esource, context)
178    }
179
180    pub fn context(&self) -> &str {
181        self.context.as_ref()
182    }
183
184    pub fn source(&self) -> &LnPoolErrorSourceKind {
185        &self.source
186    }
187
188    pub fn esource(&self) -> ServiceErrorSource {
189        self.esource
190    }
191
192    pub fn from_cln_tonic_code(
193        code: crate::components::pool::cln::grpc::client::tonic::Code,
194    ) -> ServiceErrorSource {
195        match code {
196            crate::components::pool::cln::grpc::client::tonic::Code::InvalidArgument
197            | crate::components::pool::cln::grpc::client::tonic::Code::OutOfRange => {
198                ServiceErrorSource::Downstream
199            }
200
201            _ => ServiceErrorSource::Upstream,
202        }
203    }
204
205    pub fn from_lnd_tonic_code(
206        code: crate::components::pool::lnd::grpc::client::tonic::Code,
207    ) -> ServiceErrorSource {
208        match code {
209            crate::components::pool::lnd::grpc::client::tonic::Code::OutOfRange
210            | crate::components::pool::lnd::grpc::client::tonic::Code::AlreadyExists => {
211                ServiceErrorSource::Downstream
212            }
213
214            _ => ServiceErrorSource::Upstream,
215        }
216    }
217}
218
219impl HasServiceErrorSource for LnPoolError {
220    fn get_service_error_source(&self) -> ServiceErrorSource {
221        self.esource
222    }
223}