#![deny(
warnings,
missing_debug_implementations,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unstable_features,
unused_import_braces,
unused_qualifications,
unreachable_pub,
type_alias_bounds,
trivial_bounds,
mutable_transmutes,
invalid_value,
explicit_outlives_requirements,
deprecated,
clashing_extern_declarations,
clippy::expect_used,
clippy::explicit_deref_methods
)]
#![warn(clippy::cognitive_complexity)]
#![allow(missing_docs, clippy::exhaustive_enums, clippy::exhaustive_structs)]
#[cfg(feature = "config")]
pub(crate) mod conversions;
pub(crate) mod parse;
use std::collections::HashMap;
use std::str::FromStr;
use num_traits::FromPrimitive;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_with_expand_env::with_expand_envs;
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct HostManifest {
#[serde(deserialize_with = "with_expand_envs")]
pub format: u32,
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub version: String,
#[serde(default)]
pub host: Option<HostConfig>,
#[serde(default)]
pub network: NetworkManifest,
#[serde(default)]
pub default_schematic: Option<String>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct HostConfig {
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub allow_latest: bool,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub insecure_registries: Vec<String>,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub expose: Vec<String>,
#[serde(default)]
pub mesh: Option<MeshConfig>,
#[serde(default)]
pub rpc: Option<HttpConfig>,
#[serde(default)]
pub http: Option<HttpConfig>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct HttpConfig {
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub enabled: bool,
#[serde(default)]
pub port: Option<u16>,
#[serde(default)]
pub address: Option<String>,
#[serde(default)]
pub pem: Option<String>,
#[serde(default)]
pub key: Option<String>,
#[serde(default)]
pub ca: Option<String>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct MeshConfig {
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub enabled: bool,
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub address: String,
#[serde(default)]
pub creds_path: Option<String>,
#[serde(default)]
pub token: Option<String>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct NetworkManifest {
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub schematics: Vec<SchematicManifest>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub collections: Vec<CollectionDefinition>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct CollectionDefinition {
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub namespace: String,
#[serde(default)]
pub kind: CollectionKind,
#[serde(default)]
#[serde(deserialize_with = "with_expand_envs")]
pub reference: String,
#[serde(default)]
pub data: Option<HashMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Copy, PartialEq)]
#[serde(deny_unknown_fields)]
pub enum CollectionKind {
Native = 0,
GrpcUrl = 1,
WaPC = 2,
Network = 4,
}
impl Default for CollectionKind {
fn default() -> Self {
Self::from_u16(0).unwrap()
}
}
impl FromPrimitive for CollectionKind {
fn from_i64(n: i64) -> Option<Self> {
Some(match n {
0 => Self::Native,
1 => Self::GrpcUrl,
2 => Self::WaPC,
4 => Self::Network,
_ => {
return None;
}
})
}
fn from_u64(n: u64) -> Option<Self> {
Some(match n {
0 => Self::Native,
1 => Self::GrpcUrl,
2 => Self::WaPC,
4 => Self::Network,
_ => {
return None;
}
})
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct SchematicManifest {
#[serde(deserialize_with = "with_expand_envs")]
pub name: String,
#[serde(default)]
#[serde(skip_serializing_if = "HashMap::is_empty")]
#[serde(deserialize_with = "map_component_def")]
pub instances: HashMap<String, ComponentDefinition>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
#[serde(deserialize_with = "vec_connection")]
pub connections: Vec<ConnectionDefinition>,
#[serde(default)]
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub constraints: HashMap<String, String>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ComponentDefinition {
#[serde(deserialize_with = "with_expand_envs")]
pub id: String,
#[serde(default)]
pub data: Option<HashMap<String, Value>>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ConnectionDefinition {
#[serde(default)]
#[serde(deserialize_with = "connection_target_shortform")]
pub from: ConnectionTargetDefinition,
#[serde(default)]
#[serde(deserialize_with = "connection_target_shortform")]
pub to: ConnectionTargetDefinition,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct ConnectionTargetDefinition {
#[serde(deserialize_with = "with_expand_envs")]
pub instance: String,
#[serde(deserialize_with = "with_expand_envs")]
pub port: String,
#[serde(default)]
pub data: Option<HashMap<String, Value>>,
}
impl FromStr for ComponentDefinition {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
id: s.to_owned(),
data: Default::default(),
})
}
}
impl FromStr for ConnectionDefinition {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::v0::parse::parse_connection(s)
}
}
impl FromStr for ConnectionTargetDefinition {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::v0::parse::parse_connection_target(s)
}
}
fn map_component_def<'de, D>(deserializer: D) -> Result<HashMap<String, ComponentDefinition>, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ComponentDefinitionVisitor;
impl<'de> serde::de::Visitor<'de> for ComponentDefinitionVisitor {
type Value = HashMap<String, ComponentDefinition>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "a map of instances to their components")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: serde::de::MapAccess<'de>,
{
let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));
while let Some((key, value)) = access.next_entry::<String, serde_value::Value>()? {
let result = match value {
serde_value::Value::String(s) => {
ComponentDefinition::from_str(&s).map_err(|e| serde::de::Error::custom(e.to_string()))?
}
serde_value::Value::Map(map) => {
ComponentDefinition::deserialize(serde_value::ValueDeserializer::new(serde_value::Value::Map(map)))?
}
_ => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("other"),
&self,
))
}
};
map.insert(key, result);
}
Ok(map)
}
}
deserializer.deserialize_map(ComponentDefinitionVisitor)
}
fn vec_connection<'de, D>(deserializer: D) -> Result<Vec<ConnectionDefinition>, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ConnectionDefVisitor;
impl<'de> serde::de::Visitor<'de> for ConnectionDefVisitor {
type Value = Vec<ConnectionDefinition>;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "a list of connections")
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut seq: A) -> Result<Vec<ConnectionDefinition>, A::Error> {
let mut v = vec![];
while let Some(thing) = seq.next_element::<serde_value::Value>()? {
let result = match thing {
serde_value::Value::String(s) => {
ConnectionDefinition::from_str(&s).map_err(|e| serde::de::Error::custom(e.to_string()))?
}
serde_value::Value::Map(map) => {
ConnectionDefinition::deserialize(serde_value::ValueDeserializer::new(serde_value::Value::Map(map)))?
}
_ => {
return Err(serde::de::Error::invalid_type(
serde::de::Unexpected::Other("other"),
&self,
))
}
};
v.push(result);
}
Ok(v)
}
}
deserializer.deserialize_seq(ConnectionDefVisitor)
}
fn connection_target_shortform<'de, D>(deserializer: D) -> Result<ConnectionTargetDefinition, D::Error>
where
D: serde::Deserializer<'de>,
{
struct ConnectionTargetVisitor;
impl<'de> serde::de::Visitor<'de> for ConnectionTargetVisitor {
type Value = ConnectionTargetDefinition;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a connection target definition")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
ConnectionTargetDefinition::from_str(s).map_err(|e| serde::de::Error::custom(e.to_string()))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
ConnectionTargetDefinition::deserialize(serde::de::value::MapAccessDeserializer::new(map))
}
}
deserializer.deserialize_any(ConnectionTargetVisitor)
}