dioxus_fullstack/payloads/
multipart.rs1#![allow(unreachable_code)]
2
3use crate::{ClientRequest, ClientResponse, IntoRequest};
4use axum::{
5 extract::{FromRequest, Request},
6 response::{IntoResponse, Response},
7};
8use dioxus_fullstack_core::RequestError;
9use dioxus_html::{FormData, FormEvent};
10use std::{prelude::rust_2024::Future, rc::Rc};
11
12#[cfg(feature = "server")]
13use axum::extract::multipart::{Field, MultipartError};
14
15pub struct MultipartFormData<T = ()> {
44 #[cfg(feature = "server")]
45 form: Option<axum::extract::Multipart>,
46
47 _client: Option<Rc<FormData>>,
48
49 _phantom: std::marker::PhantomData<T>,
50}
51
52impl MultipartFormData {
53 #[cfg(feature = "server")]
54 pub async fn next_field(&mut self) -> Result<Option<Field<'_>>, MultipartError> {
55 if let Some(form) = &mut self.form {
56 form.next_field().await
57 } else {
58 Ok(None)
59 }
60 }
61}
62
63impl<S> IntoRequest for MultipartFormData<S> {
64 fn into_request(
65 self,
66 _req: ClientRequest,
67 ) -> impl Future<Output = Result<ClientResponse, RequestError>> + 'static {
68 async move {
69 #[cfg(feature = "web")]
73 if cfg!(target_arch = "wasm32") {
74 let data = self._client.clone().ok_or_else(|| {
75 RequestError::Builder("Failed to get FormData from event".into())
76 })?;
77
78 fn get_form_data(data: Rc<FormData>) -> Option<wasm_bindgen::JsValue> {
79 use wasm_bindgen::JsCast;
80 let event: &web_sys::Event = data.downcast()?;
81 let target = event.target()?;
82 let form: &web_sys::HtmlFormElement = target.dyn_ref()?;
83 let data: web_sys::FormData = web_sys::FormData::new_with_form(form).ok()?;
84 Some(data.into())
85 }
86
87 let js_form_data = get_form_data(data).ok_or_else(|| {
88 RequestError::Builder("Failed to get FormData from event".into())
89 })?;
90
91 return _req.send_js_value(js_form_data).await;
92 }
93
94 #[cfg(not(target_arch = "wasm32"))]
97 {
98 let data = self._client.clone().ok_or_else(|| {
99 RequestError::Builder("Failed to get FormData from event".into())
100 })?;
101
102 return _req.send_multipart(&data).await;
103 }
104
105 unimplemented!("Non web wasm32 clients are not supported yet")
106 }
107 }
108}
109impl<S: Send + Sync + 'static, D> FromRequest<S> for MultipartFormData<D> {
110 type Rejection = Response;
111
112 #[doc = " Perform the extraction."]
113 fn from_request(
114 req: Request,
115 state: &S,
116 ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send {
117 #[cfg(feature = "server")]
118 return async move {
119 let form = axum::extract::multipart::Multipart::from_request(req, state)
120 .await
121 .map_err(|err| err.into_response())?;
122
123 Ok(MultipartFormData {
124 form: Some(form),
125 _client: None,
126 _phantom: std::marker::PhantomData,
127 })
128 };
129
130 #[cfg(not(feature = "server"))]
131 async {
132 use dioxus_fullstack_core::HttpError;
133
134 let _ = req;
135 let _ = state;
136 Err(HttpError::new(
137 http::StatusCode::INTERNAL_SERVER_ERROR,
138 "MultipartFormData extractor is not supported on non-server builds",
139 )
140 .into_response())
141 }
142 }
143}
144
145impl<T> From<Rc<FormData>> for MultipartFormData<T> {
146 fn from(_value: Rc<FormData>) -> Self {
147 MultipartFormData {
148 #[cfg(feature = "server")]
149 form: None,
150 _client: Some(_value),
151 _phantom: std::marker::PhantomData,
152 }
153 }
154}
155
156impl<T> From<FormEvent> for MultipartFormData<T> {
157 fn from(event: FormEvent) -> Self {
158 let data = event.data();
159 MultipartFormData {
160 #[cfg(feature = "server")]
161 form: None,
162 _client: Some(data),
163 _phantom: std::marker::PhantomData,
164 }
165 }
166}
167
168unsafe impl Send for MultipartFormData {}
169unsafe impl Sync for MultipartFormData {}