use {
self::{
acl::AclConfig, backends::BackendsConfig, dictionaries::DictionariesConfig,
object_store::ObjectStoreConfig, secret_store::SecretStoreConfig,
},
crate::error::FastlyConfigError,
serde_derive::Deserialize,
std::{
collections::{HashMap, HashSet},
convert::TryInto,
fs,
path::Path,
str::FromStr,
sync::Arc,
},
toml::value::Table,
};
#[cfg(test)]
mod unit_tests;
mod limits;
mod dictionaries;
pub use self::dictionaries::{Dictionary, LoadedDictionary};
pub type Dictionaries = HashMap<String, Dictionary>;
mod acl;
pub use crate::acl::Acls;
mod backends;
pub use self::backends::{Backend, BackendHealth, ClientCertError, ClientCertInfo};
pub type Backends = HashMap<String, Arc<Backend>>;
mod device_detection;
pub use self::device_detection::DeviceDetection;
mod geolocation;
pub use self::geolocation::Geolocation;
mod object_store;
pub use crate::object_store::ObjectStores;
mod secret_store;
pub use crate::secret_store::{SecretStore, SecretStores};
pub use crate::shielding_site::ShieldingSites;
pub type FakeValidFastlyKeys = HashSet<String>;
#[derive(Debug, Clone)]
pub struct FastlyConfig {
name: String,
description: String,
authors: Vec<String>,
language: String,
local_server: LocalServerConfig,
}
impl FastlyConfig {
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn description(&self) -> &str {
self.description.as_str()
}
pub fn authors(&self) -> &[String] {
self.authors.as_ref()
}
pub fn language(&self) -> &str {
self.language.as_str()
}
pub fn acls(&self) -> &Acls {
&self.local_server.acls.0
}
pub fn backends(&self) -> &Backends {
&self.local_server.backends.0
}
pub fn device_detection(&self) -> &DeviceDetection {
&self.local_server.device_detection
}
pub fn geolocation(&self) -> &Geolocation {
&self.local_server.geolocation
}
pub fn dictionaries(&self) -> &Dictionaries {
&self.local_server.dictionaries.0
}
pub fn object_stores(&self) -> &ObjectStores {
&self.local_server.object_stores.0
}
pub fn secret_stores(&self) -> &SecretStores {
&self.local_server.secret_stores.0
}
pub fn shielding_sites(&self) -> &ShieldingSites {
&self.local_server.shielding_sites
}
pub fn fake_valid_fastly_keys(&self) -> &FakeValidFastlyKeys {
&self.local_server.fake_valid_fastly_keys
}
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, FastlyConfigError> {
fs::read_to_string(path.as_ref())
.map_err(|err| FastlyConfigError::IoError {
path: path.as_ref().display().to_string(),
err,
})
.and_then(Self::from_str)
}
fn from_str(toml: impl AsRef<str>) -> Result<Self, FastlyConfigError> {
toml::from_str::<'_, TomlFastlyConfig>(toml.as_ref())
.map_err(Into::into)
.and_then(TryInto::try_into)
}
}
impl FromStr for FastlyConfig {
type Err = FastlyConfigError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::from_str(s)
}
}
#[derive(Deserialize)]
struct TomlFastlyConfig {
manifest_version: Option<u32>,
local_server: Option<RawLocalServerConfig>,
name: Option<String>,
description: Option<String>,
authors: Option<Vec<String>>,
language: Option<String>,
}
const MAX_MANIFEST_VERSION: u32 = 3;
impl TryInto<FastlyConfig> for TomlFastlyConfig {
type Error = FastlyConfigError;
fn try_into(self) -> Result<FastlyConfig, Self::Error> {
let Self {
manifest_version,
name,
description,
authors,
language,
local_server,
} = self;
if let Some(manifest_version) = manifest_version
&& manifest_version > MAX_MANIFEST_VERSION
{
return Err(FastlyConfigError::UnsupportedManifestVersion(
manifest_version,
MAX_MANIFEST_VERSION,
));
}
let local_server = local_server
.map(TryInto::try_into)
.transpose()?
.unwrap_or_default();
Ok(FastlyConfig {
name: name.unwrap_or_default(),
description: description.unwrap_or_default(),
authors: authors.unwrap_or_default(),
language: language.unwrap_or_default(),
local_server,
})
}
}
#[derive(Clone, Debug, Default)]
pub struct LocalServerConfig {
acls: AclConfig,
backends: BackendsConfig,
device_detection: DeviceDetection,
geolocation: Geolocation,
dictionaries: DictionariesConfig,
object_stores: ObjectStoreConfig,
secret_stores: SecretStoreConfig,
shielding_sites: ShieldingSites,
fake_valid_fastly_keys: FakeValidFastlyKeys,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ExperimentalModule {
WasiNn,
}
#[derive(Deserialize)]
struct RawLocalServerConfig {
acls: Option<Table>,
backends: Option<Table>,
device_detection: Option<Table>,
geolocation: Option<Table>,
#[serde(alias = "config_stores")]
dictionaries: Option<Table>,
#[serde(alias = "object_store", alias = "kv_stores")]
object_stores: Option<Table>,
secret_stores: Option<Table>,
shielding_sites: Option<Table>,
fake_valid_fastly_keys: Option<Vec<String>>,
}
impl TryInto<LocalServerConfig> for RawLocalServerConfig {
type Error = FastlyConfigError;
fn try_into(self) -> Result<LocalServerConfig, Self::Error> {
let Self {
acls,
backends,
device_detection,
geolocation,
dictionaries,
object_stores,
secret_stores,
shielding_sites,
fake_valid_fastly_keys,
} = self;
let acls = if let Some(acls) = acls {
acls.try_into()?
} else {
AclConfig::default()
};
let backends = if let Some(backends) = backends {
backends.try_into()?
} else {
BackendsConfig::default()
};
let device_detection = if let Some(device_detection) = device_detection {
device_detection.try_into()?
} else {
DeviceDetection::default()
};
let geolocation = if let Some(geolocation) = geolocation {
geolocation.try_into()?
} else {
Geolocation::default()
};
let dictionaries = if let Some(dictionaries) = dictionaries {
dictionaries.try_into()?
} else {
DictionariesConfig::default()
};
let object_stores = if let Some(object_store) = object_stores {
object_store.try_into()?
} else {
ObjectStoreConfig::default()
};
let secret_stores = if let Some(secret_store) = secret_stores {
secret_store.try_into()?
} else {
SecretStoreConfig::default()
};
let shielding_sites = if let Some(shielding_sites) = shielding_sites {
shielding_sites.try_into()?
} else {
ShieldingSites::default()
};
let fake_valid_fastly_keys = fake_valid_fastly_keys
.unwrap_or_default()
.into_iter()
.collect::<FakeValidFastlyKeys>();
Ok(LocalServerConfig {
acls,
backends,
device_detection,
geolocation,
dictionaries,
object_stores,
secret_stores,
shielding_sites,
fake_valid_fastly_keys,
})
}
}
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum, Hash)]
pub enum UnknownImportBehavior {
#[default]
LinkError,
Trap,
}