1use std::sync::{Arc, Weak};
18
19use async_trait::async_trait;
20
21use wx_rust_common::error::WxErrorException;
22use wx_rust_miniapp::api::WxMaService;
23
24use crate::api::WxOpenMaBasicService;
25use crate::api::WxOpenService;
26use crate::api::r#impl::WxOpenMaService;
27use crate::api::r#impl::base_wx_open_service_impl;
28use crate::bean::WxFastMaAccountBasicInfoResult;
29use crate::bean::WxFastMaBeenSetCategoryResult;
30use crate::bean::WxFastMaCategory;
31use crate::bean::WxFastMaCheckNickameResult;
32use crate::bean::WxFastMaQueryNicknameStatusResult;
33use crate::bean::WxFastMaSetNickameResult;
34use crate::bean::WxOpenGetAllCategoriesByTypeResult;
35use crate::bean::WxOpenMaCategoryNameListResult;
36use crate::bean::WxOpenMaGetOrderPathResult;
37use crate::bean::WxOpenResult;
38use crate::enums::url_ma_domain::{
39 component_rebind_admin_url, ma_add_category_url, ma_check_wx_verify_nickname_url,
40 ma_component_rebind_admin_url, ma_delete_category_url, ma_get_account_basic_info_url,
41 ma_get_all_categories_by_type_url, ma_get_all_categories_url, ma_get_all_category_name_url,
42 ma_get_category_url, ma_get_order_path_info_url, ma_modify_category_url,
43 ma_modify_head_image_url, ma_modify_signature_url, ma_query_nickname_url, ma_set_nickname_url,
44};
45
46pub struct WxOpenMaBasicServiceImpl {
48 wx_open_service: Weak<dyn WxOpenService>,
49 app_id: String,
50}
51
52impl WxOpenMaBasicServiceImpl {
53 pub fn new(wx_open_service: Arc<dyn WxOpenService>, app_id: String) -> Self {
57 Self {
58 wx_open_service: Arc::downgrade(&wx_open_service),
59 app_id,
60 }
61 }
62
63 pub fn app_id(&self) -> &str {
65 &self.app_id
66 }
67
68 fn svc(&self) -> Result<Arc<dyn WxOpenService>, WxErrorException> {
69 self.wx_open_service
70 .upgrade()
71 .ok_or_else(|| WxErrorException::from_code(-99, "门面服务已被释放"))
72 }
73
74 fn ma_service(&self) -> Result<Arc<dyn WxMaService>, WxErrorException> {
77 let svc = self.svc()?;
78 let component = svc.wx_open_component_service().ok_or_else(|| {
79 WxErrorException::from_code(
80 -99,
81 "组件子服务未装配(getWxOpenComponentService 返回 null)",
82 )
83 })?;
84 let any = component
85 .get_wx_ma_service_by_appid(&self.app_id)
86 .ok_or_else(|| WxErrorException::from_code(-99, "getWxMaServiceByAppid 返回 None"))?;
87 let ma = any.downcast::<WxOpenMaService>().map_err(|_| {
88 WxErrorException::from_code(-99, "代 ma 服务 downcast 失败(缓存类型不匹配)")
89 })?;
90 Ok(ma as Arc<dyn WxMaService>)
91 }
92
93 fn component_app_id(&self) -> Result<String, WxErrorException> {
96 let svc = self.svc()?;
97 Ok(svc
98 .wx_open_config_storage()
99 .component_app_id()
100 .unwrap_or_default())
101 }
102}
103
104#[async_trait]
105impl WxOpenMaBasicService for WxOpenMaBasicServiceImpl {
106 async fn get_account_basic_info(
109 &self,
110 ) -> Result<WxFastMaAccountBasicInfoResult, WxErrorException> {
111 let svc = self.svc()?;
112 let config = svc.wx_open_config_storage();
113 let ma = self.ma_service()?;
114 let response = ma
115 .get(&ma_get_account_basic_info_url(config.as_ref()), "")
116 .await?;
117 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
120 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
121 }
122
123 async fn set_nickname(
127 &self,
128 nickname: &str,
129 id_card: &str,
130 license: &str,
131 naming_other_stuff1: &str,
132 naming_other_stuff2: &str,
133 ) -> Result<WxFastMaSetNickameResult, WxErrorException> {
134 let svc = self.svc()?;
135 let config = svc.wx_open_config_storage();
136 let ma = self.ma_service()?;
137 let body = serde_json::json!({
138 "nick_name": nickname,
139 "id_card": id_card,
140 "license": license,
141 "naming_other_stuff_1": naming_other_stuff1,
142 "naming_other_stuff_2": naming_other_stuff2,
143 });
144 let response = ma
145 .post(&ma_set_nickname_url(config.as_ref()), &body.to_string())
146 .await?;
147 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
150 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
151 }
152
153 async fn query_set_nickname_status(
156 &self,
157 audit_id: &str,
158 ) -> Result<WxFastMaQueryNicknameStatusResult, WxErrorException> {
159 let svc = self.svc()?;
160 let config = svc.wx_open_config_storage();
161 let ma = self.ma_service()?;
162 let body = serde_json::json!({ "audit_id": audit_id });
163 let response = ma
164 .post(&ma_query_nickname_url(config.as_ref()), &body.to_string())
165 .await?;
166 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
169 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
170 }
171
172 async fn check_wx_verify_nickname(
176 &self,
177 nickname: &str,
178 ) -> Result<WxFastMaCheckNickameResult, WxErrorException> {
179 let svc = self.svc()?;
180 let config = svc.wx_open_config_storage();
181 let ma = self.ma_service()?;
182 let body = serde_json::json!({ "nick_name": nickname });
183 let response = ma
184 .post(
185 &ma_check_wx_verify_nickname_url(config.as_ref()),
186 &body.to_string(),
187 )
188 .await?;
189 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
192 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
193 }
194
195 async fn modify_head_image(
199 &self,
200 head_img_media_id: &str,
201 x1: f32,
202 y1: f32,
203 x2: f32,
204 y2: f32,
205 ) -> Result<WxOpenResult, WxErrorException> {
206 let svc = self.svc()?;
207 let config = svc.wx_open_config_storage();
208 let ma = self.ma_service()?;
209 let body = serde_json::json!({
210 "head_img_media_id": head_img_media_id,
211 "x1": x1,
212 "y1": y1,
213 "x2": x2,
214 "y2": y2,
215 });
216 let response = ma
217 .post(
218 &ma_modify_head_image_url(config.as_ref()),
219 &body.to_string(),
220 )
221 .await?;
222 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
225 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
226 }
227
228 async fn modify_signature(&self, signature: &str) -> Result<WxOpenResult, WxErrorException> {
231 let svc = self.svc()?;
232 let config = svc.wx_open_config_storage();
233 let ma = self.ma_service()?;
234 let body = serde_json::json!({ "signature": signature });
235 let response = ma
236 .post(&ma_modify_signature_url(config.as_ref()), &body.to_string())
237 .await?;
238 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
241 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
242 }
243
244 fn get_component_rebind_admin_url(&self, redirect_uri: &str, app_id: &str) -> String {
251 let component_app_id = self.component_app_id().unwrap_or_default();
252 let encoded = url_encoder_encode(redirect_uri);
253 component_rebind_admin_url(app_id, &component_app_id, &encoded)
254 }
255
256 async fn component_rebind_admin(
259 &self,
260 task_id: &str,
261 ) -> Result<WxOpenResult, WxErrorException> {
262 let svc = self.svc()?;
263 let config = svc.wx_open_config_storage();
264 let ma = self.ma_service()?;
265 let body = serde_json::json!({ "taskid": task_id });
266 let response = ma
267 .post(
268 &ma_component_rebind_admin_url(config.as_ref()),
269 &body.to_string(),
270 )
271 .await?;
272 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
275 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
276 }
277
278 async fn get_all_categories(&self) -> Result<String, WxErrorException> {
281 let svc = self.svc()?;
282 let config = svc.wx_open_config_storage();
283 let ma = self.ma_service()?;
284 ma.get(&ma_get_all_categories_url(config.as_ref()), "")
285 .await
286 }
287
288 async fn get_all_categories_by_type(
292 &self,
293 verify_type: &str,
294 ) -> Result<WxOpenGetAllCategoriesByTypeResult, WxErrorException> {
295 let svc = self.svc()?;
296 let config = svc.wx_open_config_storage();
297 let ma = self.ma_service()?;
298 let body = serde_json::json!({ "verify_type": verify_type });
299 let response = ma
300 .post(
301 &ma_get_all_categories_by_type_url(config.as_ref()),
302 &body.to_string(),
303 )
304 .await?;
305 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
308 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
309 }
310
311 async fn add_category(
314 &self,
315 category_list: &[WxFastMaCategory],
316 ) -> Result<WxOpenResult, WxErrorException> {
317 let svc = self.svc()?;
318 let config = svc.wx_open_config_storage();
319 let ma = self.ma_service()?;
320 let body = serde_json::json!({ "categories": category_list });
321 let response = ma
322 .post(&ma_add_category_url(config.as_ref()), &body.to_string())
323 .await?;
324 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
327 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
328 }
329
330 async fn delete_category(
333 &self,
334 first: i32,
335 second: i32,
336 ) -> Result<WxOpenResult, WxErrorException> {
337 let svc = self.svc()?;
338 let config = svc.wx_open_config_storage();
339 let ma = self.ma_service()?;
340 let body = serde_json::json!({ "first": first, "second": second });
341 let response = ma
342 .post(&ma_delete_category_url(config.as_ref()), &body.to_string())
343 .await?;
344 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
347 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
348 }
349
350 async fn get_category(&self) -> Result<WxFastMaBeenSetCategoryResult, WxErrorException> {
353 let svc = self.svc()?;
354 let config = svc.wx_open_config_storage();
355 let ma = self.ma_service()?;
356 let response = ma.get(&ma_get_category_url(config.as_ref()), "").await?;
357 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
360 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
361 }
362
363 async fn modify_category(
366 &self,
367 category: &WxFastMaCategory,
368 ) -> Result<WxOpenResult, WxErrorException> {
369 let svc = self.svc()?;
370 let config = svc.wx_open_config_storage();
371 let ma = self.ma_service()?;
372 let body =
373 serde_json::to_string(category).map_err(|e| WxErrorException::Serde(e.to_string()))?;
374 let response = ma
375 .post(&ma_modify_category_url(config.as_ref()), &body)
376 .await?;
377 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
380 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
381 }
382
383 async fn get_all_category_name(
385 &self,
386 ) -> Result<WxOpenMaCategoryNameListResult, WxErrorException> {
387 let svc = self.svc()?;
388 let config = svc.wx_open_config_storage();
389 let ma = self.ma_service()?;
390 let response = ma
391 .get(&ma_get_all_category_name_url(config.as_ref()), "")
392 .await?;
393 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
396 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
397 }
398
399 async fn get_order_path_info(
402 &self,
403 info_type: i32,
404 ) -> Result<WxOpenMaGetOrderPathResult, WxErrorException> {
405 let svc = self.svc()?;
406 let config = svc.wx_open_config_storage();
407 let ma = self.ma_service()?;
408 let body = serde_json::json!({ "info_type": info_type });
409 let response = ma
410 .post(
411 &ma_get_order_path_info_url(config.as_ref()),
412 &body.to_string(),
413 )
414 .await?;
415 let response = base_wx_open_service_impl::normalize_errcode(&response)?;
418 serde_json::from_str(&response).map_err(|e| WxErrorException::Serde(e.to_string()))
419 }
420}
421
422fn url_encoder_encode(input: &str) -> String {
428 let mut out = String::new();
429 for &b in input.as_bytes() {
430 match b {
431 b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'.' | b'-' | b'_' | b'*' => {
432 out.push(b as char);
433 }
434 b' ' => out.push('+'),
435 _ => out.push_str(&format!("%{b:02X}")),
436 }
437 }
438 out
439}