server_fn/codec/
multipart.rs1use super::{Encoding, FromReq};
2use crate::{
3 error::{FromServerFnError, ServerFnErrorWrapper},
4 request::{browser::BrowserFormData, ClientReq, Req},
5 ContentType, IntoReq,
6};
7use futures::StreamExt;
8use http::Method;
9use multer::Multipart;
10use web_sys::FormData;
11
12pub struct MultipartFormData;
16
17impl ContentType for MultipartFormData {
18 const CONTENT_TYPE: &'static str = "multipart/form-data";
19}
20
21impl Encoding for MultipartFormData {
22 const METHOD: Method = Method::POST;
23}
24
25#[derive(Debug)]
27pub enum MultipartData {
28 Client(BrowserFormData),
30 Server(multer::Multipart<'static>),
32}
33
34impl MultipartData {
35 pub fn into_inner(self) -> Option<Multipart<'static>> {
39 match self {
40 MultipartData::Client(_) => None,
41 MultipartData::Server(data) => Some(data),
42 }
43 }
44
45 pub fn into_client_data(self) -> Option<BrowserFormData> {
49 match self {
50 MultipartData::Client(data) => Some(data),
51 MultipartData::Server(_) => None,
52 }
53 }
54}
55
56impl From<FormData> for MultipartData {
57 fn from(value: FormData) -> Self {
58 MultipartData::Client(value.into())
59 }
60}
61
62impl<E: FromServerFnError, T, Request> IntoReq<MultipartFormData, Request, E>
63 for T
64where
65 Request: ClientReq<E, FormData = BrowserFormData>,
66 T: Into<MultipartData>,
67{
68 fn into_req(self, path: &str, accepts: &str) -> Result<Request, E> {
69 let multi = self.into();
70 Request::try_new_post_multipart(
71 path,
72 accepts,
73 multi.into_client_data().unwrap(),
74 )
75 }
76}
77
78impl<E, T, Request> FromReq<MultipartFormData, Request, E> for T
79where
80 Request: Req<E> + Send + 'static,
81 T: From<MultipartData>,
82 E: FromServerFnError + Send + Sync,
83{
84 async fn from_req(req: Request) -> Result<Self, E> {
85 let boundary = req
86 .to_content_type()
87 .and_then(|ct| multer::parse_boundary(ct).ok())
88 .expect("couldn't parse boundary");
89 let stream = req.try_into_stream()?;
90 let data = multer::Multipart::new(
91 stream.map(|data| data.map_err(|e| ServerFnErrorWrapper(E::de(e)))),
92 boundary,
93 );
94 Ok(MultipartData::Server(data).into())
95 }
96}