use std::marker::PhantomData;
use std::pin::Pin;
use std::{fmt::Debug, future::Future};
use lambda_runtime::{Error as LambdaError, LambdaEvent};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::Value;
pub use aws_lambda_events::{s3::S3Event, sns::SnsEvent, sqs::SqsEvent};
pub trait AwsEvent: Send + Sync + Sized + DeserializeOwned {
fn from_request(request: &Value) -> Result<Self, serde_json::Error> {
serde_json::from_value(request.clone())
}
fn from_event(event: LambdaEvent<Value>) -> Result<LambdaEvent<Self>, serde_json::Error> {
let deserialised: Self = Self::from_request(&event.payload)?;
Ok(LambdaEvent {
payload: deserialised,
context: event.context,
})
}
fn event_name(&self) -> String;
}
impl AwsEvent for S3Event {
fn event_name(&self) -> String {
self.records[0].event_name.clone().expect("No event name!")
}
}
impl AwsEvent for SnsEvent {
fn event_name(&self) -> String {
self.records[0].sns.topic_arn.clone()
}
}
impl AwsEvent for SqsEvent {
fn event_name(&self) -> String {
self.records[0]
.event_source_arn
.clone()
.expect("No topic ARN!")
}
}
pub type LambdaFuture<R> = Pin<Box<dyn Future<Output = Result<R, LambdaError>> + Send>>;
pub type LambdaFn<R> = Box<dyn Fn(LambdaEvent<Box<dyn AwsEvent>>) -> LambdaFuture<R> + Send + Sync>;
pub trait Callable<R> {
fn call(&self, event: LambdaEvent<Value>) -> LambdaFuture<R>;
}
pub struct AwsEventHandler<T, R>
where
T: AwsEvent,
R: Debug + Serialize,
{
event_type: PhantomData<T>, handler: Box<dyn Fn(LambdaEvent<T>) -> LambdaFuture<R> + Send + Sync>, }
impl<T: AwsEvent, R: Debug + Serialize> AwsEventHandler<T, R> {
pub fn new(handler: Box<dyn Fn(LambdaEvent<T>) -> LambdaFuture<R> + Send + Sync>) -> Self {
AwsEventHandler {
event_type: PhantomData,
handler,
}
}
}
impl<T: AwsEvent, R: Debug + Serialize> Callable<R> for AwsEventHandler<T, R> {
fn call(&self, event: LambdaEvent<Value>) -> LambdaFuture<R> {
let res = T::from_event(event);
match res {
Ok(converted_event) => (self.handler)(converted_event),
Err(_) => Box::pin(async { Err(LambdaError::from("Failed to process event!")) }),
}
}
}