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