use std::sync::{Arc, Weak};
use async_trait::async_trait;
use wx_rust_common::bean::WxOAuth2UserInfo;
use wx_rust_common::bean::oauth2::WxOAuth2AccessToken;
use wx_rust_common::error::WxErrorException;
use wx_rust_common::service::WxOAuth2Service;
use crate::api::WxOpenService;
use crate::enums::url_ma_domain::{
connect_oauth2_authorize_url, oauth2_component_access_token_url,
};
pub struct WxOpenMpOAuth2ServiceImpl {
wx_open_service: Weak<dyn WxOpenService>,
inner: Arc<dyn WxOAuth2Service>,
app_id: String,
}
impl WxOpenMpOAuth2ServiceImpl {
pub fn new(
wx_open_service: Arc<dyn WxOpenService>,
inner: Arc<dyn WxOAuth2Service>,
app_id: String,
) -> Self {
Self {
wx_open_service: Arc::downgrade(&wx_open_service),
inner,
app_id,
}
}
fn component_app_id(&self) -> Result<String, WxErrorException> {
let svc = self
.wx_open_service
.upgrade()
.ok_or_else(|| WxErrorException::from_code(-99, "门面服务已被释放"))?;
Ok(svc
.wx_open_config_storage()
.component_app_id()
.unwrap_or_default())
}
}
#[async_trait]
impl WxOAuth2Service for WxOpenMpOAuth2ServiceImpl {
async fn get_access_token(&self, code: &str) -> Result<WxOAuth2AccessToken, WxErrorException> {
let svc = self
.wx_open_service
.upgrade()
.ok_or_else(|| WxErrorException::from_code(-99, "门面服务已被释放"))?;
let component = svc.wx_open_component_service().ok_or_else(|| {
WxErrorException::from_code(
-99,
"组件子服务未装配(getWxOpenComponentService 返回 null)",
)
})?;
let config = svc.wx_open_config_storage();
let url = oauth2_component_access_token_url(config.as_ref(), &self.app_id, code);
let response = component.get(&url).await?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
fn build_authorization_url(&self, redirect_uri: &str, scope: &str, state: &str) -> String {
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
let encoded_redirect = utf8_percent_encode(redirect_uri, NON_ALPHANUMERIC).to_string();
let component_app_id = self.component_app_id().unwrap_or_default();
let state = state.trim();
connect_oauth2_authorize_url(
&self.app_id,
&encoded_redirect,
scope,
state,
&component_app_id,
)
}
async fn get_access_token_with(
&self,
app_id: &str,
app_secret: &str,
code: &str,
) -> Result<WxOAuth2AccessToken, WxErrorException> {
self.inner
.get_access_token_with(app_id, app_secret, code)
.await
}
async fn refresh_access_token(
&self,
refresh_token: &str,
) -> Result<WxOAuth2AccessToken, WxErrorException> {
self.inner.refresh_access_token(refresh_token).await
}
async fn get_user_info(
&self,
token: &WxOAuth2AccessToken,
lang: &str,
) -> Result<WxOAuth2UserInfo, WxErrorException> {
self.inner.get_user_info(token, lang).await
}
}