1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::dom::Callback;
use crate::{Application, Cmd, Dispatch, Program};
use js_sys::TypeError;
use std::fmt::Debug;
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use web_sys::RequestInit;
use web_sys::Response;
#[derive(Copy, Clone, Debug)]
pub struct Http;
impl Http {
pub fn fetch_with_text_response_decoder<APP, MSG, SUCCESS, ERROR>(
url: &str,
fetch_cb: SUCCESS,
error_cb: ERROR,
) -> Cmd<APP, MSG>
where
SUCCESS: Fn(String) -> MSG + Clone + 'static,
ERROR: Fn(TypeError) -> MSG + Clone + 'static,
APP: Application<MSG> + 'static,
MSG: 'static,
{
let fetch_cb = Callback::from(fetch_cb);
let decoder_dispatcher =
move |(response, program): (Response, Program<APP, MSG>)| {
let response_promise =
response.text().expect("must be a promise text");
let fetch_cb = fetch_cb.clone();
let dispatcher: Closure<dyn FnMut(JsValue)> =
Closure::once(move |js_value: JsValue| {
let response_text = js_value
.as_string()
.expect("There's no string value");
let msg = fetch_cb.emit(response_text);
program.dispatch(msg);
});
let _ = response_promise.then(&dispatcher);
dispatcher.forget();
};
let error_cb = move |type_error| error_cb(type_error);
Self::fetch_with_request_and_response_decoder(
url,
None,
decoder_dispatcher,
error_cb,
)
}
pub fn fetch_with_request_and_response_decoder<APP, MSG, DECODER, ERROR>(
url: &str,
request_init: Option<RequestInit>,
decoder_dispatcher: DECODER,
error_cb: ERROR,
) -> Cmd<APP, MSG>
where
APP: Application<MSG> + 'static,
MSG: 'static,
DECODER: Fn((Response, Program<APP, MSG>)) + 'static,
ERROR: Fn(TypeError) -> MSG + 'static,
{
let url_clone = url.to_string();
let error_cb = Callback::from(error_cb);
let decoder_dispatcher_cb = Callback::from(decoder_dispatcher);
Cmd::new(move |program| {
let program_clone = program.clone();
let error_cb = error_cb.clone();
let window =
web_sys::window().expect("should a refernce to window");
let fetch_promise = if let Some(ref request_init) = request_init {
window.fetch_with_str_and_init(&url_clone, request_init)
} else {
window.fetch_with_str(&url_clone)
};
let decoder_dispatcher_cb = decoder_dispatcher_cb.clone();
let fetch_cb_closure: Closure<dyn FnMut(JsValue)> =
Closure::once(move |js_value: JsValue| {
let response: Response = js_value.unchecked_into();
decoder_dispatcher_cb.emit((response, program_clone));
});
let error_cb_closure: Closure<dyn FnMut(JsValue)> =
Closure::once(move |js_value: JsValue| {
let type_error: TypeError = js_value.unchecked_into();
program.dispatch(error_cb.emit(type_error));
});
let _ = fetch_promise
.then(&fetch_cb_closure)
.catch(&error_cb_closure);
fetch_cb_closure.forget();
error_cb_closure.forget();
})
}
}