diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs index 98e131e9d..2b401685c 100644 --- a/bin/reth/src/args/rpc_server_args.rs +++ b/bin/reth/src/args/rpc_server_args.rs @@ -1,6 +1,9 @@ //! clap [Args](clap::Args) for RPC related arguments. -use clap::Args; +use clap::{ + builder::{PossibleValue, TypedValueParser}, + Arg, Args, Command, +}; use futures::FutureExt; use reth_network_api::{NetworkInfo, Peers}; use reth_provider::{ @@ -18,6 +21,7 @@ use reth_rpc_engine_api::{EngineApi, EngineApiServer}; use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; use std::{ + ffi::OsStr, net::{IpAddr, Ipv4Addr, SocketAddr}, path::{Path, PathBuf}, }; @@ -39,8 +43,8 @@ pub struct RpcServerArgs { #[arg(long = "http.port")] pub http_port: Option, - /// Rpc Modules to be configured for http server - #[arg(long = "http.api")] + /// Rpc Modules to be configured for the HTTP server + #[arg(long = "http.api", value_parser = RpcModuleSelectionValueParser::default())] pub http_api: Option, /// Http Corsdomain to allow request from @@ -63,8 +67,8 @@ pub struct RpcServerArgs { #[arg(long = "ws.origins", name = "ws.origins")] pub ws_allowed_origins: Option, - /// Rpc Modules to be configured for Ws server - #[arg(long = "ws.api")] + /// Rpc Modules to be configured for the WS server + #[arg(long = "ws.api", value_parser = RpcModuleSelectionValueParser::default())] pub ws_api: Option, /// Disable the IPC-RPC server @@ -307,6 +311,38 @@ impl RpcServerArgs { } } +/// clap value parser for [RpcModuleSelection]. +#[derive(Clone, Debug, Default)] +#[non_exhaustive] +struct RpcModuleSelectionValueParser; + +impl TypedValueParser for RpcModuleSelectionValueParser { + type Value = RpcModuleSelection; + + fn parse_ref( + &self, + _cmd: &Command, + arg: Option<&Arg>, + value: &OsStr, + ) -> Result { + let val = + value.to_str().ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?; + val.parse::().map_err(|err| { + let arg = arg.map(|a| a.to_string()).unwrap_or_else(|| "...".to_owned()); + let possible_values = RethRpcModule::all_variants().to_vec().join(","); + let msg = format!( + "Invalid value '{val}' for {arg}: {err}.\n [possible values: {possible_values}]" + ); + clap::Error::raw(clap::error::ErrorKind::InvalidValue, msg) + }) + } + + fn possible_values(&self) -> Option + '_>> { + let values = RethRpcModule::all_variants().iter().map(PossibleValue::new); + Some(Box::new(values)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index e73959468..178f7005e 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -535,6 +535,15 @@ pub enum RethRpcModule { Web3, } +// === impl RethRpcModule === + +impl RethRpcModule { + /// Returns all variants of the enum + pub const fn all_variants() -> &'static [&'static str] { + Self::VARIANTS + } +} + impl fmt::Display for RethRpcModule { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad(self.as_ref())