use std::sync::{Arc, Weak};
use async_trait::async_trait;
use wx_rust_common::error::WxErrorException;
use wx_rust_miniapp::api::WxMaService;
use crate::api::WxOpenMaBasicService;
use crate::api::WxOpenService;
use crate::api::r#impl::WxOpenMaService;
use crate::api::r#impl::base_wx_open_service_impl;
use crate::bean::WxFastMaAccountBasicInfoResult;
use crate::bean::WxFastMaBeenSetCategoryResult;
use crate::bean::WxFastMaCategory;
use crate::bean::WxFastMaCheckNickameResult;
use crate::bean::WxFastMaQueryNicknameStatusResult;
use crate::bean::WxFastMaSetNickameResult;
use crate::bean::WxOpenGetAllCategoriesByTypeResult;
use crate::bean::WxOpenMaCategoryNameListResult;
use crate::bean::WxOpenMaGetOrderPathResult;
use crate::bean::WxOpenResult;
use crate::enums::url_ma_domain::{
component_rebind_admin_url, ma_add_category_url, ma_check_wx_verify_nickname_url,
ma_component_rebind_admin_url, ma_delete_category_url, ma_get_account_basic_info_url,
ma_get_all_categories_by_type_url, ma_get_all_categories_url, ma_get_all_category_name_url,
ma_get_category_url, ma_get_order_path_info_url, ma_modify_category_url,
ma_modify_head_image_url, ma_modify_signature_url, ma_query_nickname_url, ma_set_nickname_url,
};
pub struct WxOpenMaBasicServiceImpl {
wx_open_service: Weak<dyn WxOpenService>,
app_id: String,
}
impl WxOpenMaBasicServiceImpl {
pub fn new(wx_open_service: Arc<dyn WxOpenService>, app_id: String) -> Self {
Self {
wx_open_service: Arc::downgrade(&wx_open_service),
app_id,
}
}
pub fn app_id(&self) -> &str {
&self.app_id
}
fn svc(&self) -> Result<Arc<dyn WxOpenService>, WxErrorException> {
self.wx_open_service
.upgrade()
.ok_or_else(|| WxErrorException::from_code(-99, "门面服务已被释放"))
}
fn ma_service(&self) -> Result<Arc<dyn WxMaService>, WxErrorException> {
let svc = self.svc()?;
let component = svc.wx_open_component_service().ok_or_else(|| {
WxErrorException::from_code(
-99,
"组件子服务未装配(getWxOpenComponentService 返回 null)",
)
})?;
let any = component
.get_wx_ma_service_by_appid(&self.app_id)
.ok_or_else(|| WxErrorException::from_code(-99, "getWxMaServiceByAppid 返回 None"))?;
let ma = any.downcast::<WxOpenMaService>().map_err(|_| {
WxErrorException::from_code(-99, "代 ma 服务 downcast 失败(缓存类型不匹配)")
})?;
Ok(ma as Arc<dyn WxMaService>)
}
fn component_app_id(&self) -> Result<String, WxErrorException> {
let svc = self.svc()?;
Ok(svc
.wx_open_config_storage()
.component_app_id()
.unwrap_or_default())
}
}
#[async_trait]
impl WxOpenMaBasicService for WxOpenMaBasicServiceImpl {
async fn get_account_basic_info(
&self,
) -> Result<WxFastMaAccountBasicInfoResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let response = ma
.get(&ma_get_account_basic_info_url(config.as_ref()), "")
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn set_nickname(
&self,
nickname: &str,
id_card: &str,
license: &str,
naming_other_stuff1: &str,
naming_other_stuff2: &str,
) -> Result<WxFastMaSetNickameResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({
"nick_name": nickname,
"id_card": id_card,
"license": license,
"naming_other_stuff_1": naming_other_stuff1,
"naming_other_stuff_2": naming_other_stuff2,
});
let response = ma
.post(&ma_set_nickname_url(config.as_ref()), &body.to_string())
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn query_set_nickname_status(
&self,
audit_id: &str,
) -> Result<WxFastMaQueryNicknameStatusResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "audit_id": audit_id });
let response = ma
.post(&ma_query_nickname_url(config.as_ref()), &body.to_string())
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn check_wx_verify_nickname(
&self,
nickname: &str,
) -> Result<WxFastMaCheckNickameResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "nick_name": nickname });
let response = ma
.post(
&ma_check_wx_verify_nickname_url(config.as_ref()),
&body.to_string(),
)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn modify_head_image(
&self,
head_img_media_id: &str,
x1: f32,
y1: f32,
x2: f32,
y2: f32,
) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({
"head_img_media_id": head_img_media_id,
"x1": x1,
"y1": y1,
"x2": x2,
"y2": y2,
});
let response = ma
.post(
&ma_modify_head_image_url(config.as_ref()),
&body.to_string(),
)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn modify_signature(&self, signature: &str) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "signature": signature });
let response = ma
.post(&ma_modify_signature_url(config.as_ref()), &body.to_string())
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
fn get_component_rebind_admin_url(&self, redirect_uri: &str, app_id: &str) -> String {
let component_app_id = self.component_app_id().unwrap_or_default();
let encoded = url_encoder_encode(redirect_uri);
component_rebind_admin_url(app_id, &component_app_id, &encoded)
}
async fn component_rebind_admin(
&self,
task_id: &str,
) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "taskid": task_id });
let response = ma
.post(
&ma_component_rebind_admin_url(config.as_ref()),
&body.to_string(),
)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn get_all_categories(&self) -> Result<String, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
ma.get(&ma_get_all_categories_url(config.as_ref()), "")
.await
}
async fn get_all_categories_by_type(
&self,
verify_type: &str,
) -> Result<WxOpenGetAllCategoriesByTypeResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "verify_type": verify_type });
let response = ma
.post(
&ma_get_all_categories_by_type_url(config.as_ref()),
&body.to_string(),
)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn add_category(
&self,
category_list: &[WxFastMaCategory],
) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "categories": category_list });
let response = ma
.post(&ma_add_category_url(config.as_ref()), &body.to_string())
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn delete_category(
&self,
first: i32,
second: i32,
) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "first": first, "second": second });
let response = ma
.post(&ma_delete_category_url(config.as_ref()), &body.to_string())
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn get_category(&self) -> Result<WxFastMaBeenSetCategoryResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let response = ma.get(&ma_get_category_url(config.as_ref()), "").await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn modify_category(
&self,
category: &WxFastMaCategory,
) -> Result<WxOpenResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body =
serde_json::to_string(category).map_err(|e| WxErrorException::Serde(e.to_string()))?;
let response = ma
.post(&ma_modify_category_url(config.as_ref()), &body)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn get_all_category_name(
&self,
) -> Result<WxOpenMaCategoryNameListResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let response = ma
.get(&ma_get_all_category_name_url(config.as_ref()), "")
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
async fn get_order_path_info(
&self,
info_type: i32,
) -> Result<WxOpenMaGetOrderPathResult, WxErrorException> {
let svc = self.svc()?;
let config = svc.wx_open_config_storage();
let ma = self.ma_service()?;
let body = serde_json::json!({ "info_type": info_type });
let response = ma
.post(
&ma_get_order_path_info_url(config.as_ref()),
&body.to_string(),
)
.await?;
let response = base_wx_open_service_impl::normalize_errcode(&response)?;
serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
}
}
fn url_encoder_encode(input: &str) -> String {
let mut out = String::new();
for &b in input.as_bytes() {
match b {
b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'*' => {
out.push(b as char);
}
b' ' => out.push('+'),
_ => out.push_str(&format!("%{b:02X}")),
}
}
out
}