use std::any::TypeId;
use std::collections::HashMap;
use std::error::Error;
use std::fmt::Debug;
use std::future::Future;
use std::task::{Context, Poll};
use lambda_runtime::{Error as LambdaError, LambdaEvent};
use serde::Serialize;
use serde_json::Value;
use tower::Service;
use crate::events::{
AwsEvent, AwsEventHandler, Callable, LambdaFuture, S3Event, SnsEvent, SqsEvent,
};
fn get_event_key(
event: LambdaEvent<Value>,
) -> Result<(TypeId, String), Box<dyn Error + Send + Sync>> {
if let Ok(parsed_event) = S3Event::from_request(&event.payload) {
return Ok((TypeId::of::<S3Event>(), parsed_event.event_name()));
}
if let Ok(parsed_event) = SnsEvent::from_request(&event.payload) {
return Ok((TypeId::of::<SnsEvent>(), parsed_event.event_name()));
}
if let Ok(parsed_event) = SqsEvent::from_request(&event.payload) {
return Ok((TypeId::of::<SqsEvent>(), parsed_event.event_name()));
}
Err("Failed to parse event".into())
}
pub struct LambdaHandler<R>
where
R: Debug + Serialize + 'static,
{
handlers: HashMap<(TypeId, String), Box<dyn Callable<R>>>,
}
impl<R: Debug + Serialize> LambdaHandler<R> {
pub fn new() -> Self {
LambdaHandler {
handlers: HashMap::new(),
}
}
pub fn route<E, F, Fut>(mut self, event_name: &str, handler: F) -> Self
where
E: AwsEvent + 'static,
F: Fn(LambdaEvent<E>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<R, LambdaError>> + Send + 'static,
{
let boxed_event_handler = Box::new(AwsEventHandler::new(Box::new(move |event| {
Box::pin(handler(event)) as LambdaFuture<R>
})));
self.handlers.insert(
(TypeId::of::<E>(), event_name.to_string()),
boxed_event_handler,
);
self
}
}
impl<R: Debug + Serialize> Default for LambdaHandler<R> {
fn default() -> Self {
Self::new()
}
}
impl<R: Debug + Serialize> Service<LambdaEvent<Value>> for LambdaHandler<R> {
type Response = R;
type Error = LambdaError;
type Future = LambdaFuture<R>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: LambdaEvent<Value>) -> Self::Future {
let cloned_request = req.clone();
let event_key = get_event_key(cloned_request);
match event_key {
Ok(key) => {
if let Some(handler) = self.handlers.get(&key) {
handler.call(req)
} else {
Box::pin(async {
Err(LambdaError::from("I don't have a handler for this event!"))
})
}
}
Err(_) => {
Box::pin(async { Err(LambdaError::from("Unable to get event type or name!")) })
}
}
}
}