1use std::collections::BTreeSet;
2use std::fmt;
3
4use anyhow::{Result, bail};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Default)]
9pub struct EventsSection {
10 #[serde(default)]
11 pub providers: Vec<EventProviderSpec>,
12}
13
14impl EventsSection {
15 pub fn validate(&self) -> Result<()> {
16 let mut seen = BTreeSet::new();
17 for provider in &self.providers {
18 provider.validate()?;
19 if !seen.insert(provider.name.clone()) {
20 bail!("duplicate events provider name: {}", provider.name);
21 }
22 }
23 Ok(())
24 }
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
28pub struct EventProviderSpec {
29 pub name: String,
30 pub kind: EventProviderKind,
31 pub component: String,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub default_flow: Option<String>,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
35 pub custom_flow: Option<String>,
36 #[serde(default)]
37 pub capabilities: EventProviderCapabilities,
38}
39
40impl EventProviderSpec {
41 fn validate(&self) -> Result<()> {
42 if self.name.trim().is_empty() {
43 bail!("events.providers[].name is required");
44 }
45 if self.component.trim().is_empty() {
46 bail!(
47 "events.providers[{}].component must not be empty",
48 self.name
49 );
50 }
51 for topic in &self.capabilities.topics {
52 if topic.trim().is_empty() {
53 bail!(
54 "events.providers[{}].capabilities.topics may not contain empty entries",
55 self.name
56 );
57 }
58 }
59 Ok(())
60 }
61}
62
63#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, Default)]
64pub struct EventProviderCapabilities {
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub transport: Option<TransportKind>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub reliability: Option<ReliabilityKind>,
69 #[serde(default, skip_serializing_if = "Option::is_none")]
70 pub ordering: Option<OrderingKind>,
71 #[serde(default, skip_serializing_if = "Vec::is_empty")]
72 pub topics: Vec<String>,
73}
74
75#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
76#[serde(rename_all = "snake_case")]
77pub enum EventProviderKind {
78 Broker,
79 Source,
80 Sink,
81 Bridge,
82}
83
84impl fmt::Display for EventProviderKind {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 let value = match self {
87 Self::Broker => "broker",
88 Self::Source => "source",
89 Self::Sink => "sink",
90 Self::Bridge => "bridge",
91 };
92 f.write_str(value)
93 }
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
97#[serde(rename_all = "snake_case")]
98#[serde(untagged)]
99pub enum TransportKind {
100 Nats,
101 Kafka,
102 Sqs,
103 Webhook,
104 Email,
105 Other(String),
106}
107
108impl fmt::Display for TransportKind {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 match self {
111 Self::Nats => f.write_str("nats"),
112 Self::Kafka => f.write_str("kafka"),
113 Self::Sqs => f.write_str("sqs"),
114 Self::Webhook => f.write_str("webhook"),
115 Self::Email => f.write_str("email"),
116 Self::Other(value) => f.write_str(value),
117 }
118 }
119}
120
121#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
122#[serde(rename_all = "snake_case")]
123pub enum ReliabilityKind {
124 AtMostOnce,
125 AtLeastOnce,
126 EffectivelyOnce,
127}
128
129impl fmt::Display for ReliabilityKind {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 let value = match self {
132 Self::AtMostOnce => "at_most_once",
133 Self::AtLeastOnce => "at_least_once",
134 Self::EffectivelyOnce => "effectively_once",
135 };
136 f.write_str(value)
137 }
138}
139
140#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
141#[serde(rename_all = "snake_case")]
142pub enum OrderingKind {
143 None,
144 PerKey,
145 Global,
146}
147
148impl fmt::Display for OrderingKind {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 let value = match self {
151 Self::None => "none",
152 Self::PerKey => "per_key",
153 Self::Global => "global",
154 };
155 f.write_str(value)
156 }
157}