use std::collections::HashMap;
use mm1_address::subnet::NetAddress;
use tokio::runtime::Runtime;
mod actor_config;
mod rt_config;
mod validation;
pub(crate) use actor_config::EffectiveActorConfig;
pub use validation::{Valid, ValidationError};
use crate::actor_key::ActorKey;
#[derive(Debug, Clone, serde::Deserialize)]
pub struct Mm1NodeConfig {
#[serde(default = "defaults::local_subnets")]
local_subnets: Vec<DefLocalSubnet>,
#[cfg(feature = "multinode")]
#[serde(default = "Default::default")]
inbound: Vec<DefMultinodeInbound>,
#[cfg(feature = "multinode")]
#[serde(default = "Default::default")]
outbound: Vec<DefMultinodeOutbound>,
#[serde(default)]
actor: actor_config::ActorConfigNode,
#[serde(default)]
runtime: rt_config::RtConfigs,
}
#[derive(Debug, Clone, serde::Deserialize)]
struct DefLocalSubnet {
net: NetAddress,
kind: LocalSubnetKind,
}
#[derive(Debug, Clone, Copy, serde::Deserialize)]
#[serde(rename_all = "lowercase")]
enum LocalSubnetKind {
Auto,
Bind,
}
impl Valid<Mm1NodeConfig> {
pub(crate) fn actor_config(&self, actor_key: &ActorKey) -> impl EffectiveActorConfig + '_ {
self.actor.select(actor_key)
}
pub(crate) fn build_runtimes(&self) -> std::io::Result<(Runtime, HashMap<String, Runtime>)> {
self.runtime.build_runtimes()
}
pub(crate) fn local_subnet_address_auto(&self) -> NetAddress {
self.local_subnets
.iter()
.find(|d| matches!(d.kind, LocalSubnetKind::Auto))
.expect("exactly one local subnet must be present")
.net
}
pub(crate) fn local_subnet_addresses_bind(&self) -> impl Iterator<Item = NetAddress> + '_ {
self.local_subnets
.iter()
.filter_map(|d| matches!(d.kind, LocalSubnetKind::Bind).then_some(d.net))
}
}
#[cfg(feature = "multinode")]
pub(crate) use multinode::*;
#[cfg(feature = "multinode")]
mod multinode {
use std::net::{IpAddr, SocketAddr};
use std::path::Path;
use std::{fmt, str};
use eyre::Context;
use mm1_common::types::AnyError;
use mm1_proto_network_management as nm;
use serde::Deserialize;
use url::Url;
use super::*;
impl Valid<Mm1NodeConfig> {
pub(crate) fn multinode_inbound(
&self,
) -> impl Iterator<Item = (Vec<nm::ProtocolName>, DefAddr, nm::Options)> + '_ {
self.inbound
.iter()
.map(|d| (d.proto.clone(), d.addr.clone(), d.options.clone()))
}
pub(crate) fn multinode_outbound(
&self,
) -> impl Iterator<Item = (Vec<nm::ProtocolName>, DefAddr, nm::Options)> + '_ {
self.outbound
.iter()
.map(|d| (d.proto.clone(), d.addr.clone(), d.options.clone()))
}
}
#[derive(Debug, Clone)]
pub(crate) enum DefAddr {
Tcp(SocketAddr),
Uds(Box<Path>),
}
#[derive(Debug, Clone, serde::Deserialize)]
pub(super) struct DefMultinodeInbound {
#[serde(default)]
proto: Vec<nm::ProtocolName>,
addr: DefAddr,
#[serde(flatten)]
options: nm::Options,
}
#[cfg(feature = "multinode")]
#[derive(Debug, Clone, serde::Deserialize)]
pub(super) struct DefMultinodeOutbound {
#[serde(default)]
proto: Vec<nm::ProtocolName>,
addr: DefAddr,
#[serde(flatten)]
options: nm::Options,
}
impl std::fmt::Display for DefAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Tcp(tcp) => write!(f, "tcp://{}", tcp),
Self::Uds(uds) => write!(f, "uds://{:?}", uds),
}
}
}
impl std::str::FromStr for DefAddr {
type Err = AnyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let url: Url = s.parse().wrap_err("Url::from_str")?;
match url.scheme() {
"uds" => {
let s = format!(
"{}{}",
url.host().map(|d| d.to_string()).unwrap_or_default(),
url.path()
);
let p: &Path = Path::new(s.as_str());
Ok(Self::Uds(p.into()))
},
"tcp" => {
let ip: IpAddr = url
.host()
.ok_or(eyre::format_err!("url.host must be present"))?
.to_string()
.parse()
.wrap_err("IpAddr::parse")?;
let port: u16 = url
.port()
.ok_or(eyre::format_err!("url.port must be present"))?;
let socket_addr = SocketAddr::new(ip, port);
Ok(Self::Tcp(socket_addr))
},
unsupported => Err(eyre::format_err!("unsupported url-scheme: {}", unsupported)),
}
}
}
impl<'de> Deserialize<'de> for DefAddr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error as _;
String::deserialize(deserializer)?
.parse()
.map_err(D::Error::custom)
}
}
}
mod defaults;