oxygengine_backend_web/
fetch.rs

1use core::fetch::{FetchEngine, FetchProcess, FetchStatus};
2use futures::{future, TryFutureExt};
3use js_sys::*;
4use wasm_bindgen::{prelude::*, JsCast};
5use wasm_bindgen_futures::{future_to_promise, JsFuture};
6use web_sys::*;
7
8fn window() -> web_sys::Window {
9    web_sys::window().expect("no global `window` exists")
10}
11
12#[derive(Default, Clone)]
13pub struct WebFetchEngine {
14    root_path: String,
15    cors: bool,
16    cache: bool,
17    credentials: bool,
18}
19
20impl WebFetchEngine {
21    pub fn new(root_path: &str) -> Self {
22        Self {
23            root_path: root_path.to_owned(),
24            cors: true,
25            cache: true,
26            credentials: true,
27        }
28    }
29
30    pub fn cors(mut self, value: bool) -> Self {
31        self.cors = value;
32        self
33    }
34
35    pub fn cache(mut self, value: bool) -> Self {
36        self.cache = value;
37        self
38    }
39
40    pub fn credentials(mut self, value: bool) -> Self {
41        self.credentials = value;
42        self
43    }
44}
45
46impl FetchEngine for WebFetchEngine {
47    fn fetch(&mut self, path: &str) -> Result<Box<FetchProcess>, FetchStatus> {
48        let mut opts = RequestInit::new();
49        opts.method("GET");
50        opts.mode(if self.cors {
51            RequestMode::Cors
52        } else {
53            RequestMode::NoCors
54        });
55        opts.cache(if self.cache {
56            RequestCache::Default
57        } else {
58            RequestCache::NoCache
59        });
60        opts.credentials(if self.credentials {
61            RequestCredentials::SameOrigin
62        } else {
63            RequestCredentials::Omit
64        });
65
66        let full_path = format!("{}/{}", self.root_path, path);
67        let request = Request::new_with_str_and_init(&full_path, &opts).unwrap();
68        let request_promise = window().fetch_with_request(&request);
69        let process = FetchProcess::new_start();
70        let mut process2 = process.clone();
71        // TODO: when web-sys will support ReadableStream we will be able to track progress.
72        let future = JsFuture::from(request_promise)
73            .and_then(|resp| {
74                assert!(resp.is_instance_of::<Response>());
75                let resp: Response = resp.dyn_into().unwrap();
76                JsFuture::from(resp.array_buffer().unwrap())
77            })
78            .and_then(move |buff| {
79                assert!(buff.is_instance_of::<ArrayBuffer>());
80                let typebuf: Uint8Array = Uint8Array::new(&buff);
81                let mut body = vec![0; typebuf.length() as usize];
82                typebuf.copy_to(&mut body[..]);
83                process2.done(body);
84                future::ok(JsValue::null())
85            });
86        // TODO: fail process on error catch.
87        drop(future_to_promise(future));
88        Ok(Box::new(process))
89    }
90}