aquatic_ws/
config.rs

1use std::net::SocketAddr;
2use std::path::PathBuf;
3
4use aquatic_common::{access_list::AccessListConfig, privileges::PrivilegeConfig};
5use serde::Deserialize;
6
7use aquatic_common::cli::LogLevel;
8use aquatic_toml_config::TomlConfig;
9
10/// aquatic_ws configuration
11///
12/// Running behind a reverse proxy is supported, but IPv4 peer requests have
13/// to be proxied to IPv4 requests, and IPv6 requests to IPv6 requests.
14#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
15#[serde(default, deny_unknown_fields)]
16pub struct Config {
17    /// Number of socket workers.
18    ///
19    /// On servers with 1-7 physical cores, using a worker per core is
20    /// recommended. With more cores, using two workers less than the
21    /// number of cores is recommended.
22    ///
23    /// Socket workers receive requests from the socket, parse them and send
24    /// them on to the swarm workers. They then receive responses from the
25    /// swarm workers, encode them and send them back over the socket.
26    pub socket_workers: usize,
27    /// Number of swarm workers.
28    ///
29    /// A single worker is recommended for servers with 1-7 physical cores.
30    /// With more cores, using two workers is recommended.
31    ///
32    /// Swarm workers receive a number of requests from socket workers,
33    /// generate responses and send them back to the socket workers.
34    pub swarm_workers: usize,
35    pub log_level: LogLevel,
36    pub network: NetworkConfig,
37    pub protocol: ProtocolConfig,
38    pub cleaning: CleaningConfig,
39    pub privileges: PrivilegeConfig,
40    /// Access list configuration
41    ///
42    /// The file is read on start and when the program receives `SIGUSR1`. If
43    /// initial parsing fails, the program exits. Later failures result in in
44    /// emitting of an error-level log message, while successful updates of the
45    /// access list result in emitting of an info-level log message.
46    pub access_list: AccessListConfig,
47    #[cfg(feature = "metrics")]
48    pub metrics: MetricsConfig,
49}
50
51impl Default for Config {
52    fn default() -> Self {
53        Self {
54            socket_workers: 1,
55            swarm_workers: 1,
56            log_level: LogLevel::default(),
57            network: NetworkConfig::default(),
58            protocol: ProtocolConfig::default(),
59            cleaning: CleaningConfig::default(),
60            privileges: PrivilegeConfig::default(),
61            access_list: AccessListConfig::default(),
62            #[cfg(feature = "metrics")]
63            metrics: Default::default(),
64        }
65    }
66}
67
68impl aquatic_common::cli::Config for Config {
69    fn get_log_level(&self) -> Option<LogLevel> {
70        Some(self.log_level)
71    }
72}
73
74#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
75#[serde(default, deny_unknown_fields)]
76pub struct NetworkConfig {
77    /// Bind to this address
78    pub address: SocketAddr,
79    /// Only allow access over IPv6
80    pub only_ipv6: bool,
81    /// Maximum number of pending TCP connections
82    pub tcp_backlog: i32,
83
84    /// Enable TLS
85    ///
86    /// The TLS files are read on start and when the program receives `SIGUSR1`.
87    /// If initial parsing fails, the program exits. Later failures result in
88    /// in emitting of an error-level log message, while successful updates
89    /// result in emitting of an info-level log message. Updates only affect
90    /// new connections.
91    pub enable_tls: bool,
92    /// Path to TLS certificate (DER-encoded X.509)
93    pub tls_certificate_path: PathBuf,
94    /// Path to TLS private key (DER-encoded ASN.1 in PKCS#8 or PKCS#1 format)
95    pub tls_private_key_path: PathBuf,
96
97    pub websocket_max_message_size: usize,
98    pub websocket_max_frame_size: usize,
99    pub websocket_write_buffer_size: usize,
100
101    /// Return a HTTP 200 Ok response when receiving GET /health. Can not be
102    /// combined with enable_tls.
103    pub enable_http_health_checks: bool,
104}
105
106impl Default for NetworkConfig {
107    fn default() -> Self {
108        Self {
109            address: SocketAddr::from(([0, 0, 0, 0], 3000)),
110            only_ipv6: false,
111            tcp_backlog: 1024,
112
113            enable_tls: false,
114            tls_certificate_path: "".into(),
115            tls_private_key_path: "".into(),
116
117            websocket_max_message_size: 64 * 1024,
118            websocket_max_frame_size: 16 * 1024,
119            websocket_write_buffer_size: 8 * 1024,
120
121            enable_http_health_checks: false,
122        }
123    }
124}
125
126#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
127#[serde(default, deny_unknown_fields)]
128pub struct ProtocolConfig {
129    /// Maximum number of torrents to accept in scrape request
130    pub max_scrape_torrents: usize,
131    /// Maximum number of offers to accept in announce request
132    pub max_offers: usize,
133    /// Ask peers to announce this often (seconds)
134    pub peer_announce_interval: usize,
135}
136
137impl Default for ProtocolConfig {
138    fn default() -> Self {
139        Self {
140            max_scrape_torrents: 255,
141            max_offers: 10,
142            peer_announce_interval: 120,
143        }
144    }
145}
146
147#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
148#[serde(default, deny_unknown_fields)]
149pub struct CleaningConfig {
150    /// Clean peers this often (seconds)
151    pub torrent_cleaning_interval: u64,
152    /// Remove peers that have not announced for this long (seconds)
153    pub max_peer_age: u32,
154    /// Require that offers are answered to withing this period (seconds)
155    pub max_offer_age: u32,
156    // Clean connections this often (seconds)
157    pub connection_cleaning_interval: u64,
158    /// Close connections if no responses have been sent to them for this long (seconds)
159    pub max_connection_idle: u32,
160    /// After updating TLS certificates, close connections running with
161    /// previous certificates after this long (seconds)
162    ///
163    /// Countdown starts at next connection cleaning.
164    pub close_after_tls_update_grace_period: u32,
165}
166
167impl Default for CleaningConfig {
168    fn default() -> Self {
169        Self {
170            torrent_cleaning_interval: 30,
171            max_peer_age: 180,
172            max_offer_age: 120,
173            max_connection_idle: 180,
174            connection_cleaning_interval: 30,
175            close_after_tls_update_grace_period: 60 * 60 * 60,
176        }
177    }
178}
179
180#[cfg(feature = "metrics")]
181#[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)]
182#[serde(default, deny_unknown_fields)]
183pub struct MetricsConfig {
184    /// Run a prometheus endpoint
185    pub run_prometheus_endpoint: bool,
186    /// Address to run prometheus endpoint on
187    pub prometheus_endpoint_address: SocketAddr,
188    /// Update metrics for torrent count this often (seconds)
189    pub torrent_count_update_interval: u64,
190    /// Serve information on peer clients
191    ///
192    /// Expect a certain CPU hit
193    pub peer_clients: bool,
194    /// Serve information on all peer id prefixes
195    ///
196    /// Requires `peer_clients` to be activated.
197    ///
198    /// Expect a certain CPU hit
199    pub peer_id_prefixes: bool,
200}
201
202#[cfg(feature = "metrics")]
203impl Default for MetricsConfig {
204    fn default() -> Self {
205        Self {
206            run_prometheus_endpoint: false,
207            prometheus_endpoint_address: SocketAddr::from(([0, 0, 0, 0], 9000)),
208            torrent_count_update_interval: 10,
209            peer_clients: false,
210            peer_id_prefixes: false,
211        }
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::Config;
218
219    ::aquatic_toml_config::gen_serialize_deserialize_test!(Config);
220}