use crate::{ types::{Form, Value}, upload::handle_multipart, }; use actix_web::{dev::Payload, FromRequest, HttpRequest, ResponseError}; use std::{future::Future, pin::Pin, rc::Rc}; pub trait FormData { type Item: 'static; type Error: ResponseError + 'static; fn form(req: &HttpRequest) -> Result, Self::Error>; fn extract(value: Value) -> Result where Self: Sized; } pub struct Multipart(pub T); impl FromRequest for Multipart where T: FormData, { type Error = actix_web::Error; type Future = Pin> + 'static>>; fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { let multipart = actix_multipart::Multipart::new(req.headers(), payload.take()); let res = T::form(req); Box::pin(async move { let form = Rc::new(res?); let uploaded = match handle_multipart(multipart, Rc::clone(&form)).await { Ok(Ok(uploaded)) => uploaded, Ok(Err(e)) => return Err(e.into()), Err(e) => { if let Some(f) = &form.transform_error { return Err((f)(e)); } else { return Err(e.into()); } } }; Ok(Multipart(T::extract(uploaded)?)) }) } }