Skip to main content

greentic_pack/
messaging.rs

1use std::collections::BTreeSet;
2
3use anyhow::{Result, bail};
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Default)]
8pub struct MessagingSection {
9    #[serde(default, skip_serializing_if = "Option::is_none")]
10    pub adapters: Option<Vec<MessagingAdapter>>,
11}
12
13impl MessagingSection {
14    pub fn validate(&self) -> Result<()> {
15        let mut seen = BTreeSet::new();
16        if let Some(adapters) = &self.adapters {
17            for adapter in adapters {
18                adapter.validate()?;
19                if !seen.insert(adapter.name.clone()) {
20                    bail!("duplicate messaging adapter name: {}", adapter.name);
21                }
22            }
23        }
24        Ok(())
25    }
26}
27
28#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
29pub struct MessagingAdapter {
30    pub name: String,
31    pub kind: MessagingAdapterKind,
32    pub component: String,
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub default_flow: Option<String>,
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub custom_flow: Option<String>,
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    pub capabilities: Option<MessagingAdapterCapabilities>,
39}
40
41impl MessagingAdapter {
42    fn validate(&self) -> Result<()> {
43        if self.name.trim().is_empty() {
44            bail!("messaging.adapters[].name is required");
45        }
46        if self.component.trim().is_empty() {
47            bail!(
48                "messaging.adapters[{}].component must not be empty",
49                self.name
50            );
51        }
52        if let Some(cap) = &self.capabilities {
53            cap.validate(&self.name)?;
54        }
55        Ok(())
56    }
57}
58
59#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
60#[serde(rename_all = "kebab-case")]
61pub enum MessagingAdapterKind {
62    Ingress,
63    Egress,
64    IngressEgress,
65}
66
67#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Default)]
68#[serde(deny_unknown_fields)]
69pub struct MessagingAdapterCapabilities {
70    #[serde(default, skip_serializing_if = "Vec::is_empty")]
71    pub direction: Vec<String>,
72    #[serde(default, skip_serializing_if = "Vec::is_empty")]
73    pub features: Vec<String>,
74}
75
76impl MessagingAdapterCapabilities {
77    fn validate(&self, name: &str) -> Result<()> {
78        for entry in &self.direction {
79            if entry.trim().is_empty() {
80                bail!(
81                    "messaging.adapters[{name}].capabilities.direction must not contain empty values"
82                );
83            }
84        }
85        for entry in &self.features {
86            if entry.trim().is_empty() {
87                bail!(
88                    "messaging.adapters[{name}].capabilities.features must not contain empty values"
89                );
90            }
91        }
92        Ok(())
93    }
94}