Skip to content
Clone
eba4fd1
88 lines 2.4 KB Rust
use std::net::IpAddr;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct AdminConfig {
pub enabled: Option<bool>,
pub bind_addr: Option<String>,
pub port: Option<u16>,
pub grpc_port: Option<u16>,
#[serde(default, deserialize_with = "string_or_vec")]
pub grpc_trusted_keys: Vec<String>,
pub cors_allow_origins: Vec<String>,
pub cors_allow_credentials: Option<bool>,
}
fn string_or_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrVec {
String(String),
Vec(Vec<String>),
}
Ok(match StringOrVec::deserialize(deserializer)? {
StringOrVec::String(value) => value
.split(',')
.map(str::trim)
.filter(|value| !value.is_empty())
.map(str::to_string)
.collect(),
StringOrVec::Vec(values) => values,
})
}
impl AdminConfig {
pub fn enabled(&self) -> bool {
self.enabled.unwrap_or(true)
}
pub fn bind_addr(&self) -> &str {
self.bind_addr.as_deref().unwrap_or("0.0.0.0")
}
pub fn port(&self) -> u16 {
self.port.unwrap_or(3004)
}
pub fn grpc_port(&self) -> u16 {
self.grpc_port.unwrap_or(3014)
}
pub fn grpc_trusted_keys(&self) -> &[String] {
&self.grpc_trusted_keys
}
pub fn cors_allow_credentials(&self) -> bool {
self.cors_allow_credentials.unwrap_or(false)
}
pub fn is_valid(&self) -> Result<(), String> {
if !self.enabled() {
return Ok(());
}
let bind = self.bind_addr();
if bind.parse::<IpAddr>().is_err() {
return Err(format!("admin.bind_addr is not a valid IP: {bind:?}"));
}
if self.port == Some(0) {
return Err("admin.port must be greater than 0".to_string());
}
if self.grpc_port == Some(0) {
return Err("admin.grpc_port must be greater than 0".to_string());
}
for origin in &self.cors_allow_origins {
if !origin.starts_with("http://") && !origin.starts_with("https://") {
return Err(format!(
"admin.cors_allow_origins entry must be an origin URL: {origin:?}"
));
}
}
Ok(())
}
}