reth_rpc_builder/
error.rs
1use crate::{cors::CorsDomainError, RethRpcModule};
2use reth_ipc::server::IpcServerStartError;
3use std::{
4 collections::HashSet,
5 io::{self, ErrorKind},
6 net::SocketAddr,
7};
8
9#[derive(Debug, PartialEq, Eq, Copy, Clone)]
11pub enum ServerKind {
12 Http(SocketAddr),
14 WS(SocketAddr),
16 WsHttp(SocketAddr),
18 Auth(SocketAddr),
20}
21
22impl ServerKind {
23 pub const fn flags(&self) -> &'static str {
25 match self {
26 Self::Http(_) => "--http.port",
27 Self::WS(_) => "--ws.port",
28 Self::WsHttp(_) => "--ws.port and --http.port",
29 Self::Auth(_) => "--authrpc.port",
30 }
31 }
32}
33
34impl std::fmt::Display for ServerKind {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::Http(addr) => write!(f, "{addr} (HTTP-RPC server)"),
38 Self::WS(addr) => write!(f, "{addr} (WS-RPC server)"),
39 Self::WsHttp(addr) => write!(f, "{addr} (WS-HTTP-RPC server)"),
40 Self::Auth(addr) => write!(f, "{addr} (AUTH server)"),
41 }
42 }
43}
44
45#[derive(Debug, thiserror::Error)]
47pub enum RpcError {
48 #[error("Failed to start {kind} server: {error}")]
50 ServerError {
51 kind: ServerKind,
53 error: io::Error,
55 },
56 #[error("address {kind} is already in use (os error 98). Choose a different port using {}", kind.flags())]
58 AddressAlreadyInUse {
59 kind: ServerKind,
61 error: io::Error,
63 },
64 #[error(transparent)]
66 Cors(#[from] CorsDomainError),
67 #[error(transparent)]
69 WsHttpSamePortError(#[from] WsHttpSamePortError),
70 #[error(transparent)]
72 IpcServerError(#[from] IpcServerStartError),
73 #[error("{0}")]
75 Custom(String),
76}
77
78impl RpcError {
79 pub fn server_error(io_error: io::Error, kind: ServerKind) -> Self {
81 if io_error.kind() == ErrorKind::AddrInUse {
82 return Self::AddressAlreadyInUse { kind, error: io_error }
83 }
84 Self::ServerError { kind, error: io_error }
85 }
86}
87
88#[derive(Debug)]
90pub struct ConflictingModules {
91 pub overlap: HashSet<RethRpcModule>,
93 pub http_not_ws: HashSet<RethRpcModule>,
95 pub ws_not_http: HashSet<RethRpcModule>,
97}
98
99impl std::fmt::Display for ConflictingModules {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(
102 f,
103 "different API modules for HTTP and WS on the same port is currently not supported: \
104 Overlap: {:?}, \
105 HTTP modules not present in WS: {:?} \
106 WS modules not present in HTTP: {:?}
107 ",
108 self.overlap, self.http_not_ws, self.ws_not_http
109 )
110 }
111}
112
113#[derive(Debug, thiserror::Error)]
115pub enum WsHttpSamePortError {
116 #[error(
118 "CORS domains for HTTP and WS are different, but they are on the same port: \
119 HTTP: {http_cors_domains:?}, WS: {ws_cors_domains:?}"
120 )]
121 ConflictingCorsDomains {
122 http_cors_domains: Option<String>,
124 ws_cors_domains: Option<String>,
126 },
127 #[error("{0}")]
129 ConflictingModules(Box<ConflictingModules>),
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use std::net::{Ipv4Addr, SocketAddrV4};
136 #[test]
137 fn test_address_in_use_message() {
138 let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 1234));
139 let kinds = [
140 ServerKind::Http(addr),
141 ServerKind::WS(addr),
142 ServerKind::WsHttp(addr),
143 ServerKind::Auth(addr),
144 ];
145
146 for kind in &kinds {
147 let err = RpcError::AddressAlreadyInUse {
148 kind: *kind,
149 error: io::Error::from(ErrorKind::AddrInUse),
150 };
151
152 assert!(err.to_string().contains(kind.flags()));
153 }
154 }
155}