use std::collections::HashMap;
use::std::hash::BuildHasher;
use futures::{future, Future};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen_futures;
use web_sys;
use serde::Serialize;
use serde_json;
pub enum Method {
Get,
Head,
Post,
Put,
Delete,
Connect,
Options,
Trace,
Patch
}
impl Method {
fn as_str(&self) -> &str {
match *self {
Method::Get => "GET",
Method::Head => "HEAD",
Method::Post => "POST",
Method::Put => "PUT",
Method::Delete => "DELETE",
Method::Connect => "CONNECT",
Method::Options => "OPTIONS",
Method::Trace => "TRACE",
Method::Patch => "PATCH",
}
}
}
#[derive(Clone)]
pub struct RequestOpts {
pub payload: Option<String>,
pub headers: HashMap<String, String>,
pub credentials: HashMap<String, String>,
pub mode: web_sys::RequestMode,
}
impl RequestOpts {
pub fn new() -> Self {
Self {
payload: None,
headers: HashMap::new(),
credentials: HashMap::new(),
mode: web_sys::RequestMode::Cors,
}
}
}
pub fn fetch(
method: Method,
url: &str,
request_opts: Option<RequestOpts>,
callback: Box<Fn(JsValue)>)
{
let mut opts = web_sys::RequestInit::new();
opts.method(method.as_str());
opts.mode(web_sys::RequestMode::Cors);
if let Some(o) = request_opts.clone() {
if let Some(p) = o.payload {
opts.body(Some(&JsValue::from_str(&p)));
}
opts.mode(o.mode);
}
let request = web_sys::Request::new_with_str_and_init(url, &opts.clone())
.expect("Problem with request");
if let Some(o) = request_opts {
for (name, value) in &o.headers {
request.headers().set(&name, &value).unwrap();
}
}
let window = web_sys::window().expect("Can't find window");
let request_promise = window.fetch_with_request(&request);
let f = wasm_bindgen_futures::JsFuture::from(request_promise)
.and_then(|resp_value| {
let resp: web_sys::Response = resp_value.dyn_into()
.expect("Problem casting response as Reponse.");
resp.json()
})
.and_then(|json_value| {
wasm_bindgen_futures::JsFuture::from(json_value)
})
.and_then(move |v| {
callback(v);
future::ok(JsValue::null())
});
wasm_bindgen_futures::future_to_promise(f);
}
pub fn get(
url: &str,
request_opts: Option<RequestOpts>,
callback: Box<Fn(JsValue)>)
{
fetch(Method::Get, url, request_opts, callback)
}
pub fn post<S: Serialize>(
url: &str,
payload: S,
request_opts: Option<RequestOpts>,
callback: Box<Fn(JsValue)>)
{
let serialized_payload = serde_json::to_string(&payload).expect("Problem serializing payload");
let updated_opts = match request_opts {
Some(o) => RequestOpts{payload: Some(serialized_payload), ..o},
None => {
let mut opts = RequestOpts::new();
opts.payload = Some(serialized_payload);
opts
}
};
fetch(Method::Post, url, Some(updated_opts), callback)
}