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