wx_mini_api 0.1.27

微信小程序api wasm接口
Documentation
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,
}

/// 微信小程序 请求使用示例
/// ```
///     #[derive(Default, Serialize, Debug)]
///     #[serde(rename_all = "kebab-case")]
///     struct Header {
///         content_type: String,
///     }
///     let header = Header {
///         content_type: "application/json".to_string(),
///     };
///
///     let req: Request<serde_json::Value, serde_json::Value> = Request {
///         url: "your_url",
///         ..Default::default()
///     };
///     let res: Response<serde_json::Value> = wx_request(req).await.unwrap();
/// ```
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(&params, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
    if let Some(v) = req.data {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("data"), &value).unwrap();
    }
    if let Some(v) = req.header {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("header"), &value).unwrap();
    }
    if let Some(v) = req.timeout {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("timeout"), &value).unwrap();
    }
    if let Some(v) = req.method {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("method"), &value).unwrap();
    }
    if let Some(v) = req.response_type {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &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(&params, &JsValue::from("success"), success_handler.as_ref()).unwrap();
        success_handler.forget();
        Reflect::set(&params, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
        fail_handler.forget();

        request(&params);
    });
    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(&params, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
    if let Some(v) = req.header {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("header"), &value).unwrap();
    }
    if let Some(v) = req.timeout {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("timeout"), &value).unwrap();
    }
    if let Some(v) = req.file_path {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &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(&params, &JsValue::from("success"), success_handler.as_ref()).unwrap();
        success_handler.forget();
        Reflect::set(&params, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
        fail_handler.forget();

        download_file(&params);
    });
    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(&params, &JsValue::from("url"), &JsValue::from(req.url)).unwrap();
    Reflect::set(
        &params,
        &JsValue::from("filePath"),
        &JsValue::from(req.file_path),
    )
    .unwrap();
    Reflect::set(&params, &JsValue::from("name"), &JsValue::from(req.name)).unwrap();
    if let Some(v) = req.header {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("header"), &value).unwrap();
    }
    if let Some(v) = req.form_data {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &JsValue::from("formData"), &value).unwrap();
    }
    if let Some(v) = req.timeout {
        let value = to_value(&v).unwrap();
        Reflect::set(&params, &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(&params, &JsValue::from("success"), success_handler.as_ref()).unwrap();
        success_handler.forget();
        Reflect::set(&params, &JsValue::from("fail"), fail_handler.as_ref()).unwrap();
        fail_handler.forget();

        download_file(&params);
    });
    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())),
    }
}