switchgear_service/components/pool/
error.rs

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