1use anyhow::{Context, Result};
4use core::time::Duration;
5use serde::{Deserialize, Serialize, de::DeserializeOwned};
6use serde_with::{DurationSeconds, serde_as};
7use std::net::SocketAddr;
8use tracing::debug;
9
10#[serde_as]
11#[derive(Clone, Debug, Deserialize, Serialize)]
12#[serde(rename_all = "kebab-case")]
13pub struct ProxyConfig {
14 pub network: String,
15 pub listen_address: SocketAddr,
16 pub remote_write: RemoteWriteConfig,
17 pub dynamic_peers: DynamicPeerValidationConfig,
18 pub static_peers: Option<StaticPeerValidationConfig>,
19 pub metrics_address: String,
20 pub histogram_address: String,
21}
22
23#[serde_as]
24#[derive(Clone, Debug, Deserialize, Serialize, Default)]
25#[serde(rename_all = "kebab-case")]
26pub struct RemoteWriteConfig {
27 #[serde(default = "remote_write_url")]
30 pub url: String,
31 pub username: String,
33 pub password: String,
34
35 #[serde(default = "pool_max_idle_per_host_default")]
38 pub pool_max_idle_per_host: usize,
39}
40
41#[serde_as]
45#[derive(Clone, Debug, Deserialize, Serialize)]
46#[serde(rename_all = "kebab-case")]
47pub struct DynamicPeerValidationConfig {
48 pub url: String,
50 #[serde_as(as = "DurationSeconds<u64>")]
51 pub interval: Duration,
52 #[serde(default = "hostname_default")]
55 pub hostname: Option<String>,
56
57 pub certificate_file: Option<String>,
60 pub private_key: Option<String>,
63}
64
65#[serde_as]
68#[derive(Clone, Debug, Deserialize, Serialize)]
69#[serde(rename_all = "kebab-case")]
70pub struct StaticPeerValidationConfig {
71 pub pub_keys: Vec<StaticPubKey>,
72}
73
74#[serde_as]
77#[derive(Clone, Debug, Deserialize, Serialize)]
78#[serde(rename_all = "kebab-case")]
79pub struct StaticPubKey {
80 pub name: String,
82 pub peer_id: String,
84}
85
86fn pool_max_idle_per_host_default() -> usize {
88 8
89}
90
91fn hostname_default() -> Option<String> {
93 Some("localhost".to_string())
94}
95
96fn remote_write_url() -> String {
98 "http://metrics-gw.testnet.sui.io/api/v1/push".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}