switchgear_service/components/pool/
error.rs

1use crate::api::service::{HasServiceErrorSource, ServiceErrorSource};
2use std::borrow::Cow;
3use std::fmt::{Display, Formatter};
4use thiserror::Error;
5use tonic::{transport, Code, Status};
6
7#[derive(Error, Debug)]
8pub enum LnPoolErrorSourceKind {
9    #[error("CLN tonic gRPC error: {0}")]
10    TonicError(Status),
11    #[error("CLN transport connection error: {0}")]
12    TransportError(transport::Error),
13    #[error("invalid configuration for: {0}")]
14    InvalidConfiguration(String),
15    #[error("invalid credentials for {0}")]
16    InvalidCredentials(String),
17    #[error("memory error: {0}")]
18    MemoryError(String),
19}
20
21#[derive(Error, Debug)]
22pub struct LnPoolError {
23    context: Cow<'static, str>,
24    #[source]
25    source: LnPoolErrorSourceKind,
26    esource: ServiceErrorSource,
27}
28
29impl Display for LnPoolError {
30    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31        write!(
32            f,
33            "LnPoolError: while {}: {}",
34            self.context.as_ref(),
35            self.source
36        )
37    }
38}
39
40impl LnPoolError {
41    fn new<C: Into<Cow<'static, str>>>(
42        source: LnPoolErrorSourceKind,
43        esource: ServiceErrorSource,
44        context: C,
45    ) -> Self {
46        Self {
47            context: context.into(),
48            source,
49            esource,
50        }
51    }
52
53    pub fn from_invalid_configuration<C: Into<Cow<'static, str>>>(
54        source: C,
55        esource: ServiceErrorSource,
56        context: C,
57    ) -> Self {
58        Self::new(
59            LnPoolErrorSourceKind::InvalidConfiguration(source.into().to_string()),
60            esource,
61            context.into(),
62        )
63    }
64
65    pub fn from_invalid_credentials<C: Into<Cow<'static, str>>>(
66        source: C,
67        esource: ServiceErrorSource,
68        context: C,
69    ) -> Self {
70        Self::new(
71            LnPoolErrorSourceKind::InvalidCredentials(source.into().to_string()),
72            esource,
73            context.into(),
74        )
75    }
76
77    pub fn from_tonic_error<C: Into<Cow<'static, str>>>(source: Status, context: C) -> Self {
78        let esource = Self::from_tonic_code(source.code());
79        Self::new(LnPoolErrorSourceKind::TonicError(source), esource, context)
80    }
81
82    pub fn from_transport_error<C: Into<Cow<'static, str>>>(
83        source: transport::Error,
84        esource: ServiceErrorSource,
85        context: C,
86    ) -> Self {
87        Self::new(
88            LnPoolErrorSourceKind::TransportError(source),
89            esource,
90            context,
91        )
92    }
93
94    pub fn from_memory_error<C: Into<Cow<'static, str>>>(source: String, context: C) -> Self {
95        Self::new(
96            LnPoolErrorSourceKind::MemoryError(source),
97            ServiceErrorSource::Internal,
98            context,
99        )
100    }
101
102    pub fn context(&self) -> &str {
103        self.context.as_ref()
104    }
105
106    pub fn source(&self) -> &LnPoolErrorSourceKind {
107        &self.source
108    }
109
110    pub fn esource(&self) -> ServiceErrorSource {
111        self.esource
112    }
113
114    fn from_tonic_code(code: Code) -> ServiceErrorSource {
115        match code {
116            Code::InvalidArgument | Code::OutOfRange | Code::AlreadyExists => {
117                ServiceErrorSource::Downstream
118            }
119
120            _ => ServiceErrorSource::Upstream,
121        }
122    }
123}
124
125impl HasServiceErrorSource for LnPoolError {
126    fn get_service_error_source(&self) -> ServiceErrorSource {
127        self.esource
128    }
129}