wechat_minapp/
qr_code.rs

1use crate::{
2    Client, Result, constants,
3    error::Error::{self, InternalServer},
4};
5use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use tracing::debug;
9
10#[derive(Debug, Serialize, Deserialize, Clone)]
11pub struct QrCode {
12    buffer: Vec<u8>,
13}
14
15impl QrCode {
16    pub fn buffer(&self) -> &Vec<u8> {
17        &self.buffer
18    }
19}
20
21#[derive(Debug, Deserialize)]
22pub struct QrCodeArgs {
23    path: String,
24    width: Option<i16>,
25    auto_color: Option<bool>,
26    line_color: Option<Rgb>,
27    is_hyaline: Option<bool>,
28    env_version: Option<MinappEnvVersion>,
29}
30
31#[derive(Debug, Deserialize)]
32pub struct QrCodeArgBuilder {
33    path: Option<String>,
34    width: Option<i16>,
35    auto_color: Option<bool>,
36    line_color: Option<Rgb>,
37    is_hyaline: Option<bool>,
38    env_version: Option<MinappEnvVersion>,
39}
40#[derive(Debug, Deserialize, Serialize)]
41pub struct Rgb {
42    r: i8,
43    g: i8,
44    b: i8,
45}
46
47impl QrCodeArgs {
48    pub fn builder() -> QrCodeArgBuilder {
49        QrCodeArgBuilder::new()
50    }
51}
52
53impl Default for QrCodeArgBuilder {
54    fn default() -> Self {
55        Self::new()
56    }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub enum MinappEnvVersion {
61    Release,
62    Trial,
63    Develop,
64}
65
66impl From<MinappEnvVersion> for String {
67    fn from(value: MinappEnvVersion) -> Self {
68        match value {
69            MinappEnvVersion::Develop => "develop".to_string(),
70            MinappEnvVersion::Release => "release".to_string(),
71            MinappEnvVersion::Trial => "trial".to_string(),
72        }
73    }
74}
75impl QrCodeArgBuilder {
76    pub fn new() -> Self {
77        QrCodeArgBuilder {
78            path: None,
79            width: None,
80            auto_color: None,
81            line_color: None,
82            is_hyaline: None,
83            env_version: None,
84        }
85    }
86
87    pub fn path(mut self, path: impl Into<String>) -> Self {
88        self.path = Some(path.into());
89        self
90    }
91
92    pub fn width(mut self, width: i16) -> Self {
93        self.width = Some(width);
94        self
95    }
96
97    pub fn with_auto_color(mut self) -> Self {
98        self.auto_color = Some(true);
99        self
100    }
101
102    pub fn line_color(mut self, color: Rgb) -> Self {
103        self.line_color = Some(color);
104        self
105    }
106
107    pub fn with_is_hyaline(mut self) -> Self {
108        self.is_hyaline = Some(true);
109        self
110    }
111
112    pub fn env_version(mut self, version: MinappEnvVersion) -> Self {
113        self.env_version = Some(version);
114        self
115    }
116
117    pub fn build(self) -> Result<QrCodeArgs> {
118        let path = self.path.map_or_else(
119            || {
120                Err(Error::InvalidParameter(
121                    "小程序页面路径不能为空".to_string(),
122                ))
123            },
124            |v| {
125                if v.len() > 1024 {
126                    return Err(Error::InvalidParameter(
127                        "页面路径最大长度 1024 个字符".to_string(),
128                    ));
129                }
130                Ok(v)
131            },
132        )?;
133
134        Ok(QrCodeArgs {
135            path,
136            width: self.width,
137            auto_color: self.auto_color,
138            line_color: self.line_color,
139            is_hyaline: self.is_hyaline,
140            env_version: self.env_version,
141        })
142    }
143}
144
145impl Client {
146    /// ```ignore
147    /// use wechat_minapp::{Client,QrCodeArgs};
148    ///
149    /// #[tokio::main]
150    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
151    ///     let app_id = "your app id";
152    ///     let secret = "your app secret";
153    ///     
154    ///     let client = Client::new(app_id, secret);
155    ///     let qr_args = QrCodeArgs::builder().path(&page).build()?;
156    ///     let buffer = minapp.qr_code(qr_args).await?;
157    ///
158    ///     Ok(())
159    /// }
160    /// ```
161    ///
162    pub async fn qr_code(&self, args: QrCodeArgs) -> Result<QrCode> {
163        debug!("get qr code args {:?}", &args);
164
165        let mut query = HashMap::new();
166        let mut body = HashMap::new();
167
168        query.insert("access_token", self.access_token().await?);
169        body.insert("path", args.path);
170
171        if let Some(width) = args.width {
172            body.insert("width", width.to_string());
173        }
174
175        if let Some(auto_color) = args.auto_color {
176            body.insert("auto_color", auto_color.to_string());
177        }
178
179        if let Some(line_color) = args.line_color {
180            let value = serde_json::to_string(&line_color)?;
181            body.insert("line_color", value);
182        }
183
184        if let Some(is_hyaline) = args.is_hyaline {
185            body.insert("is_hyaline", is_hyaline.to_string());
186        }
187
188        if let Some(env_version) = args.env_version {
189            body.insert("env_version", env_version.into());
190        }
191
192        let mut headers = HeaderMap::new();
193        headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
194        headers.insert("encoding", HeaderValue::from_static("null"));
195
196        let response = self
197            .request()
198            .post(constants::QR_CODE_ENDPOINT)
199            .headers(headers)
200            .query(&query)
201            .json(&body)
202            .send()
203            .await?;
204
205        debug!("response: {:#?}", response);
206
207        if response.status().is_success() {
208            let response = response.bytes().await?;
209
210            Ok(QrCode {
211                buffer: response.to_vec(),
212            })
213        } else {
214            Err(InternalServer(response.text().await?))
215        }
216    }
217}