1use crate::EthRpcModule;
30use std::{
31 collections::HashSet,
32 io::{self, ErrorKind},
33 net::SocketAddr,
34};
35
36#[derive(Debug, PartialEq, Eq, Copy, Clone)]
38pub enum ServerKind {
39 Http(SocketAddr),
41 WS(SocketAddr),
43 WsHttp(SocketAddr),
45 Auth(SocketAddr),
47}
48
49impl ServerKind {
50 pub const fn flags(&self) -> &'static str {
52 match self {
53 Self::Http(_) => "--http.port",
54 Self::WS(_) => "--ws.port",
55 Self::WsHttp(_) => "--ws.port and --http.port",
56 Self::Auth(_) => "--authrpc.port",
57 }
58 }
59}
60
61impl std::fmt::Display for ServerKind {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 match self {
64 Self::Http(addr) => write!(f, "{addr} (HTTP-RPC server)"),
65 Self::WS(addr) => write!(f, "{addr} (WS-RPC server)"),
66 Self::WsHttp(addr) => write!(f, "{addr} (WS-HTTP-RPC server)"),
67 Self::Auth(addr) => write!(f, "{addr} (AUTH server)"),
68 }
69 }
70}
71
72#[derive(Debug, thiserror::Error)]
74pub enum RpcError {
75 #[error("Failed to start {kind} server: {error}")]
77 ServerError {
78 kind: ServerKind,
80 error: io::Error,
82 },
83 #[error("address {kind} is already in use (os error 98). Choose a different port using {}", kind.flags())]
85 AddressAlreadyInUse {
86 kind: ServerKind,
88 error: io::Error,
90 },
91 #[error(transparent)]
97 WsHttpSamePortError(#[from] WsHttpSamePortError),
98 #[error("{0}")]
103 Custom(String),
104}
105
106impl RpcError {
107 pub fn server_error(io_error: io::Error, kind: ServerKind) -> Self {
109 if io_error.kind() == ErrorKind::AddrInUse {
110 return Self::AddressAlreadyInUse {
111 kind,
112 error: io_error,
113 };
114 }
115 Self::ServerError {
116 kind,
117 error: io_error,
118 }
119 }
120}
121
122#[derive(Debug)]
124pub struct ConflictingModules {
125 pub overlap: HashSet<EthRpcModule>,
127 pub http_not_ws: HashSet<EthRpcModule>,
129 pub ws_not_http: HashSet<EthRpcModule>,
131}
132
133impl std::fmt::Display for ConflictingModules {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 write!(
136 f,
137 "different API modules for HTTP and WS on the same port is currently not supported: \
138 Overlap: {:?}, \
139 HTTP modules not present in WS: {:?} \
140 WS modules not present in HTTP: {:?}
141 ",
142 self.overlap, self.http_not_ws, self.ws_not_http
143 )
144 }
145}
146
147#[derive(Debug, thiserror::Error)]
149pub enum WsHttpSamePortError {
150 #[error(
153 "CORS domains for HTTP and WS are different, but they are on the same port: \
154 HTTP: {http_cors_domains:?}, WS: {ws_cors_domains:?}"
155 )]
156 ConflictingCorsDomains {
157 http_cors_domains: Option<String>,
159 ws_cors_domains: Option<String>,
161 },
162 #[error("{0}")]
164 ConflictingModules(Box<ConflictingModules>),
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use std::net::{Ipv4Addr, SocketAddrV4};
171 #[test]
172 fn test_address_in_use_message() {
173 let addr = SocketAddr::V4(SocketAddrV4::new(
174 Ipv4Addr::new(127, 0, 0, 1),
175 1234,
176 ));
177 let kinds = [
178 ServerKind::Http(addr),
179 ServerKind::WS(addr),
180 ServerKind::WsHttp(addr),
181 ServerKind::Auth(addr),
182 ];
183
184 for kind in &kinds {
185 let err = RpcError::AddressAlreadyInUse {
186 kind: *kind,
187 error: io::Error::from(ErrorKind::AddrInUse),
188 };
189
190 assert!(err.to_string().contains(kind.flags()));
191 }
192 }
193}