cloudpub_common/
config.rs1use crate::constants::DEFAULT_CONNECT_TIMEOUT_SECS;
2use anyhow::{anyhow, Result};
3use serde::{Deserialize, Serialize};
4use std::fmt::{Debug, Formatter};
5use std::ops::Deref;
6use url::Url;
7
8pub use crate::protocol::Protocol;
9
10#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone)]
13pub struct MaskedString(pub String);
14
15impl Debug for MaskedString {
16 fn fmt(&self, f: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
17 if self.0.is_empty() {
18 f.write_str("EMPTY")
19 } else {
20 #[cfg(debug_assertions)]
21 f.write_str(&self.0)?;
22 #[cfg(not(debug_assertions))]
23 f.write_str("MASKED")?;
24 Ok(())
25 }
26 }
27}
28
29impl Deref for MaskedString {
30 type Target = str;
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36impl From<&str> for MaskedString {
37 fn from(s: &str) -> MaskedString {
38 MaskedString(String::from(s))
39 }
40}
41
42#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq, Eq, Default)]
43pub enum TransportType {
44 #[serde(rename = "websocket")]
45 #[default]
46 Websocket,
47 #[serde(rename = "tcp")]
48 Tcp,
49 #[cfg(feature = "rustls")]
50 #[serde(rename = "tls")]
51 Tls,
52}
53
54#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
55#[serde(deny_unknown_fields)]
56#[derive(Default)]
57pub struct TlsConfig {
58 pub hostname: Option<String>,
59 pub trusted_root: Option<String>,
60 pub pkcs12: Option<String>,
61 pub pkcs12_password: Option<MaskedString>,
62 pub danger_ignore_certificate_verification: Option<bool>,
63}
64
65#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
66#[serde(deny_unknown_fields)]
67pub struct WebsocketConfig {
68 pub tls: bool,
69}
70
71impl Default for WebsocketConfig {
72 fn default() -> Self {
73 Self { tls: true }
74 }
75}
76
77#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
78pub struct TcpConfig {
79 pub proxy: Option<Url>,
80 #[serde(default = "default_connect_timeout_secs")]
83 pub connect_timeout_secs: u64,
84}
85
86fn default_connect_timeout_secs() -> u64 {
87 DEFAULT_CONNECT_TIMEOUT_SECS
88}
89
90impl Default for TcpConfig {
91 fn default() -> Self {
92 Self {
93 proxy: None,
94 connect_timeout_secs: default_connect_timeout_secs(),
95 }
96 }
97}
98
99#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
100#[serde(deny_unknown_fields)]
101pub struct TransportConfig {
102 #[serde(rename = "type")]
103 pub transport_type: TransportType,
104 pub tcp: TcpConfig,
105 pub tls: Option<TlsConfig>,
106 pub websocket: Option<WebsocketConfig>,
107}
108
109impl Default for TransportConfig {
110 fn default() -> Self {
111 Self {
112 transport_type: TransportType::Websocket,
113 tcp: TcpConfig::default(),
114 tls: TlsConfig::default().into(),
115 websocket: WebsocketConfig::default().into(),
116 }
117 }
118}
119
120impl TransportConfig {
121 pub fn validate(config: &TransportConfig, _is_server: bool) -> Result<()> {
122 config
123 .tcp
124 .proxy
125 .as_ref()
126 .map_or(Ok(()), |u| match u.scheme() {
127 "socks5" => Ok(()),
128 "http" => Ok(()),
129 _ => Err(anyhow!(format!("Unknown proxy scheme: {}", u.scheme()))),
130 })?;
131 match config.transport_type {
132 TransportType::Tcp => Ok(()),
133 #[cfg(feature = "rustls")]
134 TransportType::Tls => {
135 let tls_config = config
136 .tls
137 .as_ref()
138 .ok_or_else(|| anyhow!("Missing TLS configuration"))?;
139 if _is_server {
140 tls_config
141 .pkcs12
142 .as_ref()
143 .and(tls_config.pkcs12_password.as_ref())
144 .ok_or_else(|| anyhow!("Missing `pkcs12` or `pkcs12_password`"))?;
145 }
146 Ok(())
147 }
148 TransportType::Websocket => Ok(()),
149 }
150 }
151
152 pub fn notls() -> Self {
153 Self {
154 transport_type: TransportType::Websocket,
155 tcp: TcpConfig::default(),
156 tls: None,
157 websocket: WebsocketConfig { tls: false }.into(),
158 }
159 }
160}