1use core::time::Duration;
6use std::net::SocketAddr;
7
8use anyhow::{Context, Result};
9use serde::{Deserialize, Serialize, de::DeserializeOwned};
10use serde_with::{DurationSeconds, serde_as};
11use tracing::debug;
12
13#[serde_as]
14#[derive(Clone, Debug, Deserialize, Serialize)]
15#[serde(rename_all = "kebab-case")]
16pub struct ProxyConfig {
17 pub network: String,
18 pub listen_address: SocketAddr,
19 pub remote_write: RemoteWriteConfig,
20 pub dynamic_peers: DynamicPeerValidationConfig,
21 pub static_peers: Option<StaticPeerValidationConfig>,
22 pub metrics_address: String,
23 pub histogram_address: String,
24}
25
26#[serde_as]
27#[derive(Clone, Debug, Deserialize, Serialize, Default)]
28#[serde(rename_all = "kebab-case")]
29pub struct RemoteWriteConfig {
30 pub url: String,
33 pub username: String,
35 pub password: String,
36
37 #[serde(default = "pool_max_idle_per_host_default")]
40 pub pool_max_idle_per_host: usize,
41}
42
43#[serde_as]
48#[derive(Clone, Debug, Deserialize, Serialize)]
49#[serde(rename_all = "kebab-case")]
50pub struct DynamicPeerValidationConfig {
51 pub url: String,
53 #[serde_as(as = "DurationSeconds<u64>")]
54 pub interval: Duration,
55 #[serde(default = "hostname_default")]
58 pub hostname: Option<String>,
59
60 pub certificate_file: Option<String>,
63 pub private_key: Option<String>,
66}
67
68#[serde_as]
72#[derive(Clone, Debug, Deserialize, Serialize)]
73#[serde(rename_all = "kebab-case")]
74pub struct StaticPeerValidationConfig {
75 pub pub_keys: Vec<StaticPubKey>,
76}
77
78#[serde_as]
82#[derive(Clone, Debug, Deserialize, Serialize)]
83#[serde(rename_all = "kebab-case")]
84pub struct StaticPubKey {
85 pub name: String,
87 pub peer_id: String,
89}
90
91fn pool_max_idle_per_host_default() -> usize {
93 8
94}
95
96fn hostname_default() -> Option<String> {
98 Some("localhost".to_string())
99}
100
101pub fn load<P: AsRef<std::path::Path>, T: DeserializeOwned + Serialize>(path: P) -> Result<T> {
103 let path = path.as_ref();
104 debug!("Reading config from {:?}", path);
105 Ok(serde_yaml::from_reader(
106 std::fs::File::open(path).context(format!("cannot open {:?}", path))?,
107 )?)
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 #[test]
114 fn config_load() {
115 const TEMPLATE: &str = include_str!("./data/config.yaml");
116
117 let _template: ProxyConfig = serde_yaml::from_str(TEMPLATE).unwrap();
118 }
119}