use super::version::validate_version;
use crate::error::{Error, Result};
use crate::spec::{
allora_spec::AlloraSpec, channels_spec_yaml::ChannelsSpecYamlParser,
filters_spec_yaml::FiltersSpecYamlParser, ChannelsSpec, FiltersSpec, HttpInboundAdaptersSpec,
HttpInboundAdaptersSpecYamlParser, HttpOutboundAdaptersSpec,
HttpOutboundAdaptersSpecYamlParser, ServiceActivatorsSpec, ServiceSpecYamlParser,
};
use serde_yaml::Value as YamlValue;
pub struct AlloraSpecYamlParser;
impl AlloraSpecYamlParser {
pub fn parse_value(yaml: &YamlValue) -> Result<AlloraSpec> {
let v = validate_version(yaml)?; let channels_root_opt = yaml.get("channels");
let mut all = if let Some(ch_root) = channels_root_opt {
if !ch_root.is_sequence() {
return Err(Error::serialization("'channels' must be a sequence"));
}
let mut obj = serde_yaml::Mapping::new();
obj.insert(
serde_yaml::Value::String("version".into()),
serde_yaml::Value::Number(serde_yaml::Number::from(v)),
);
obj.insert(
serde_yaml::Value::String("channels".into()),
ch_root.clone(),
);
let synthesized = serde_yaml::Value::Mapping(obj);
let channels_spec: ChannelsSpec = ChannelsSpecYamlParser::parse_value(&synthesized)?;
AlloraSpec::new(v, channels_spec)
} else {
AlloraSpec::new(v, ChannelsSpec::new(v))
};
let filters_root = yaml.get("filters");
let services_root = yaml.get("service-activators");
let http_inbound_root = yaml.get("http-inbound-adapters");
let http_outbound_root = yaml.get("http-outbound-adapters");
if let Some(fr) = filters_root {
if !fr.is_sequence() {
return Err(Error::serialization("'filters' must be a sequence"));
}
let mut fobj = serde_yaml::Mapping::new();
fobj.insert(
serde_yaml::Value::String("version".into()),
serde_yaml::Value::Number(serde_yaml::Number::from(v)),
);
fobj.insert(serde_yaml::Value::String("filters".into()), fr.clone());
let fsynth = serde_yaml::Value::Mapping(fobj);
let filters_spec: FiltersSpec = FiltersSpecYamlParser::parse_value(&fsynth)?;
all = all.with_filters(filters_spec);
}
if let Some(sr) = services_root {
if !sr.is_sequence() {
return Err(Error::serialization(
"'service-activators' must be a sequence",
));
}
let seq = sr.as_sequence().unwrap();
if seq.is_empty() {
return Err(Error::serialization(
"'service-activators' sequence must not be empty",
));
}
let mut services_spec = ServiceActivatorsSpec::new(v);
for item in seq {
if !item.is_mapping() {
return Err(Error::serialization(
"service-activator entry must be a mapping",
));
}
let mut obj = serde_yaml::Mapping::new();
obj.insert(
serde_yaml::Value::String("version".into()),
serde_yaml::Value::Number(serde_yaml::Number::from(v)),
);
obj.insert(
serde_yaml::Value::String("service-activator".into()),
item.clone(),
);
let synthesized = serde_yaml::Value::Mapping(obj);
let svc = ServiceSpecYamlParser::parse_value(&synthesized)?;
services_spec.push(svc);
}
all = all.with_services(services_spec);
}
if let Some(hr) = http_inbound_root {
if !hr.is_sequence() {
return Err(Error::serialization(
"'http-inbound-adapters' must be a sequence",
));
}
if hr.as_sequence().unwrap().is_empty() {
return Err(Error::serialization(
"'http-inbound-adapters' sequence must not be empty",
));
}
let mut hobj = serde_yaml::Mapping::new();
hobj.insert(
serde_yaml::Value::String("version".into()),
serde_yaml::Value::Number(serde_yaml::Number::from(v)),
);
hobj.insert(
serde_yaml::Value::String("http-inbound-adapters".into()),
hr.clone(),
);
let hsynth = serde_yaml::Value::Mapping(hobj);
let adapters_spec: HttpInboundAdaptersSpec =
HttpInboundAdaptersSpecYamlParser::parse_value(&hsynth)?;
all = all.with_http_inbound_adapters(adapters_spec);
}
if let Some(oroot) = http_outbound_root {
if !oroot.is_sequence() {
return Err(Error::serialization(
"'http-outbound-adapters' must be a sequence",
));
}
if oroot.as_sequence().unwrap().is_empty() {
return Err(Error::serialization(
"'http-outbound-adapters' sequence must not be empty",
));
}
let mut oobj = serde_yaml::Mapping::new();
oobj.insert(
serde_yaml::Value::String("version".into()),
serde_yaml::Value::Number(serde_yaml::Number::from(v)),
);
oobj.insert(
serde_yaml::Value::String("http-outbound-adapters".into()),
oroot.clone(),
);
let osynth = serde_yaml::Value::Mapping(oobj);
let outbound_spec: HttpOutboundAdaptersSpec =
HttpOutboundAdaptersSpecYamlParser::parse_value(&osynth)?;
all = all.with_http_outbound_adapters(outbound_spec);
}
Ok(all)
}
pub fn parse_str(raw: &str) -> Result<AlloraSpec> {
let val: YamlValue = serde_yaml::from_str(raw)
.map_err(|e| Error::serialization(format!("yaml parse error: {e}")))?;
Self::parse_value(&val)
}
}