mod access_token;
mod token_storage;
pub mod token_type;
pub use access_token::AccessToken;
pub use token_storage::{MemoryTokenStorage, TokenStorage};
pub use token_type::{NonStableToken, StableToken};
pub type WechatMinapp = WechatMinappSDK;
pub type NormalToken = NonStableToken;
use crate::Result;
use async_trait::async_trait;
use http::{Request, Response};
use reqwest::Request as ReqwestRequest;
use std::{fmt, sync::Arc};
#[derive(Debug, Clone)]
pub struct AppConfig {
pub app_id: String,
pub secret: String,
}
pub struct WechatMinappSDK {
pub client: Arc<dyn HttpClient>,
pub token_storage: Arc<dyn TokenStorage>,
}
impl fmt::Debug for WechatMinappSDK {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("WechatMinappSDK")
.field("client", &"Arc<dyn HttpClient>")
.field("token_storage", &"Arc<dyn TokenStorage>")
.finish()
}
}
impl Clone for WechatMinappSDK {
fn clone(&self) -> Self {
WechatMinappSDK {
client: self.client.clone(),
token_storage: self.token_storage.clone(),
}
}
}
impl WechatMinappSDK {
pub fn new(app_id: &str, secret: &str) -> Self {
let http_client = Arc::new(ReqwestHttpClient::new());
let token_type = Arc::new(StableToken::new(app_id, secret, false, http_client.clone()));
let token_storage = Arc::new(MemoryTokenStorage::new(token_type));
WechatMinappSDK {
client: http_client,
token_storage,
}
}
pub fn custom(http_client: Arc<dyn HttpClient>, token_storage: Arc<dyn TokenStorage>) -> Self {
WechatMinappSDK {
client: http_client,
token_storage,
}
}
pub async fn token(&self) -> Result<String> {
self.token_storage.token().await
}
pub fn app_config(&self) -> AppConfig {
self.token_storage.token_type().app_config()
}
}
#[async_trait]
pub trait HttpClient: Send + Sync {
async fn execute(&self, request: Request<Vec<u8>>) -> Result<Response<Vec<u8>>>;
}
#[derive(Default, Clone)]
pub struct ReqwestHttpClient {
pub client: Arc<reqwest::Client>,
}
impl ReqwestHttpClient {
pub fn new() -> Self {
ReqwestHttpClient {
client: Arc::new(reqwest::Client::new()),
}
}
}
#[async_trait]
impl HttpClient for ReqwestHttpClient {
async fn execute(&self, req: Request<Vec<u8>>) -> Result<Response<Vec<u8>>> {
let reqwest_req: ReqwestRequest = req.try_into()?;
eprintln!("reqwest url: {:?}", reqwest_req.url());
let reqwest_res = self.client.execute(reqwest_req).await?;
let status = reqwest_res.status();
let version = reqwest_res.version();
let headers = reqwest_res.headers().clone();
let body = reqwest_res.bytes().await?.to_vec();
let mut http_res_builder = Response::builder().status(status).version(version);
if let Some(headers_map) = http_res_builder.headers_mut() {
headers_map.extend(headers);
}
let http_res = http_res_builder.body(body)?;
Ok(http_res)
}
}