use js_sys::*;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_wasm_bindgen::{from_value, to_value};
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use crate::common::{ErrMsg, WxError};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = wx, js_name = request)]
fn request(params: &Object) -> JsValue;
#[wasm_bindgen(js_namespace = wx, js_name = downloadFile)]
fn download_file(params: &Object) -> JsValue;
#[wasm_bindgen(js_namespace = wx, js_name = uploadFile)]
fn upload_file(params: &Object) -> JsValue;
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub enum ResponseType {
#[default]
#[serde(rename = "text")]
Text,
#[serde(rename = "arraybuffer")]
Arraybuffer,
}
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub enum RequestMethod {
#[serde(rename = "OPTIONS")]
Options,
#[default]
#[serde(rename = "GET")]
Get,
#[serde(rename = "HEAD")]
Head,
#[serde(rename = "POST")]
Post,
#[serde(rename = "PUT")]
Put,
#[serde(rename = "DELETE")]
Delete,
#[serde(rename = "TRACE")]
Trace,
#[serde(rename = "CONNECT")]
Connect,
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct Request<'a, D, H> {
pub url: &'a str,
pub data: Option<D>,
pub header: Option<H>,
pub timeout: Option<u32>,
pub method: Option<RequestMethod>,
pub response_type: Option<ResponseType>,
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct Response<T> {
pub data: T,
pub status_code: u16,
}
pub async fn wx_request<'a, D, H, T>(req: Request<'a, D, H>) -> Result<Response<T>, WxError>
where
D: Serialize + DeserializeOwned,
H: Serialize + DeserializeOwned,
T: Serialize + DeserializeOwned,
{
let params = Object::new();
Reflect::set(¶ms, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
if let Some(v) = req.data {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("data"), &value).unwrap();
}
if let Some(v) = req.header {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("header"), &value).unwrap();
}
if let Some(v) = req.timeout {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("timeout"), &value).unwrap();
}
if let Some(v) = req.method {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("method"), &value).unwrap();
}
if let Some(v) = req.response_type {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("response_type"), &value).unwrap();
}
let promise = Promise::new(&mut |resolve, reject| {
let success_handler = move |res| -> Result<JsValue, JsValue> {
let _ = resolve.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let success_handler = Closure::wrap(
Box::new(success_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
let fail_handler = move |res| -> Result<JsValue, JsValue> {
let _ = reject.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let fail_handler = Closure::wrap(
Box::new(fail_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
Reflect::set(¶ms, &JsValue::from("success"), success_handler.as_ref()).unwrap();
success_handler.forget();
Reflect::set(¶ms, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
fail_handler.forget();
request(¶ms);
});
let future = JsFuture::from(promise);
match future.await {
Ok(info) => Ok(from_value::<Response<T>>(info).unwrap()),
Err(err) => Err(WxError::WxErrMsg(from_value::<ErrMsg>(err).unwrap())),
}
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DownloadFile<'a, H> {
pub url: &'a str,
pub header: Option<H>,
pub timeout: Option<u32>,
pub file_path: Option<&'a str>,
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DownloadRes {
pub temp_file_path: Option<String>,
pub file_path: Option<String>,
pub status_code: u16,
}
pub async fn wx_download_file<'a, H, T>(req: DownloadFile<'a, H>) -> Result<DownloadRes, WxError>
where
H: Serialize + DeserializeOwned,
T: Serialize + DeserializeOwned,
{
let params = Object::new();
Reflect::set(¶ms, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
if let Some(v) = req.header {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("header"), &value).unwrap();
}
if let Some(v) = req.timeout {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("timeout"), &value).unwrap();
}
if let Some(v) = req.file_path {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("file_path"), &value).unwrap();
}
let promise = Promise::new(&mut |resolve, reject| {
let success_handler = move |res| -> Result<JsValue, JsValue> {
let _ = resolve.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let success_handler = Closure::wrap(
Box::new(success_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
let fail_handler = move |res| -> Result<JsValue, JsValue> {
let _ = reject.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let fail_handler = Closure::wrap(
Box::new(fail_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
Reflect::set(¶ms, &JsValue::from("success"), success_handler.as_ref()).unwrap();
success_handler.forget();
Reflect::set(¶ms, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
fail_handler.forget();
download_file(¶ms);
});
let future = JsFuture::from(promise);
match future.await {
Ok(info) => Ok(from_value::<DownloadRes>(info).unwrap()),
Err(err) => Err(WxError::WxErrMsg(from_value::<ErrMsg>(err).unwrap())),
}
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct UploadFile<'a, D, H> {
pub url: &'a str,
pub file_path: &'a str,
pub name: &'a str,
pub header: Option<H>,
pub form_data: Option<D>,
pub timeout: Option<u32>,
}
pub async fn wx_upload_file<'a, D, H, T>(req: UploadFile<'a, D, H>) -> Result<Response<T>, WxError>
where
D: Serialize + DeserializeOwned,
H: Serialize + DeserializeOwned,
T: Serialize + DeserializeOwned,
{
let params = Object::new();
Reflect::set(¶ms, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
Reflect::set(
¶ms,
&JsValue::from("filePath"),
&JsValue::from(req.file_path),
)
.unwrap();
Reflect::set(¶ms, &JsValue::from("name"), &JsValue::from(req.name)).unwrap();
if let Some(v) = req.header {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("header"), &value).unwrap();
}
if let Some(v) = req.form_data {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("formData"), &value).unwrap();
}
if let Some(v) = req.timeout {
let value = to_value(&v).unwrap();
Reflect::set(¶ms, &JsValue::from("timeout"), &value).unwrap();
}
let promise = Promise::new(&mut |resolve, reject| {
let success_handler = move |res| -> Result<JsValue, JsValue> {
let _ = resolve.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let success_handler = Closure::wrap(
Box::new(success_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
let fail_handler = move |res| -> Result<JsValue, JsValue> {
let _ = reject.call1(&JsValue::NULL, &res);
Ok(JsValue::NULL)
};
let fail_handler = Closure::wrap(
Box::new(fail_handler) as Box<dyn Fn(JsValue) -> Result<JsValue, JsValue>>
);
Reflect::set(¶ms, &JsValue::from("success"), success_handler.as_ref()).unwrap();
success_handler.forget();
Reflect::set(¶ms, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
fail_handler.forget();
download_file(¶ms);
});
let future = JsFuture::from(promise);
match future.await {
Ok(info) => Ok(from_value::<Response<T>>(info).unwrap()),
Err(err) => Err(WxError::WxErrMsg(from_value::<ErrMsg>(err).unwrap())),
}
}