allora_runtime/spec/
http_inbound_adapters_spec_yaml.rs

1//! YAML parser for HttpInboundAdaptersSpec (collection v1).
2//! Expects structure defined in `schema/v1/http-inbound-adapters.schema.yml`.
3//! Delegates per-entry parsing to `HttpInboundAdapterSpecYamlParser` and focuses on sequence + version validation.
4//!
5//! # Responsibilities
6//! * Validate root `version` (must equal 1).
7//! * Ensure `http-inbound-adapters` is a non-empty YAML sequence.
8//! * Delegate each item mapping to existing single parser by synthesizing a temporary document.
9//! * Preserve order of entries.
10//!
11//! # Error Cases
12//! * Missing `http-inbound-adapters` key.
13//! * Non-sequence `http-inbound-adapters` value.
14//! * Empty sequence (minItems=1).
15//! * Non-mapping item inside sequence.
16//! * Any error bubbled from `HttpInboundAdapterSpecYamlParser`.
17//!
18//! # Example YAML
19//! ```yaml
20//! version: 1
21//! http-inbound-adapters:
22//!   - id: http.receiveGateway
23//!     host: 127.0.0.1
24//!     port: 8080
25//!     path: /receiveGateway
26//!     methods: [ POST ]
27//!     request-channel: receiveChannel
28//!     reply-channel: replyChannel
29//!   - host: 0.0.0.0
30//!     port: 8081
31//!     path: /orders
32//!     methods: [ POST, GET ]
33//!     request-channel: inbound.orders
34//! ```
35
36use crate::error::{Error, Result};
37use crate::spec::version::validate_version;
38use crate::spec::{HttpInboundAdapterSpecYamlParser, HttpInboundAdaptersSpec};
39use serde_yaml::Value as YamlValue;
40
41pub struct HttpInboundAdaptersSpecYamlParser;
42
43impl HttpInboundAdaptersSpecYamlParser {
44    pub fn parse_value(yaml: &YamlValue) -> Result<HttpInboundAdaptersSpec> {
45        let v = validate_version(yaml)?;
46        let root = yaml
47            .get("http-inbound-adapters")
48            .ok_or_else(|| Error::serialization("missing 'http-inbound-adapters'"))?;
49        if !root.is_sequence() {
50            return Err(Error::serialization(
51                "'http-inbound-adapters' must be a sequence",
52            ));
53        }
54        let seq = root.as_sequence().unwrap();
55        if seq.is_empty() {
56            return Err(Error::serialization(
57                "'http-inbound-adapters' sequence must not be empty (minItems=1)",
58            ));
59        }
60        let mut spec = HttpInboundAdaptersSpec::new(v);
61        for item in seq {
62            if !item.is_mapping() {
63                return Err(Error::serialization(
64                    "http-inbound-adapter entry must be a mapping",
65                ));
66            }
67            let mut obj = serde_yaml::Mapping::new();
68            obj.insert(
69                serde_yaml::Value::String("version".into()),
70                serde_yaml::Value::Number(serde_yaml::Number::from(v)),
71            );
72            obj.insert(
73                serde_yaml::Value::String("http-inbound-adapter".into()),
74                item.clone(),
75            );
76            let synthesized = YamlValue::Mapping(obj);
77            let single = HttpInboundAdapterSpecYamlParser::parse_value(&synthesized)?;
78            spec.push(single);
79        }
80        Ok(spec)
81    }
82    pub fn parse_str(raw: &str) -> Result<HttpInboundAdaptersSpec> {
83        let val: YamlValue = serde_yaml::from_str(raw)
84            .map_err(|e| Error::serialization(format!("yaml parse error: {e}")))?;
85        Self::parse_value(&val)
86    }
87}