scratchstack_config/service/
mod.rs

1mod iam;
2mod sts;
3
4use {
5    super::TlsConfig,
6    crate::error::ConfigError,
7    serde::Deserialize,
8    std::{
9        fmt::{Debug, Formatter, Result as FmtResult},
10        net::{IpAddr, Ipv6Addr, SocketAddr},
11    },
12    tokio_rustls::rustls::ServerConfig as TlsServerConfig,
13};
14
15pub use self::{
16    iam::{Iam, ResolvedIam},
17    sts::{Sts, ResolvedSts},
18};
19
20/// Configuration for all services.
21#[derive(Debug, Deserialize)]
22pub struct ServiceConfig {
23    pub iam: Option<Iam>,
24    pub sts: Option<Sts>,
25}
26
27const DEFAULT_ADDRESS: IpAddr = IpAddr::V6(Ipv6Addr::LOCALHOST);
28
29const DEFAULT_PARTITION: &str = "aws";
30
31const DEFAULT_THREADS: usize = 1;
32
33/// Base configuration data for a service. This allows for optional fields and references  to files for things like
34/// TLS certificates and keys.
35#[derive(Debug, Deserialize)]
36pub struct BaseServiceConfig {
37    #[serde(default)]
38    pub address: Option<IpAddr>,
39
40    #[serde(default)]
41    pub port: Option<u16>,
42
43    #[serde(default)]
44    pub partition: Option<String>,
45
46    pub region: String,
47
48    #[serde(default)]
49    pub tls: Option<TlsConfig>,
50
51    #[serde(default)]
52    pub threads: Option<usize>,
53}
54
55impl BaseServiceConfig {
56    pub fn resolve(&self, default_port: u16) -> Result<ResolvedBaseServiceConfig, ConfigError> {
57        let address = self.address.unwrap_or(DEFAULT_ADDRESS);
58
59        let port = self.port.unwrap_or(default_port);
60        if port == 0 {
61            return Err(ConfigError::InvalidPort);
62        }
63
64        let partition = self.partition.clone().unwrap_or_else(|| DEFAULT_PARTITION.to_string());
65        if partition.is_empty() {
66            return Err(ConfigError::InvalidPartition);
67        }
68
69        let region = self.region.clone();
70        if region.is_empty() {
71            return Err(ConfigError::InvalidRegion);
72        }
73
74        let threads = self.threads.unwrap_or(DEFAULT_THREADS);
75
76        let tls = match &self.tls {
77            None => None,
78            Some(c) => Some(c.to_server_config()?),
79        };
80
81        Ok(ResolvedBaseServiceConfig {
82            address: SocketAddr::new(address, port),
83            partition,
84            region,
85            threads,
86            tls,
87        })
88    }
89}
90
91/// The resolved configuration: optional values have been replaced
92pub struct ResolvedBaseServiceConfig {
93    pub address: SocketAddr,
94    pub partition: String,
95    pub region: String,
96    pub threads: usize,
97    pub tls: Option<TlsServerConfig>,
98}
99
100impl Debug for ResolvedBaseServiceConfig {
101    fn fmt(&self, f: &mut Formatter) -> FmtResult {
102        let tls_debug = match &self.tls {
103            None => "None",
104            Some(_) => "Some(TlsServerConfig)",
105        };
106
107        f.debug_struct("ResolvedConfig")
108            .field("address", &self.address)
109            .field("partition", &self.partition)
110            .field("region", &self.region)
111            .field("threads", &self.threads)
112            .field("tls", &tls_debug)
113            .finish()
114    }
115}