Skip to main content

coreon_yaml/
schema.rs

1//! Serde types for the camel-rs YAML DSL.
2//!
3//! Each YAML step is a single-key map like `{ filter: { body_contains: ... } }`.
4//! We express that with `#[serde(untagged)]` enums whose struct variants have
5//! a single required field matching the YAML key. Untagged dispatch is
6//! unambiguous because the field names are distinct.
7
8use serde::Deserialize;
9
10#[derive(Debug, Deserialize)]
11pub struct Document {
12    pub routes: Vec<RouteSpec>,
13}
14
15#[derive(Debug, Deserialize)]
16pub struct RouteSpec {
17    pub id: String,
18    pub from: String,
19    #[serde(default)]
20    pub steps: Vec<Step>,
21}
22
23#[derive(Debug, Deserialize)]
24#[serde(untagged, deny_unknown_fields)]
25pub enum Step {
26    To { to: String },
27    WireTap { wire_tap: String },
28    Filter { filter: PredicateSpec },
29    Transform { transform: TransformSpec },
30    Delay { delay: DelaySpec },
31    Throttle { throttle: ThrottleSpec },
32    Multicast { multicast: Vec<String> },
33    Split { split: SplitSpec },
34    Choice { choice: ChoiceSpec },
35    RecipientList { recipient_list: RecipientListSpec },
36    LoadBalance { load_balance: LoadBalanceSpec },
37    Idempotent { idempotent: IdempotentSpec },
38    OnException { on_exception: OnExceptionSpec },
39}
40
41#[derive(Debug, Deserialize)]
42#[serde(untagged, deny_unknown_fields)]
43pub enum PredicateSpec {
44    BodyContains { body_contains: String },
45    BodyStartsWith { body_starts_with: String },
46    HeaderEquals { header_equals: HeaderEq },
47    HeaderPresent { header_present: String },
48}
49
50#[derive(Debug, Deserialize)]
51pub struct HeaderEq {
52    pub name: String,
53    pub value: String,
54}
55
56#[derive(Debug, Deserialize)]
57#[serde(untagged, deny_unknown_fields)]
58pub enum TransformSpec {
59    Upper { upper: bool },
60    Lower { lower: bool },
61    Prepend { prepend: String },
62    Append { append: String },
63}
64
65#[derive(Debug, Deserialize)]
66pub struct DelaySpec {
67    pub millis: u64,
68}
69
70#[derive(Debug, Deserialize)]
71pub struct ThrottleSpec {
72    pub max: u32,
73    pub period_millis: u64,
74}
75
76#[derive(Debug, Deserialize)]
77pub struct SplitSpec {
78    #[serde(default = "default_split_on")]
79    pub on: char,
80    #[serde(default)]
81    pub then: Vec<Step>,
82}
83
84fn default_split_on() -> char {
85    ','
86}
87
88#[derive(Debug, Deserialize)]
89pub struct ChoiceSpec {
90    #[serde(default)]
91    pub when: Vec<WhenSpec>,
92    #[serde(default)]
93    pub otherwise: Vec<Step>,
94}
95
96#[derive(Debug, Deserialize)]
97pub struct WhenSpec {
98    pub predicate: PredicateSpec,
99    #[serde(default)]
100    pub then: Vec<Step>,
101}
102
103#[derive(Debug, Deserialize)]
104pub struct RecipientListSpec {
105    pub from_header: String,
106    #[serde(default = "default_rl_separator")]
107    pub separator: String,
108}
109
110fn default_rl_separator() -> String {
111    ",".to_owned()
112}
113
114#[derive(Debug, Deserialize)]
115pub struct LoadBalanceSpec {
116    pub strategy: LoadBalanceStrategy,
117    pub to: Vec<String>,
118}
119
120#[derive(Debug, Deserialize)]
121#[serde(rename_all = "lowercase")]
122pub enum LoadBalanceStrategy {
123    #[serde(alias = "round_robin", alias = "roundrobin")]
124    RoundRobin,
125    Failover,
126}
127
128#[derive(Debug, Deserialize)]
129#[serde(untagged, deny_unknown_fields)]
130pub enum IdempotentSpec {
131    ByBody { by_body: bool },
132    ByHeader { by_header: String },
133}
134
135#[derive(Debug, Deserialize)]
136pub struct OnExceptionSpec {
137    pub max_redeliveries: u32,
138    #[serde(default)]
139    pub backoff_millis: u64,
140    #[serde(default = "default_backoff_multiplier")]
141    pub backoff_multiplier: f64,
142    #[serde(default)]
143    pub dead_letter: Option<String>,
144}
145
146fn default_backoff_multiplier() -> f64 {
147    2.0
148}