Skip to main content

wx_rust_open/api/impl/
wx_open_ma_auth_service_impl.rs

1//! 小程序认证(年审)服务实现。
2//!
3//! 对应 Java `me.chanjar.weixin.open.api.impl.WxOpenMaAuthServiceImpl`
4//! (持有 `WxMaService`——代 ma 桥接服务,构造入参
5//! `new WxOpenMaAuthServiceImpl(this)`)。
6//!
7//! 依赖表达与 [`crate::api::r#impl::WxOpenMaAuthAndIcpServiceImpl`] 相同
8//! (`Weak<dyn WxOpenService>` + 按 appid 取回代 ma 桥接服务,ADAPTED)。
9//! `upload` 对应 Java `wxMaService.upload(url, new CommonUploadParam(
10//! "media", data))`:Rust 以
11//! [`MediaUploadRequestExecutor`] + 代 ma 执行引擎(`execute_with_retry`,
12//! authorizer access_token 注入 + 自动刷新)承载。
13
14use std::sync::{Arc, Weak};
15
16use async_trait::async_trait;
17
18use wx_rust_common::bean::{CommonUploadData, CommonUploadParam};
19use wx_rust_common::error::WxErrorException;
20use wx_rust_common::util::http::MediaUploadRequestExecutor;
21use wx_rust_miniapp::api::WxMaService;
22
23use crate::api::WxOpenMaAuthService;
24use crate::api::WxOpenService;
25use crate::api::r#impl::WxOpenMaService;
26use crate::api::r#impl::base_wx_open_service_impl;
27use crate::bean::MaAuthQueryIdentityTreeResult;
28use crate::bean::MaAuthQueryResult;
29use crate::bean::MaAuthResubmitParam;
30use crate::bean::MaAuthSubmitParam;
31use crate::bean::MaAuthSubmitResult;
32use crate::bean::MaAuthUploadResult;
33use crate::enums::url_ma_domain::{
34    ma_auth_identity_url, ma_auth_query_url, ma_auth_resubmit_url, ma_auth_submit_url,
35    ma_auth_upload_url,
36};
37
38/// 小程序认证服务实现(对应 Java `WxOpenMaAuthServiceImpl`)。
39pub struct WxOpenMaAuthServiceImpl {
40    wx_open_service: Weak<dyn WxOpenService>,
41    app_id: String,
42}
43
44impl WxOpenMaAuthServiceImpl {
45    /// 构建服务(对应 Java
46    /// `new WxOpenMaAuthServiceImpl(WxMaService)`,`WxMaService` 为代 ma
47    /// 桥接服务自身)。
48    pub fn new(wx_open_service: Arc<dyn WxOpenService>, app_id: String) -> Self {
49        Self {
50            wx_open_service: Arc::downgrade(&wx_open_service),
51            app_id,
52        }
53    }
54
55    /// 授权方 appid(Java 构造入参,代运营目标账号)。
56    pub fn app_id(&self) -> &str {
57        &self.app_id
58    }
59
60    fn svc(&self) -> Result<Arc<dyn WxOpenService>, WxErrorException> {
61        self.wx_open_service
62            .upgrade()
63            .ok_or_else(|| WxErrorException::from_code(-99, "门面服务已被释放"))
64    }
65
66    /// 取代 ma 桥接服务(同
67    /// [`WxOpenMaAuthAndIcpServiceImpl::ma_service`])。
68    fn ma_service(&self) -> Result<Arc<dyn WxMaService>, WxErrorException> {
69        let svc = self.svc()?;
70        let component = svc.wx_open_component_service().ok_or_else(|| {
71            WxErrorException::from_code(
72                -99,
73                "组件子服务未装配(getWxOpenComponentService 返回 null)",
74            )
75        })?;
76        let any = component
77            .get_wx_ma_service_by_appid(&self.app_id)
78            .ok_or_else(|| WxErrorException::from_code(-99, "getWxMaServiceByAppid 返回 None"))?;
79        let ma = any.downcast::<WxOpenMaService>().map_err(|_| {
80            WxErrorException::from_code(-99, "代 ma 服务 downcast 失败(缓存类型不匹配)")
81        })?;
82        Ok(ma as Arc<dyn WxMaService>)
83    }
84}
85
86#[async_trait]
87impl WxOpenMaAuthService for WxOpenMaAuthServiceImpl {
88    /// 小程序认证(提审)(对应 Java `submit(MaAuthSubmitParam param)`:
89    /// POST 参数序列化 → `MaAuthSubmitResult`)。
90    async fn submit(
91        &self,
92        param: &MaAuthSubmitParam,
93    ) -> Result<MaAuthSubmitResult, WxErrorException> {
94        let svc = self.svc()?;
95        let config = svc.wx_open_config_storage();
96        let ma = self.ma_service()?;
97        let body =
98            serde_json::to_string(param).map_err(|e| WxErrorException::Serde(e.to_string()))?;
99        let response = ma.post(&ma_auth_submit_url(config.as_ref()), &body).await?;
100        // Java Gson 宽松类型转换:数字 errcode 归一化为字符串(bean 的
101        // errcode 字段为 String,镜像 Java 字段类型)
102        let response = base_wx_open_service_impl::normalize_errcode(&response)?;
103        serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
104    }
105
106    /// 进度查询(对应 Java `query(String taskId)`:POST
107    /// `{"taskid": ...}` → `MaAuthQueryResult`)。
108    async fn query(&self, task_id: &str) -> Result<MaAuthQueryResult, WxErrorException> {
109        let svc = self.svc()?;
110        let config = svc.wx_open_config_storage();
111        let ma = self.ma_service()?;
112        let body = serde_json::json!({ "taskid": task_id });
113        let response = ma
114            .post(&ma_auth_query_url(config.as_ref()), &body.to_string())
115            .await?;
116        // Java Gson 宽松类型转换:数字 errcode 归一化为字符串(bean 的
117        // errcode 字段为 String,镜像 Java 字段类型)
118        let response = base_wx_open_service_impl::normalize_errcode(&response)?;
119        serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
120    }
121
122    /// 上传补充材料(对应 Java `upload(CommonUploadData data)`:
123    /// multipart 字段 `media` 上传 → `MaAuthUploadResult`)。
124    async fn upload(
125        &self,
126        data: &CommonUploadData,
127    ) -> Result<MaAuthUploadResult, WxErrorException> {
128        let svc = self.svc()?;
129        let config = svc.wx_open_config_storage();
130        let ma = self.ma_service()?;
131        let executor = MediaUploadRequestExecutor::new(ma.http_client().clone());
132        let param = CommonUploadParam::new("media", data.clone());
133        let response = wx_rust_miniapp::api::r#impl::base_wx_ma_service_impl::execute_with_retry(
134            ma.as_ref(),
135            &executor,
136            &ma_auth_upload_url(config.as_ref()),
137            param,
138        )
139        .await?;
140        // Java Gson 宽松类型转换:数字 errcode 归一化为字符串(bean 的
141        // errcode 字段为 String,镜像 Java 字段类型)
142        let response = base_wx_open_service_impl::normalize_errcode(&response)?;
143        serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
144    }
145
146    /// 重新提审(对应 Java `resubmit(MaAuthResubmitParam param)`:POST
147    /// 参数序列化 → `MaAuthSubmitResult`)。
148    async fn resubmit(
149        &self,
150        param: &MaAuthResubmitParam,
151    ) -> Result<MaAuthSubmitResult, WxErrorException> {
152        let svc = self.svc()?;
153        let config = svc.wx_open_config_storage();
154        let ma = self.ma_service()?;
155        let body =
156            serde_json::to_string(param).map_err(|e| WxErrorException::Serde(e.to_string()))?;
157        let response = ma
158            .post(&ma_auth_resubmit_url(config.as_ref()), &body)
159            .await?;
160        // Java Gson 宽松类型转换:数字 errcode 归一化为字符串(bean 的
161        // errcode 字段为 String,镜像 Java 字段类型)
162        let response = base_wx_open_service_impl::normalize_errcode(&response)?;
163        serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
164    }
165
166    /// 查询个人认证身份选项列表(对应 Java `queryIdentityTree()`:
167    /// GET `null` 参数 → `MaAuthQueryIdentityTreeResult`)。
168    async fn query_identity_tree(&self) -> Result<MaAuthQueryIdentityTreeResult, WxErrorException> {
169        let svc = self.svc()?;
170        let config = svc.wx_open_config_storage();
171        let ma = self.ma_service()?;
172        let response = ma.get(&ma_auth_identity_url(config.as_ref()), "").await?;
173        // Java Gson 宽松类型转换:数字 errcode 归一化为字符串(bean 的
174        // errcode 字段为 String,镜像 Java 字段类型)
175        let response = base_wx_open_service_impl::normalize_errcode(&response)?;
176        serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
177    }
178}