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::{Level, event};
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 pub async fn qr_code(&self, args: QrCodeArgs) -> Result<QrCode> {
163 event!(Level::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 event!(Level::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}