diff --git a/src/config/router.rs b/src/config/router.rs index cfee4f8..9247cc3 100644 --- a/src/config/router.rs +++ b/src/config/router.rs @@ -58,11 +58,10 @@ impl Router for RouterConfig { .or(self.default.as_ref()) .ok_or(RouterError::NoServer)?; - let address: SocketAddr = match route.ip { - RouteType::Simple(address) => address.into(), - RouteType::Balanced(ref list) => { - let hash = client.hash(); - list.get(hash as usize) + let address: SocketAddr = match &route.ip { + RouteType::Simple(addr) => addr.resolve().ok_or(RouterError::Unavailable)?, + RouteType::Balanced(list) => { + list.get(client.hash() as usize).ok_or(RouterError::Unavailable)? } }; diff --git a/src/config/router/balancer.rs b/src/config/router/balancer.rs index 770a01b..b2e2491 100644 --- a/src/config/router/balancer.rs +++ b/src/config/router/balancer.rs @@ -22,7 +22,7 @@ pub struct Balanced { // } impl Balanced { - pub(super) fn get(&self, n: usize) -> SocketAddr { - self.servers[n & self.servers.len()].into() + pub(super) fn get(&self, n: usize) -> Option { + self.servers[n % self.servers.len()].resolve() } } diff --git a/src/config/router/resolver.rs b/src/config/router/resolver.rs index b66a16a..8fd3b0d 100644 --- a/src/config/router/resolver.rs +++ b/src/config/router/resolver.rs @@ -2,26 +2,26 @@ use std::net::{SocketAddr, ToSocketAddrs}; use serde::{Deserialize, Deserializer}; -#[derive(Deserialize, Debug, Clone, Copy)] -pub(super) struct ResolvableAddr(#[serde(deserialize_with = "resolve_hostname")] SocketAddr); +#[derive(Deserialize, Debug, Clone)] +pub(super) struct ResolvableAddr(#[serde(deserialize_with = "parse_addr_string")] String); -fn resolve_hostname<'de, D>(deserializer: D) -> Result +fn parse_addr_string<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { use serde::de::Error; - let inner = ::deserialize(deserializer)?; - - let mut addr = inner - .to_socket_addrs() - .map_err(|err| Error::custom(format!("invalid hostname format: {err}")))?; - - addr.next().ok_or_else(|| Error::missing_field("address")) + let s = String::deserialize(deserializer)?; + if !s.contains(':') { + return Err(Error::custom(format!( + "invalid socket address syntax, expected host:port: {s}" + ))); + } + Ok(s) } -impl From for SocketAddr { - fn from(addr: ResolvableAddr) -> Self { - addr.0 +impl ResolvableAddr { + pub fn resolve(&self) -> Option { + self.0.to_socket_addrs().ok()?.next() } } diff --git a/src/server/router.rs b/src/server/router.rs index 4aae8e7..ad2849b 100644 --- a/src/server/router.rs +++ b/src/server/router.rs @@ -7,6 +7,9 @@ use thiserror::Error; pub enum RouterError { #[error("no server with such hostname has been found")] NoServer, + + #[error("backend server is currently unavailable")] + Unavailable, } // #[async_trait::async_trait]