reth_node_ethstats/credentials.rs
1use crate::error::EthStatsError;
2use std::str::FromStr;
3
4/// Credentials for connecting to an `EthStats` server
5///
6/// Contains the node identifier, authentication secret, and server host
7/// information needed to establish a connection with the `EthStats` service.
8#[derive(Debug, Clone)]
9pub(crate) struct EthstatsCredentials {
10 /// Unique identifier for this node in the `EthStats` network
11 pub node_id: String,
12 /// Authentication secret for the `EthStats` server
13 pub secret: String,
14 /// Host address of the `EthStats` server
15 pub host: String,
16 /// Whether to use secure `WebSocket` (`WSS`) connection
17 pub use_tls: bool,
18}
19
20impl FromStr for EthstatsCredentials {
21 type Err = EthStatsError;
22
23 /// Parse credentials from a string in the format "`node_id:secret@host`" or
24 /// "`node_id:secret@wss://host`"
25 ///
26 /// Supports the following formats:
27 /// - `node_id:secret@host` - Uses plain `WebSocket` (`ws://`)
28 /// - `node_id:secret@ws://host` - Explicitly use plain `WebSocket`
29 /// - `node_id:secret@wss://host` - Use secure `WebSocket` (`WSS`)
30 ///
31 /// # Arguments
32 /// * `s` - String containing credentials
33 ///
34 /// # Returns
35 /// * `Ok(EthstatsCredentials)` - Successfully parsed credentials
36 /// * `Err(EthStatsError::InvalidUrl)` - Invalid format or missing separators
37 fn from_str(s: &str) -> Result<Self, Self::Err> {
38 let parts: Vec<&str> = s.split('@').collect();
39 if parts.len() != 2 {
40 return Err(EthStatsError::InvalidUrl("Missing '@' separator".to_string()));
41 }
42 let creds = parts[0];
43 let mut host = parts[1].to_string();
44 let creds_parts: Vec<&str> = creds.split(':').collect();
45 if creds_parts.len() != 2 {
46 return Err(EthStatsError::InvalidUrl(
47 "Missing ':' separator in credentials".to_string(),
48 ));
49 }
50 let node_id = creds_parts[0].to_string();
51 let secret = creds_parts[1].to_string();
52
53 // Detect and strip protocol prefix if present
54 let mut use_tls = false;
55 if let Some(stripped) = host.strip_prefix("wss://") {
56 use_tls = true;
57 host = stripped.to_string();
58 } else if let Some(stripped) = host.strip_prefix("ws://") {
59 use_tls = false;
60 host = stripped.to_string();
61 }
62
63 Ok(Self { node_id, secret, host, use_tls })
64 }
65}