1
1
use aws_lambda_events:: event:: s3:: { S3Entity , S3Event } ;
2
+ use aws_lambda_events:: sqs:: SqsEvent ;
2
3
use aws_sdk_s3:: Client as S3Client ;
3
4
use lambda_runtime:: { run, service_fn, Error , LambdaEvent } ;
4
5
use routefinder:: Router ;
5
6
use tracing:: log:: * ;
6
7
7
8
use std:: collections:: HashMap ;
8
9
9
- async fn function_handler ( event : LambdaEvent < S3Event > , client : & S3Client ) -> Result < ( ) , Error > {
10
+ /// A simple structure to make deserializing test events for identification easier
11
+ ///
12
+ /// See <fhttps://github.com/buoyant-data/oxbow/issues/8>
13
+ #[ derive( serde:: Deserialize ) ]
14
+ #[ serde( rename_all = "PascalCase" ) ]
15
+ struct TestEvent {
16
+ event : String ,
17
+ }
18
+
19
+ /// Convert the given [aws_lambda_events::sqs::SqsEvent] to a collection of
20
+ /// [aws_lambda_events::s3::S3EventRecord] entities. This is mostly useful for handling S3 Bucket
21
+ /// Notifications which have been passed into SQS
22
+ ///
23
+ /// In the case where the [aws_lambda_events::sqs::SqsEvent] contains an `s3:TestEvent` which is
24
+ /// fired when S3 Bucket Notifications are first enabled, the event will be ignored to avoid
25
+ /// errorsin the processing pipeline
26
+ fn s3_from_sqs ( event : SqsEvent ) -> Result < S3Event , anyhow:: Error > {
27
+ let mut records = vec ! [ ] ;
28
+ for record in event. records . iter ( ) {
29
+ /* each record is an SqsMessage */
30
+ if let Some ( body) = & record. body {
31
+ match serde_json:: from_str :: < S3Event > ( body) {
32
+ Ok ( s3event) => {
33
+ for s3record in s3event. records {
34
+ records. push ( s3record. clone ( ) ) ;
35
+ }
36
+ }
37
+ Err ( err) => {
38
+ // if we cannot deserialize and the event is an s3::TestEvent, then we should
39
+ // just return empty records.
40
+ let test_event = serde_json:: from_str :: < TestEvent > ( body) ;
41
+ // Early exit with the original error if we cannot parse the JSON at all
42
+ if test_event. is_err ( ) {
43
+ return Err ( err. into ( ) ) ;
44
+ }
45
+
46
+ // Ignore the error on deserialization if the event ends up being an S3
47
+ // TestEvent which is fired when bucket notifications are originally configured
48
+ if "s3:TestEvent" != test_event. unwrap ( ) . event {
49
+ return Err ( err. into ( ) ) ;
50
+ }
51
+ }
52
+ } ;
53
+ }
54
+ }
55
+ Ok ( aws_lambda_events:: s3:: S3Event { records } )
56
+ }
57
+
58
+ async fn function_handler (
59
+ event : LambdaEvent < serde_json:: Value > ,
60
+ client : & S3Client ,
61
+ ) -> Result < ( ) , Error > {
10
62
let input_pattern =
11
63
std:: env:: var ( "INPUT_PATTERN" ) . expect ( "You must define INPUT_PATTERN in the environment" ) ;
12
64
let output_template = std:: env:: var ( "OUTPUT_TEMPLATE" )
@@ -18,9 +70,13 @@ async fn function_handler(event: LambdaEvent<S3Event>, client: &S3Client) -> Res
18
70
. parse ( & output_template) ?;
19
71
20
72
router. add ( input_pattern, 1 ) ?;
21
- info ! ( "Processing records: {event:?}" ) ;
22
73
23
- for entity in entities_from ( event. payload ) ? {
74
+ let records = match serde_json:: from_value :: < SqsEvent > ( event. payload . clone ( ) ) {
75
+ Ok ( sqs_event) => s3_from_sqs ( sqs_event) ?,
76
+ Err ( _) => serde_json:: from_value ( event. payload ) ?,
77
+ } ;
78
+
79
+ for entity in entities_from ( records) ? {
24
80
debug ! ( "Processing {entity:?}" ) ;
25
81
26
82
if let Some ( source_key) = entity. object . key {
@@ -62,13 +118,10 @@ async fn main() -> Result<(), Error> {
62
118
run ( func) . await
63
119
}
64
120
65
- /**
66
- * Return the deserialized and useful objects from the event payload
67
- *
68
- * This function will apply a filter to make sure that it is only return objects which have been
69
- * put in this invocation
70
- */
71
-
121
+ /// Return the deserialized and useful objects from the event payload
122
+ ///
123
+ /// This function will apply a filter to make sure that it is only return objects which have been
124
+ /// put in this invocation
72
125
fn entities_from ( event : S3Event ) -> Result < Vec < S3Entity > , anyhow:: Error > {
73
126
Ok ( event
74
127
. records
@@ -79,10 +132,8 @@ fn entities_from(event: S3Event) -> Result<Vec<S3Entity>, anyhow::Error> {
79
132
. collect ( ) )
80
133
}
81
134
82
- /**
83
- * Take the source key and the already configured router in order to access a collection of
84
- * captured parameters in a HashMap format
85
- */
135
+ /// Take the source key and the already configured router in order to access a collection of
136
+ /// captured parameters in a HashMap format
86
137
fn captured_parameters < Handler > (
87
138
router : & Router < Handler > ,
88
139
source_key : & str ,
0 commit comments