Rust_wasm/rs/xmlHttpRequest/
xmlHttpPostRequest.rs

1use 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_form(form_id: &str) -> Self {
35    //     let window = web_sys::window().expect("Fatal: No window found!");
36    //     let document = window.document().expect("Fatal: No document in window");
37
38    //     let form = document
39    //         .get_element_by_id(form_id)
40    //         .unwrap_or_else(|| panic!("Could not find the form specified: {}", form_id));
41
42    //     let form_data = FormData::new_with_form(&form.dyn_into().unwrap_or_else(|_| {
43    //         panic!(
44    //             "The id provided (\"{}\") did not point to an html form!",
45    //             form_id
46    //         )
47    //     }))
48    //     .unwrap_or_else(|_| panic!("Could not extract form with id \"{}\"!", form_id));
49
50    //     PostRequest {
51    //         content: Some(PostRequestContent::Form(form_data)),
52    //         ..Default::default()
53    //     }
54    // }
55
56    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        // let callback = closure.map(|c| Closure::<dyn Fn(ErrorEvent)>::wrap(c).into_js_value());
112        self.request_onerror = fun;
113    }
114
115    pub fn set_request_onload(&mut self, fun:Option<JsValue>) {
116       //let callback = closure.map(|c| Closure::<dyn Fn(ProgressEvent)>::wrap(c).into_js_value());
117        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_upload_callbacks(&request);
142        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}