use super::version::validate_version;
use crate::error::{Error, Result};
use crate::spec::channels_spec::ChannelsSpec;
use crate::spec::{ChannelKindSpec, ChannelSpec};
use serde_yaml::Value as YamlValue;
pub struct ChannelsSpecYamlParser;
impl ChannelsSpecYamlParser {
pub fn parse_value(yaml: &YamlValue) -> Result<ChannelsSpec> {
let v = validate_version(yaml)?; let channels_val = yaml
.get("channels")
.ok_or_else(|| Error::serialization("missing 'channels'"))?;
if !channels_val.is_sequence() {
return Err(Error::serialization("'channels' must be a sequence"));
}
let mut spec = ChannelsSpec::new(v);
for item in channels_val.as_sequence().unwrap() {
if !item.is_mapping() {
return Err(Error::serialization("channel entry must be a mapping"));
}
let kind_spec = if let Some(kind_val) = item.get("kind") {
let kind_str = kind_val
.as_str()
.ok_or_else(|| Error::serialization("channel.kind must be string"))?;
match kind_str {
"direct" => ChannelKindSpec::Direct,
"queue" => ChannelKindSpec::Queue,
other => {
return Err(Error::serialization(format!(
"unsupported channel.kind '{other}'"
)))
}
}
} else {
tracing::info!("channel.kind missing in entry; defaulting to 'direct'");
ChannelKindSpec::Direct
};
let id_opt = item
.get("id")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
if let Some(ref id) = id_opt {
if id.is_empty() {
return Err(Error::serialization("channel.id must not be empty"));
}
}
spec.push(ChannelSpec {
id: id_opt,
kind: kind_spec,
});
}
Ok(spec)
}
pub fn parse_str(raw: &str) -> Result<ChannelsSpec> {
let val: YamlValue = serde_yaml::from_str(raw)
.map_err(|e| Error::serialization(format!("yaml parse error: {e}")))?;
Self::parse_value(&val)
}
}