Skip to main content

wx_rust_open/api/impl/
wx_open_service_impl.rs

1//! 开放平台服务实现。
2//!
3//! 对应 Java `me.chanjar.weixin.open.api.impl.WxOpenServiceImpl`(继承
4//! `WxOpenServiceHttpComponentsImpl` → `WxOpenServiceAbstractImpl`):
5//! 组合门面 trait 的默认实现 + 单一配置存储 + reqwest HTTP 后端。
6//! 组件子服务以 `Weak<dyn WxOpenService>` 注入(对应 Java
7//! `new WxOpenComponentServiceImpl(this)` 的循环引用,Rust 用弱引用打破)。
8
9use std::sync::{Arc, OnceLock, RwLock};
10
11use async_trait::async_trait;
12
13use wx_rust_common::bean::result::WxMinishopImageUploadResult;
14use wx_rust_common::error::WxErrorException;
15
16use crate::api::r#impl::{MinishopUploadRequestExecutor, WxOpenComponentServiceImpl};
17use crate::api::{WxOpenComponentService, WxOpenService};
18use crate::config::WxOpenConfigStorage;
19
20/// 开放平台服务实现(reqwest HTTP 后端)。
21pub struct WxOpenServiceImpl {
22    client: reqwest::Client,
23    config_storage: RwLock<Arc<dyn WxOpenConfigStorage>>,
24    component_service: OnceLock<Arc<dyn WxOpenComponentService>>,
25}
26
27impl WxOpenServiceImpl {
28    /// 构建服务(组件子服务注入 `Weak<dyn WxOpenService>` 打破循环引用)。
29    ///
30    /// # 参数
31    /// - `config`:开放平台(第三方平台)配置存储
32    pub fn new_arc(config: Arc<dyn WxOpenConfigStorage>) -> Arc<Self> {
33        let arc = Arc::new(Self {
34            client: reqwest::Client::new(),
35            config_storage: RwLock::new(config),
36            component_service: OnceLock::new(),
37        });
38        // 先转 Arc<dyn WxOpenService> 再降级为 Weak<dyn WxOpenService>
39        let dyn_arc: Arc<dyn WxOpenService> = arc.clone();
40        let weak = Arc::downgrade(&dyn_arc);
41        let _ = arc
42            .component_service
43            .set(Arc::new(WxOpenComponentServiceImpl::new(weak)));
44        arc
45    }
46}
47
48#[async_trait]
49impl WxOpenService for WxOpenServiceImpl {
50    fn wx_open_component_service(&self) -> Option<Arc<dyn WxOpenComponentService>> {
51        self.component_service.get().cloned()
52    }
53
54    fn wx_open_config_storage(&self) -> Arc<dyn WxOpenConfigStorage> {
55        self.config_storage.read().unwrap().clone()
56    }
57
58    fn set_wx_open_config_storage(&self, wx_open_config_storage: Arc<dyn WxOpenConfigStorage>) {
59        *self.config_storage.write().unwrap() = wx_open_config_storage;
60        // Java `setWxOpenConfigStorage` 触发 `initHttp()` 重建 HTTP 客户端
61        // (代理配置);Rust reqwest Client 在构造时固定,代理/超时重建
62        // 留待 Wave 1(ADAPTED)
63    }
64
65    fn http_client(&self) -> &reqwest::Client {
66        &self.client
67    }
68
69    /// 上传图片到小程序/开放平台素材库(对应 Java
70    /// `uploadMinishopMediaFile(String url, File file)`)。
71    ///
72    /// Wave 2 实现:经 [`MinishopUploadRequestExecutor`](reqwest multipart,
73    /// 字段名 `media`,对应 Java `MinishopUploadRequestExecutor`);
74    /// ADAPTED:Java `File` 入参 → Rust 文件路径字符串。
75    async fn upload_minishop_media_file(
76        &self,
77        url: &str,
78        file_path: &str,
79    ) -> Result<WxMinishopImageUploadResult, WxErrorException> {
80        MinishopUploadRequestExecutor::new(self.http_client().clone())
81            .upload(url, file_path)
82            .await
83    }
84}