diff --git a/crates/ptth_relay/src/config.rs b/crates/ptth_relay/src/config.rs index b59120a..451d130 100644 --- a/crates/ptth_relay/src/config.rs +++ b/crates/ptth_relay/src/config.rs @@ -4,7 +4,9 @@ use std::{ collections::HashMap, convert::{TryFrom}, + net::IpAddr, path::Path, + str::FromStr, }; use crate::{ @@ -90,6 +92,7 @@ pub mod file { #[serde (flatten)] pub iso: Isomorphic, + pub address: Option , pub port: Option , pub servers: Option >, @@ -102,16 +105,29 @@ pub mod file { /// Config fields as they are used at runtime -#[derive (Default)] pub struct Config { pub iso: file::Isomorphic, + pub address: IpAddr, pub port: Option , pub servers: HashMap , pub scraper_keys: HashMap >, pub news_url: Option , } +impl Default for Config { + fn default () -> Self { + Self { + iso: Default::default (), + address: IpAddr::from ([0, 0, 0, 0]), + port: None, + servers: Default::default (), + scraper_keys: Default::default (), + news_url: None, + } + } +} + impl TryFrom for Config { type Error = ConfigError; @@ -131,6 +147,7 @@ impl TryFrom for Config { Ok (Self { iso: f.iso, + address: parse_address (f.address.as_ref ().map (|s| &s[..]))?, port: f.port, servers, scraper_keys, @@ -139,6 +156,14 @@ impl TryFrom for Config { } } +fn parse_address (s: Option <&str>) -> Result { + Ok (s + .map (|s| IpAddr::from_str (s)) + .transpose ().map_err (|_| ConfigError::BadServerAddress)? + .unwrap_or (IpAddr::from ([0, 0, 0, 0])) + ) +} + impl Config { pub async fn from_file (path: &Path) -> Result { let config_s = tokio::fs::read_to_string (path).await?; @@ -147,3 +172,23 @@ impl Config { Self::try_from (new_config) } } + +#[cfg (test)] +mod tests { + use super::*; + + #[test] + fn ip_address () { + for (input, expected) in vec! [ + (None, Some (IpAddr::from ([0, 0, 0, 0]))), + (Some ("bogus"), None), + (Some ("0.0.0.0"), Some (IpAddr::from ([0, 0, 0, 0]))), + (Some ("0"), None), + (Some ("127.0.0.1"), Some (IpAddr::from ([127, 0, 0, 1]))), + (Some ("10.0.0.1"), Some (IpAddr::from ([10, 0, 0, 1]))), + ].into_iter () { + let actual = parse_address (input).ok (); + assert_eq! (actual, expected); + } + } +} diff --git a/crates/ptth_relay/src/errors.rs b/crates/ptth_relay/src/errors.rs index 14af9e0..4fa2d8a 100644 --- a/crates/ptth_relay/src/errors.rs +++ b/crates/ptth_relay/src/errors.rs @@ -17,6 +17,9 @@ pub enum ConfigError { #[error ("tripcode not 32 bytes after decoding")] TripcodeBadLength, + #[error ("Bad server address")] + BadServerAddress, + #[error ("unknown config error")] Unknown, } diff --git a/crates/ptth_relay/src/lib.rs b/crates/ptth_relay/src/lib.rs index 7610bda..8a88715 100644 --- a/crates/ptth_relay/src/lib.rs +++ b/crates/ptth_relay/src/lib.rs @@ -683,16 +683,22 @@ pub async fn run_relay ( } }); - let addr = SocketAddr::from (( - [0, 0, 0, 0], - state.config.read ().await.port.unwrap_or (4000), - )); + let addr = { + let guard = state.config.read ().await; + + SocketAddr::from (( + guard.address, + guard.port.unwrap_or (4000), + )) + }; let server = Server::bind (&addr) .serve (make_svc); state.audit_log.push (AuditEvent::new (AuditData::RelayStart)).await; + trace! ("Serving relay on {:?}", addr); + server.with_graceful_shutdown (async { use ShuttingDownError::ShuttingDown; diff --git a/crates/ptth_relay/src/relay_state.rs b/crates/ptth_relay/src/relay_state.rs index c1d7c2f..cae2174 100644 --- a/crates/ptth_relay/src/relay_state.rs +++ b/crates/ptth_relay/src/relay_state.rs @@ -200,6 +200,11 @@ impl Builder { Relay::try_from (self.config) } + pub fn address (mut self, addr: std::net::IpAddr) -> Self { + self.config.address = addr; + self + } + pub fn enable_scraper_api (mut self, b: bool) -> Self { self.config.iso.enable_scraper_api = b; self