1use {
4 self::{
5 acl::AclConfig, backends::BackendsConfig, dictionaries::DictionariesConfig,
6 object_store::ObjectStoreConfig, secret_store::SecretStoreConfig,
7 },
8 crate::error::FastlyConfigError,
9 serde_derive::Deserialize,
10 std::{collections::HashMap, convert::TryInto, fs, path::Path, str::FromStr, sync::Arc},
11 toml::value::Table,
12};
13
14#[cfg(test)]
16mod unit_tests;
17
18mod limits;
20
21mod dictionaries;
23
24pub use self::dictionaries::{Dictionary, LoadedDictionary};
25
26pub type Dictionaries = HashMap<String, Dictionary>;
27
28mod acl;
30pub use crate::acl::Acls;
31
32mod backends;
34
35pub use self::backends::{Backend, ClientCertError, ClientCertInfo};
36
37pub type Backends = HashMap<String, Arc<Backend>>;
38
39mod device_detection;
41
42pub use self::device_detection::DeviceDetection;
43
44mod geolocation;
46
47pub use self::geolocation::Geolocation;
48
49mod object_store;
51
52pub use crate::object_store::ObjectStores;
53
54mod secret_store;
56pub use crate::secret_store::{SecretStore, SecretStores};
57
58pub use crate::shielding_site::ShieldingSites;
59
60#[derive(Debug, Clone)]
64pub struct FastlyConfig {
65 name: String,
66 description: String,
67 authors: Vec<String>,
68 language: String,
69 local_server: LocalServerConfig,
70}
71
72impl FastlyConfig {
73 pub fn name(&self) -> &str {
75 self.name.as_str()
76 }
77
78 pub fn description(&self) -> &str {
80 self.description.as_str()
81 }
82
83 pub fn authors(&self) -> &[String] {
85 self.authors.as_ref()
86 }
87
88 pub fn language(&self) -> &str {
90 self.language.as_str()
91 }
92
93 pub fn acls(&self) -> &Acls {
95 &self.local_server.acls.0
96 }
97
98 pub fn backends(&self) -> &Backends {
100 &self.local_server.backends.0
101 }
102
103 pub fn device_detection(&self) -> &DeviceDetection {
105 &self.local_server.device_detection
106 }
107
108 pub fn geolocation(&self) -> &Geolocation {
110 &self.local_server.geolocation
111 }
112
113 pub fn dictionaries(&self) -> &Dictionaries {
115 &self.local_server.dictionaries.0
116 }
117
118 pub fn object_stores(&self) -> &ObjectStores {
120 &self.local_server.object_stores.0
121 }
122
123 pub fn secret_stores(&self) -> &SecretStores {
125 &self.local_server.secret_stores.0
126 }
127 pub fn shielding_sites(&self) -> &ShieldingSites {
129 &self.local_server.shielding_sites
130 }
131
132 pub fn from_file(path: impl AsRef<Path>) -> Result<Self, FastlyConfigError> {
134 fs::read_to_string(path.as_ref())
135 .map_err(|err| FastlyConfigError::IoError {
136 path: path.as_ref().display().to_string(),
137 err,
138 })
139 .and_then(Self::from_str)
140 }
141
142 fn from_str(toml: impl AsRef<str>) -> Result<Self, FastlyConfigError> {
144 toml::from_str::<'_, TomlFastlyConfig>(toml.as_ref())
145 .map_err(Into::into)
146 .and_then(TryInto::try_into)
147 }
148}
149
150impl FromStr for FastlyConfig {
151 type Err = FastlyConfigError;
152 fn from_str(s: &str) -> Result<Self, Self::Err> {
153 Self::from_str(s)
154 }
155}
156
157#[derive(Deserialize)]
165struct TomlFastlyConfig {
166 local_server: Option<RawLocalServerConfig>,
167 name: Option<String>,
173 description: Option<String>,
174 authors: Option<Vec<String>>,
175 language: Option<String>,
176}
177
178impl TryInto<FastlyConfig> for TomlFastlyConfig {
179 type Error = FastlyConfigError;
180 fn try_into(self) -> Result<FastlyConfig, Self::Error> {
181 let Self {
182 name,
183 description,
184 authors,
185 language,
186 local_server,
187 } = self;
188 let local_server = local_server
189 .map(TryInto::try_into)
190 .transpose()?
191 .unwrap_or_default();
192 Ok(FastlyConfig {
193 name: name.unwrap_or_default(),
194 description: description.unwrap_or_default(),
195 authors: authors.unwrap_or_default(),
196 language: language.unwrap_or_default(),
197 local_server,
198 })
199 }
200}
201
202#[derive(Clone, Debug, Default)]
208pub struct LocalServerConfig {
209 acls: AclConfig,
210 backends: BackendsConfig,
211 device_detection: DeviceDetection,
212 geolocation: Geolocation,
213 dictionaries: DictionariesConfig,
214 object_stores: ObjectStoreConfig,
215 secret_stores: SecretStoreConfig,
216 shielding_sites: ShieldingSites,
217}
218
219#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
221pub enum ExperimentalModule {
222 WasiNn,
223}
224
225#[derive(Deserialize)]
230struct RawLocalServerConfig {
231 acls: Option<Table>,
232 backends: Option<Table>,
233 device_detection: Option<Table>,
234 geolocation: Option<Table>,
235 #[serde(alias = "config_stores")]
236 dictionaries: Option<Table>,
237 #[serde(alias = "object_store", alias = "kv_stores")]
238 object_stores: Option<Table>,
239 secret_stores: Option<Table>,
240 shielding_sites: Option<Table>,
241}
242
243impl TryInto<LocalServerConfig> for RawLocalServerConfig {
244 type Error = FastlyConfigError;
245 fn try_into(self) -> Result<LocalServerConfig, Self::Error> {
246 let Self {
247 acls,
248 backends,
249 device_detection,
250 geolocation,
251 dictionaries,
252 object_stores,
253 secret_stores,
254 shielding_sites,
255 } = self;
256 let acls = if let Some(acls) = acls {
257 acls.try_into()?
258 } else {
259 AclConfig::default()
260 };
261 let backends = if let Some(backends) = backends {
262 backends.try_into()?
263 } else {
264 BackendsConfig::default()
265 };
266 let device_detection = if let Some(device_detection) = device_detection {
267 device_detection.try_into()?
268 } else {
269 DeviceDetection::default()
270 };
271 let geolocation = if let Some(geolocation) = geolocation {
272 geolocation.try_into()?
273 } else {
274 Geolocation::default()
275 };
276 let dictionaries = if let Some(dictionaries) = dictionaries {
277 dictionaries.try_into()?
278 } else {
279 DictionariesConfig::default()
280 };
281 let object_stores = if let Some(object_store) = object_stores {
282 object_store.try_into()?
283 } else {
284 ObjectStoreConfig::default()
285 };
286 let secret_stores = if let Some(secret_store) = secret_stores {
287 secret_store.try_into()?
288 } else {
289 SecretStoreConfig::default()
290 };
291 let shielding_sites = if let Some(shielding_sites) = shielding_sites {
292 shielding_sites.try_into()?
293 } else {
294 ShieldingSites::default()
295 };
296
297 Ok(LocalServerConfig {
298 acls,
299 backends,
300 device_detection,
301 geolocation,
302 dictionaries,
303 object_stores,
304 secret_stores,
305 shielding_sites,
306 })
307 }
308}
309
310#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum, Hash)]
311pub enum UnknownImportBehavior {
312 #[default]
314 LinkError,
315 Trap,
317}