1use std::marker::PhantomData;
2use serde_json::Value;
3use crate::events::{FlexibleTimeWindow, RetryPolicy, Schedule, ScheduleProperties, ScheduleRef, ScheduleType, Target};
4use crate::iam::RoleRef;
5use crate::lambda::FunctionRef;
6use crate::shared::Id;
7use crate::sns::TopicRef;
8use crate::sqs::QueueRef;
9use crate::stack::{Resource, StackBuilder};
10use crate::type_state;
11use crate::wrappers::{MaxFlexibleTimeWindow, RetryPolicyEventAge, RetryPolicyRetries, ScheduleAtExpression, ScheduleCronExpression, ScheduleName, ScheduleRateExpression};
12
13type_state!(
14 ScheduleBuilderState,
15 StartState,
16 OneTimeScheduleState,
17 RepeatedScheduleState,
18);
19
20#[derive(Debug)]
21pub enum State {
22 Enabled,
23 Disabled,
24}
25
26impl From<State> for String {
27 fn from(value: State) -> String {
28 match value {
29 State::Enabled => "ENABLED".to_string(),
30 State::Disabled => "DISABLED".to_string(),
31 }
32 }
33}
34
35pub struct ScheduleBuilder<T: ScheduleBuilderState> {
36 phantom_data: PhantomData<T>,
37 id: Id,
38 start_date: Option<String>,
39 end_date: Option<String>,
40 flexible_time_window: FlexibleTimeWindow,
41 group_name: Option<String>,
42 name: Option<String>,
43 state: Option<String>,
44 schedule_expression: Option<String>,
45 target: Target
46}
47
48impl<T: ScheduleBuilderState> ScheduleBuilder<T> {
49 pub fn name(self, name: ScheduleName) -> Self {
50 Self {
51 name: Some(name.0),
52 ..self
53 }
54 }
55
56 pub fn group_name(self, group_name: ScheduleName) -> Self {
57 Self {
58 group_name: Some(group_name.0),
59 ..self
60 }
61 }
62
63 pub fn state(self, state: State) -> Self {
64 Self {
65 state: Some(state.into()),
66 ..self
67 }
68 }
69
70 fn build_internal(self, stack_builder: &mut StackBuilder) -> ScheduleRef {
71 let resource_id = Resource::generate_id("Schedule");
72 stack_builder.add_resource(Schedule {
73 id: self.id,
74 resource_id: resource_id.clone(),
75 r#type: ScheduleType::ScheduleType,
76 properties: ScheduleProperties {
77 start_date: self.start_date,
78 end_date: self.end_date,
79 flexible_time_window: self.flexible_time_window,
80 group_name: self.group_name,
81 name: self.name,
82 state: self.state,
83 schedule_expression: self.schedule_expression.expect("schedule expression to be present, enforced by builder"),
84 target: self.target,
85 },
86 });
87
88 ScheduleRef::internal_new(resource_id)
89 }
90}
91
92impl ScheduleBuilder<StartState> {
93 pub fn new(id: &str, target: Target, flexible_time_window: FlexibleTimeWindow) -> ScheduleBuilder<StartState> {
94 ScheduleBuilder {
95 phantom_data: Default::default(),
96 id: Id(id.to_string()),
97 flexible_time_window,
98 target,
99 start_date: None,
100 end_date: None,
101 group_name: None,
102 name: None,
103 state: None,
104 schedule_expression: None,
105 }
106 }
107
108 pub fn one_time_schedule(self, expression: ScheduleAtExpression) -> ScheduleBuilder<OneTimeScheduleState> {
109 let one_time_schedule = format!("at({})", expression.0);
110 ScheduleBuilder {
111 phantom_data: Default::default(),
112 schedule_expression: Some(one_time_schedule),
113 id: self.id,
114 flexible_time_window: self.flexible_time_window,
115 group_name: self.group_name,
116 name: self.name,
117 state: self.state,
118 target: self.target,
119 start_date: None,
120 end_date: None,
121 }
122 }
123
124 pub fn rate_schedule(self, expression: ScheduleRateExpression) -> ScheduleBuilder<RepeatedScheduleState> {
125 let rate = format!("rate({} {})", expression.0, expression.1);
126 ScheduleBuilder {
127 phantom_data: Default::default(),
128 schedule_expression: Some(rate),
129 id: self.id,
130 flexible_time_window: self.flexible_time_window,
131 group_name: self.group_name,
132 name: self.name,
133 state: self.state,
134 target: self.target,
135 start_date: self.start_date,
136 end_date: self.end_date,
137 }
138 }
139
140 pub fn cron_schedule(self, expression: ScheduleCronExpression) -> ScheduleBuilder<RepeatedScheduleState> {
141 let schedule = format!("cron({})", expression.0);
142 ScheduleBuilder {
143 phantom_data: Default::default(),
144 schedule_expression: Some(schedule),
145 id: self.id,
146 flexible_time_window: self.flexible_time_window,
147 group_name: self.group_name,
148 name: self.name,
149 state: self.state,
150 target: self.target,
151 start_date: self.start_date,
152 end_date: self.end_date,
153 }
154 }
155}
156
157impl ScheduleBuilder<OneTimeScheduleState> {
158 pub fn build(self, stack_builder: &mut StackBuilder) -> ScheduleRef {
159 self.build_internal(stack_builder)
160 }
161}
162
163impl ScheduleBuilder<RepeatedScheduleState> {
164 pub fn start_date(self, start_date: String) -> Self {
166 Self {
167 start_date: Some(start_date),
168 ..self
169 }
170 }
171
172 pub fn end_date(self, end_date: String) -> Self {
174 Self {
175 end_date: Some(end_date),
176 ..self
177 }
178 }
179
180 pub fn build(self, stack_builder: &mut StackBuilder) -> ScheduleRef {
181 self.build_internal(stack_builder)
182 }
183}
184
185type_state!(
186 TargetBuilderState,
187 TargetStartState,
188 JsonTargetState,
189 NormalTargetState,
190);
191
192pub struct TargetBuilder<T: TargetBuilderState> {
193 phantom_data: PhantomData<T>,
194 target_arn: Value,
195 role_arn: Value,
196 input: Option<String>,
197 retry_policy: Option<RetryPolicy>,
198}
199
200pub enum JsonTarget<'a> {
201 Lambda(&'a FunctionRef)
202 }
205
206pub enum NormalTarget<'a> {
207 Sqs(&'a QueueRef),
208 Sns(&'a TopicRef),
209 Other(Value)
210}
211
212impl TargetBuilder<TargetStartState> {
213 pub fn new_normal_target(target: NormalTarget, schedule_role: &RoleRef) -> TargetBuilder<NormalTargetState> {
215 let arn = match target {
216 NormalTarget::Sqs(r) => r.get_arn(),
217 NormalTarget::Sns(r) => r.get_arn(),
218 NormalTarget::Other(r) => r,
219 };
220 TargetBuilder {
221 phantom_data: Default::default(),
222 target_arn: arn,
223 role_arn: schedule_role.get_arn(),
224 input: None,
225 retry_policy: None,
226 }
227 }
228
229 pub fn new_json_target(target: JsonTarget, schedule_role: &RoleRef) -> TargetBuilder<JsonTargetState> {
234 let target_arn = match target {
235 JsonTarget::Lambda(l) => l.get_arn(),
236 };
237 TargetBuilder {
238 phantom_data: Default::default(),
239 target_arn,
240 role_arn: schedule_role.get_arn(),
241 input: None,
242 retry_policy: None,
243 }
244 }
245}
246
247impl<T: TargetBuilderState> TargetBuilder<T> {
248 pub fn retry_policy(self, retry_policy: RetryPolicy) -> TargetBuilder<T> {
249 TargetBuilder {
250 retry_policy: Some(retry_policy),
251 phantom_data: Default::default(),
252 target_arn: self.target_arn,
253 role_arn: self.role_arn,
254 input: self.input,
255 }
256 }
257
258 pub fn build(self) -> Target {
259 Target {
260 arn: self.target_arn,
261 role_arn: self.role_arn,
262 input: self.input,
263 retry_policy: self.retry_policy,
264 }
265 }
266}
267
268impl TargetBuilder<NormalTargetState> {
269 pub fn input(self, input: String) -> Self {
270 Self {
271 input: Some(input),
272 ..self
273 }
274 }
275}
276
277impl TargetBuilder<JsonTargetState> {
278 pub fn input(self, input: Value) -> Self {
279 Self {
280 input: Some(input.to_string()),
281 ..self
282 }
283 }
284}
285
286pub enum Mode {
287 Off,
288 Flexible(MaxFlexibleTimeWindow)
289}
290
291pub struct FlexibleTimeWindowBuilder {
292 maximum_window_in_minutes: Option<u16>,
293 mode: String,
294}
295
296impl FlexibleTimeWindowBuilder {
297 pub fn new(mode: Mode) -> Self {
298 match mode {
299 Mode::Off => {
300 Self {
301 maximum_window_in_minutes: None,
302 mode: "OFF".to_string(),
303 }
304 }
305 Mode::Flexible(max) => {
306 Self {
307 maximum_window_in_minutes: Some(max.0),
308 mode: "FLEXIBLE".to_string(),
309 }
310 }
311 }
312 }
313
314 pub fn build(self) -> FlexibleTimeWindow {
315 FlexibleTimeWindow {
316 maximum_window_in_minutes: self.maximum_window_in_minutes,
317 mode: self.mode,
318 }
319 }
320}
321
322pub struct RetryPolicyBuilder {
323 maximum_event_age_in_seconds: Option<u32>,
324 maximum_retry_attempts: Option<u8>
325}
326
327impl RetryPolicyBuilder {
328 pub fn new() -> Self {
329 Self {
330 maximum_event_age_in_seconds: None,
331 maximum_retry_attempts: None,
332 }
333 }
334
335 pub fn maximum_event_age_in_seconds(self, maximum_event_age_in_seconds: RetryPolicyEventAge) -> Self {
336 Self {
337 maximum_event_age_in_seconds: Some(maximum_event_age_in_seconds.0),
338 ..self
339 }
340 }
341
342 pub fn maximum_retry_attempts(self, maximum_retry_attempts: RetryPolicyRetries) -> Self {
343 Self {
344 maximum_retry_attempts: Some(maximum_retry_attempts.0),
345 ..self
346 }
347 }
348
349 pub fn build(self) -> RetryPolicy {
350 RetryPolicy {
351 maximum_event_age_in_seconds: self.maximum_event_age_in_seconds,
352 maximum_retry_attempts: self.maximum_retry_attempts,
353 }
354 }
355}