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