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 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}