Rust_wasm/rs/xmlHttpRequest/
xmlHttpPostRequest.rs1use std::collections::HashMap;
2
3use js_sys::Uint8Array;
4use wasm_bindgen::{prelude::Closure, JsCast, JsValue};
5use web_sys::{Blob, ErrorEvent, FormData, ProgressEvent, XmlHttpRequest, XmlHttpRequestResponseType};
6use crate::log;
7
8enum PostRequestContent {
9 Form(FormData),
10 Blob(Blob),
11}
12
13pub struct PostRequest {
14 upload_onabort: Option<JsValue>,
15 upload_onerror: Option<JsValue>,
16 upload_onload: Option<JsValue>,
17 upload_onloadend: Option<JsValue>,
18 upload_onloadstart: Option<JsValue>,
19 upload_on_progress: Option<JsValue>,
20 upload_ontimeout: Option<JsValue>,
21 request_onabort: Option<JsValue>,
22 request_onerror: Option<JsValue>,
23 request_onload: Option<JsValue>,
24 request_onloadend: Option<JsValue>,
25 request_onloadstart: Option<JsValue>,
26 request_on_progress: Option<JsValue>,
27 request_ontimeout: Option<JsValue>,
28 _async: bool,
29 content: Option<PostRequestContent>,
30 headers: HashMap<String, String>,
31}
32
33impl PostRequest {
34 pub fn new_from_default()->Self {
57 PostRequest {
58 ..Default::default()
59 }
60 }
61
62 pub fn new_from_blob(blob: Vec<u8>, mime_type: &str) -> Self {
63 let uint8arr: Uint8Array = blob.as_slice().into();
64 let blob = Blob::new_with_u8_array_sequence_and_options(
65 &uint8arr,
66 web_sys::BlobPropertyBag::new().type_(mime_type),
67 )
68 .unwrap();
69 PostRequest {
70 content: Some(PostRequestContent::Blob(blob)),
71 ..Default::default()
72 }
73 }
74
75 pub fn set_upload_onabort(&mut self, closure: Option<Box<dyn Fn()>>) {
76 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
77 self.upload_onabort = callback;
78 }
79
80 pub fn set_upload_onerror(&mut self, closure: Option<Box<dyn Fn(ErrorEvent)>>) {
81 let callback = closure.map(|c| Closure::<dyn Fn(ErrorEvent)>::wrap(c).into_js_value());
82 self.upload_onerror = callback;
83 }
84
85 pub fn set_upload_onload(&mut self, closure: Option<Box<dyn Fn(ProgressEvent)>>) {
86 let callback = closure.map(|c| Closure::<dyn Fn(ProgressEvent)>::wrap(c).into_js_value());
87 self.upload_onload = callback;
88 }
89
90 pub fn set_upload_onloadstart(&mut self, closure: Option<Box<dyn Fn()>>) {
91 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
92 self.upload_onloadstart = callback;
93 }
94
95 pub fn set_upload_onloadend(&mut self, closure: Option<Box<dyn Fn()>>) {
96 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
97 self.upload_onloadend = callback;
98 }
99
100 pub fn set_upload_onprogress(&mut self, closure: Option<Box<dyn Fn(ProgressEvent)>>) {
101 let callback = closure.map(|c| Closure::<dyn Fn(ProgressEvent)>::wrap(c).into_js_value());
102 self.upload_on_progress = callback;
103 }
104
105 pub fn set_request_onabort(&mut self, closure: Option<Box<dyn Fn()>>) {
106 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
107 self.request_onabort = callback;
108 }
109
110 pub fn set_request_onerror(&mut self, fun:Option<JsValue>) {
111 self.request_onerror = fun;
113 }
114
115 pub fn set_request_onload(&mut self, fun:Option<JsValue>) {
116 self.request_onload = fun;
118 }
119
120 pub fn set_request_onloadstart(&mut self, closure: Option<Box<dyn Fn()>>) {
121 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
122 self.request_onloadstart = callback;
123 }
124
125 pub fn set_request_onloadend(&mut self, closure: Option<Box<dyn Fn()>>) {
126 let callback = closure.map(|c| Closure::<dyn Fn()>::wrap(c).into_js_value());
127 self.request_onloadstart = callback;
128 }
129
130 pub fn set_request_onprogress(&mut self, closure: Option<Box<dyn Fn(ProgressEvent)>>) {
131 let callback = closure.map(|c| Closure::<dyn Fn(ProgressEvent)>::wrap(c).into_js_value());
132 self.request_on_progress = callback;
133 }
134
135 pub fn set_async(&mut self, _async: bool) {
136 self._async = _async;
137 }
138
139 pub fn send(self, url: &str) -> Result<SendRequest, JsValue> {
140 let request = self.get_request(url);
141 self.set_request_callbacks(&request);
143
144 self.set_headers(&request)?;
145
146 let result: SendRequest = self.send_request(request)?.into();
147 Ok(result)
148 }
149
150 pub fn set_header(&mut self, header: String, value: String) {
151 self.headers.insert(header, value);
152 }
153
154 fn send_request(self, request: XmlHttpRequest) -> Result<XmlHttpRequest, JsValue> {
155 let result = match &self.content {
156 Some(content) => match content {
157 PostRequestContent::Form(form) => request.send_with_opt_form_data(Some(form)),
158 PostRequestContent::Blob(blob) => request.send_with_opt_blob(Some(blob)),
159 },
160 None => request.send(),
161 };
162
163 match result {
164 Ok(_) => Ok(request),
165 Err(error) => Err(error),
166 }
167 }
168
169 fn get_request(&self, url: &str) -> XmlHttpRequest {
170 let request = XmlHttpRequest::new().expect("Could not create request!");
171 request
172 .open_with_async("GET", url, self._async)
173 .expect("Could not open request");
174 request
175 }
176
177 fn set_request_callbacks(&self, request: &XmlHttpRequest) {
178 log!("set_request_callbacks");
179 if let Some(callback) = &self.request_onabort {
180 request.set_onabort(Some(callback.as_ref().unchecked_ref()));
181 }
182 if let Some(callback) = &self.request_onerror {
183 request.set_onerror(Some(callback.as_ref().unchecked_ref()));
184 }
185 if let Some(callback) = &self.request_onload {
186 log!("Request onload{:?}", request);
187 request.set_onload(Some(callback.as_ref().unchecked_ref()));
188 }
189 if let Some(callback) = &self.request_onloadend {
190 request.set_onloadend(Some(callback.as_ref().unchecked_ref()));
191 }
192 if let Some(callback) = &self.request_onloadstart {
193 request.set_onloadstart(Some(callback.as_ref().unchecked_ref()));
194 }
195 if let Some(callback) = &self.request_on_progress {
196 request.set_onprogress(Some(callback.as_ref().unchecked_ref()));
197 }
198 if let Some(callback) = &self.request_ontimeout {
199 request.set_ontimeout(Some(callback.as_ref().unchecked_ref()));
200 }
201 }
202
203 fn set_upload_callbacks(&self, request: &XmlHttpRequest) {
204 let upload = request
205 .upload()
206 .expect("Could not fetch upload field of xmlhttprequest");
207 if let Some(callback) = &self.upload_onabort {
208 upload.set_onabort(Some(callback.as_ref().unchecked_ref()));
209 }
210 if let Some(callback) = &self.upload_onerror {
211 upload.set_onerror(Some(callback.as_ref().unchecked_ref()));
212 }
213 if let Some(callback) = &self.upload_onload {
214 upload.set_onload(Some(callback.as_ref().unchecked_ref()));
215 }
216 if let Some(callback) = &self.upload_onloadend {
217 upload.set_onloadend(Some(callback.as_ref().unchecked_ref()));
218 }
219 if let Some(callback) = &self.upload_onloadstart {
220 upload.set_onloadstart(Some(callback.as_ref().unchecked_ref()));
221 }
222 if let Some(callback) = &self.upload_on_progress {
223 upload.set_onprogress(Some(callback.as_ref().unchecked_ref()));
224 }
225 if let Some(callback) = &self.upload_ontimeout {
226 upload.set_ontimeout(Some(callback.as_ref().unchecked_ref()));
227 }
228 }
229
230 fn set_headers(&self, request: &XmlHttpRequest) -> Result<(), JsValue> {
231 for (key, value) in &self.headers {
232 request.set_request_header(key, value)?;
233 }
234 Ok(())
235 }
236}
237
238impl Default for PostRequest {
239 fn default() -> Self {
240 Self {
241 _async: true,
242 content: None,
243 upload_onabort: None,
244 upload_onerror: None,
245 upload_onload: None,
246 upload_onloadend: None,
247 upload_onloadstart: None,
248 upload_on_progress: None,
249 upload_ontimeout: None,
250 request_onload: None,
251 request_onabort: None,
252 request_onerror: None,
253 request_onloadend: None,
254 request_onloadstart: None,
255 request_on_progress: None,
256 request_ontimeout: None,
257 headers: Default::default(),
258 }
259 }
260}
261
262pub struct SendRequest {
263 pub request: XmlHttpRequest,
264}
265
266impl SendRequest {
267 pub fn abort(self) {
268 self.request
269 .abort()
270 .expect("tried to abort request which could not be aborted");
271 }
272
273 pub fn status(&self) -> u16 {
274 self.request
275 .status()
276 .expect("Could not fetch request status")
277 }
278
279 pub fn ready_state(&self) -> u16 {
280 self.request.ready_state()
281 }
282}
283
284impl From<XmlHttpRequest> for SendRequest {
285 fn from(request: XmlHttpRequest) -> Self {
286 Self { request }
287 }
288}