wechat_oa_sdk/api/
qrcode.rs1use serde::Deserialize;
2
3use crate::client::WeChatClient;
4use crate::error::{Result, WeChatError};
5use crate::models::qrcode::{QrCodeAction, QrCodeResponse};
6
7const WECHAT_MP_BASE: &str = "https://mp.weixin.qq.com";
8
9impl WeChatClient {
10 pub async fn create_qrcode(
16 &self,
17 scene_id: u32,
18 action: QrCodeAction,
19 expire_seconds: Option<i64>,
20 ) -> Result<QrCodeResponse> {
21 let mut body = serde_json::json!({
22 "action_name": action.as_str(),
23 "action_info": {
24 "scene": {
25 "scene_id": scene_id
26 }
27 }
28 });
29
30 if let Some(expire) = expire_seconds {
31 body["expire_seconds"] = serde_json::json!(expire);
32 }
33
34 self.post_json("/qrcode/create", &body).await
35 }
36
37 pub async fn create_qrcode_str(
43 &self,
44 scene_str: &str,
45 action: QrCodeAction,
46 expire_seconds: Option<i64>,
47 ) -> Result<QrCodeResponse> {
48 let mut body = serde_json::json!({
49 "action_name": action.as_str(),
50 "action_info": {
51 "scene": {
52 "scene_str": scene_str
53 }
54 }
55 });
56
57 if let Some(expire) = expire_seconds {
58 body["expire_seconds"] = serde_json::json!(expire);
59 }
60
61 self.post_json("/qrcode/create", &body).await
62 }
63
64 pub fn get_qrcode_url(ticket: &str) -> String {
68 format!(
69 "{}/cgi-bin/showqrcode?ticket={}",
70 WECHAT_MP_BASE,
71 urlencoding::encode(ticket)
72 )
73 }
74
75 pub async fn download_qrcode(&self, ticket: &str) -> Result<Vec<u8>> {
77 let url = Self::get_qrcode_url(ticket);
78 let resp = self.http.get(&url).send().await?;
79
80 if !resp.status().is_success() {
81 return Err(WeChatError::Api {
82 errcode: resp.status().as_u16() as i64,
83 errmsg: "Failed to download QR code".to_string(),
84 });
85 }
86
87 Ok(resp.bytes().await?.to_vec())
88 }
89
90 pub async fn create_short_url(&self, long_url: &str) -> Result<String> {
94 let body = serde_json::json!({
95 "action": "long2short",
96 "long_url": long_url
97 });
98
99 #[derive(Deserialize)]
100 struct Response {
101 short_url: Option<String>,
102 errcode: Option<i64>,
103 errmsg: Option<String>,
104 }
105
106 let resp: Response = self.post_json("/shorturl", &body).await?;
107
108 if let Some(errcode) = resp.errcode {
109 if errcode != 0 {
110 return Err(WeChatError::Api {
111 errcode,
112 errmsg: resp.errmsg.unwrap_or_default(),
113 });
114 }
115 }
116
117 resp.short_url.ok_or(WeChatError::TokenUnavailable)
118 }
119
120 pub async fn get_callback_ip_list(&self) -> Result<Vec<String>> {
124 #[derive(Deserialize)]
125 struct Response {
126 ip_list: Vec<String>,
127 }
128
129 let resp: Response = self.get("/getcallbackip", &[]).await?;
130 Ok(resp.ip_list)
131 }
132
133 pub async fn get_api_domain_ip_list(&self) -> Result<Vec<String>> {
135 #[derive(Deserialize)]
136 struct Response {
137 ip_list: Vec<String>,
138 }
139
140 let resp: Response = self.get("/get_api_domain_ip", &[]).await?;
141 Ok(resp.ip_list)
142 }
143
144 pub async fn check_network(&self) -> Result<bool> {
146 #[derive(Deserialize)]
147 #[allow(dead_code)]
148 struct Response {
149 dns: Option<Vec<DnsInfo>>,
150 ping: Option<Vec<PingInfo>>,
151 }
152
153 #[derive(Deserialize)]
154 #[allow(dead_code)]
155 struct DnsInfo {
156 ip: String,
157 real_operator: String,
158 }
159
160 #[derive(Deserialize)]
161 #[allow(dead_code)]
162 struct PingInfo {
163 ip: String,
164 from_operator: String,
165 package_loss: String,
166 time: String,
167 }
168
169 let body = serde_json::json!({
170 "action": "all",
171 "check_operator": "DEFAULT"
172 });
173
174 let _resp: Response = self.post_json("/callback/check", &body).await?;
175 Ok(true)
176 }
177}