Skip to main content

cloudiful_server/core/
error.rs

1use std::{fmt, path::PathBuf};
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub enum ServerConfigError {
5    MissingListenAddr,
6    MissingCorsOrigins,
7    MissingCorsMethods,
8    InvalidCorsOrigin(String),
9    InvalidCorsMethod(String),
10    MissingTlsCertPath,
11    MissingTlsKeyPath,
12}
13
14impl fmt::Display for ServerConfigError {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        match self {
17            Self::MissingListenAddr => write!(f, "listen_addr must not be empty"),
18            Self::MissingCorsOrigins => {
19                write!(
20                    f,
21                    "restricted CORS configuration requires at least one origin"
22                )
23            }
24            Self::MissingCorsMethods => {
25                write!(
26                    f,
27                    "restricted CORS configuration requires at least one method"
28                )
29            }
30            Self::InvalidCorsOrigin(origin) => {
31                write!(f, "restricted CORS origin is invalid: {origin}")
32            }
33            Self::InvalidCorsMethod(method) => {
34                write!(f, "restricted CORS method is invalid: {method}")
35            }
36            Self::MissingTlsCertPath => write!(f, "TLS configuration requires cert_path"),
37            Self::MissingTlsKeyPath => write!(f, "TLS configuration requires cert_key_path"),
38        }
39    }
40}
41
42impl std::error::Error for ServerConfigError {}
43
44#[derive(Debug)]
45pub enum TlsConfigLoadError {
46    OpenCertificate {
47        path: PathBuf,
48        source: std::io::Error,
49    },
50    ReadCertificates {
51        path: PathBuf,
52        source: std::io::Error,
53    },
54    OpenPrivateKey {
55        path: PathBuf,
56        source: std::io::Error,
57    },
58    ReadPrivateKey {
59        path: PathBuf,
60        source: std::io::Error,
61    },
62    MissingPrivateKey {
63        path: PathBuf,
64    },
65    InvalidConfig {
66        source: rustls::Error,
67    },
68}
69
70impl fmt::Display for TlsConfigLoadError {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            Self::OpenCertificate { path, source } => {
74                write!(
75                    f,
76                    "failed to open TLS certificate at {}: {source}",
77                    path.display()
78                )
79            }
80            Self::ReadCertificates { path, source } => {
81                write!(
82                    f,
83                    "failed to read TLS certificates from {}: {source}",
84                    path.display()
85                )
86            }
87            Self::OpenPrivateKey { path, source } => {
88                write!(
89                    f,
90                    "failed to open TLS private key at {}: {source}",
91                    path.display()
92                )
93            }
94            Self::ReadPrivateKey { path, source } => {
95                write!(
96                    f,
97                    "failed to read TLS private key from {}: {source}",
98                    path.display()
99                )
100            }
101            Self::MissingPrivateKey { path } => {
102                write!(f, "no TLS private key found in {}", path.display())
103            }
104            Self::InvalidConfig { source } => {
105                write!(f, "failed to build TLS server configuration: {source}")
106            }
107        }
108    }
109}
110
111impl std::error::Error for TlsConfigLoadError {
112    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
113        match self {
114            Self::OpenCertificate { source, .. }
115            | Self::ReadCertificates { source, .. }
116            | Self::OpenPrivateKey { source, .. }
117            | Self::ReadPrivateKey { source, .. } => Some(source),
118            Self::InvalidConfig { source } => Some(source),
119            Self::MissingPrivateKey { .. } => None,
120        }
121    }
122}
123
124#[derive(Debug)]
125pub enum ServerError {
126    Config(ServerConfigError),
127    Io(std::io::Error),
128    Tls(TlsConfigLoadError),
129}
130
131impl fmt::Display for ServerError {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        match self {
134            Self::Config(err) => err.fmt(f),
135            Self::Io(err) => err.fmt(f),
136            Self::Tls(err) => err.fmt(f),
137        }
138    }
139}
140
141impl std::error::Error for ServerError {
142    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
143        match self {
144            Self::Config(err) => Some(err),
145            Self::Io(err) => Some(err),
146            Self::Tls(err) => Some(err),
147        }
148    }
149}
150
151impl From<ServerConfigError> for ServerError {
152    fn from(value: ServerConfigError) -> Self {
153        Self::Config(value)
154    }
155}
156
157impl From<std::io::Error> for ServerError {
158    fn from(value: std::io::Error) -> Self {
159        Self::Io(value)
160    }
161}