use super::{MinappEnvVersion, Qr, QrCode, Rgb};
use crate::{
Result, constants,
error::Error::{self, InternalServer},
new_type::{NonQueryPagePath, SceneString},
};
use http::header::{CONTENT_TYPE, HeaderValue};
use http::{Method, Request};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tracing::debug;
#[derive(Debug, Deserialize, Serialize)]
pub struct UnlimitedQrCodeArgs {
page: String,
scene: String,
width: Option<i16>,
check_path: Option<bool>,
auto_color: Option<bool>,
line_color: Option<Rgb>,
is_hyaline: Option<bool>,
env_version: Option<MinappEnvVersion>,
}
#[derive(Debug, Deserialize)]
pub struct UnlimitedQrCodeArgsBuilder {
page: Option<String>,
scene: Option<String>,
width: Option<i16>,
check_path: Option<bool>,
auto_color: Option<bool>,
line_color: Option<Rgb>,
is_hyaline: Option<bool>,
env_version: Option<MinappEnvVersion>,
}
impl UnlimitedQrCodeArgs {
pub fn builder() -> UnlimitedQrCodeArgsBuilder {
UnlimitedQrCodeArgsBuilder::new()
}
pub fn page(&self) -> String {
self.page.clone()
}
pub fn width(&self) -> Option<i16> {
self.width
}
pub fn auto_color(&self) -> Option<bool> {
self.auto_color
}
pub fn line_color(&self) -> Option<Rgb> {
self.line_color.clone()
}
pub fn is_hyaline(&self) -> Option<bool> {
self.is_hyaline
}
pub fn env_version(&self) -> Option<MinappEnvVersion> {
self.env_version.clone()
}
}
impl Default for UnlimitedQrCodeArgsBuilder {
fn default() -> Self {
Self::new()
}
}
impl UnlimitedQrCodeArgsBuilder {
pub fn new() -> Self {
UnlimitedQrCodeArgsBuilder {
page: None,
scene: None,
check_path: None,
width: None,
auto_color: None,
line_color: None,
is_hyaline: None,
env_version: None,
}
}
pub fn page(mut self, page: impl Into<String>) -> Self {
self.page = Some(page.into());
self
}
pub fn scene(mut self, scene: impl Into<String>) -> Self {
self.scene = Some(scene.into());
self
}
pub fn width(mut self, width: i16) -> Self {
self.width = Some(width);
self
}
pub fn with_auto_color(mut self) -> Self {
self.auto_color = Some(true);
self
}
pub fn line_color(mut self, color: Rgb) -> Self {
self.line_color = Some(color);
self
}
pub fn with_is_hyaline(mut self) -> Self {
self.is_hyaline = Some(true);
self
}
pub fn env_version(mut self, version: MinappEnvVersion) -> Self {
self.env_version = Some(version);
self
}
pub fn build(self) -> Result<UnlimitedQrCodeArgs> {
let page = self.page.map_or_else(
|| {
Err(Error::InvalidParameter(
"小程序页面路径不能为空".to_string(),
))
},
|v| {
let path = NonQueryPagePath::try_from(v)?;
Ok(path.to_string())
},
)?;
let scene = self.scene.map_or_else(
|| Err(Error::InvalidParameter("scene 不能为空".to_string())),
|v| {
let valid_scene = SceneString::try_from(v)?;
Ok(valid_scene.to_string())
},
)?;
if self.auto_color.is_some() && self.line_color.is_some() {
return Err(Error::InvalidParameter(
"auto_color 为 true 时,line_color 不能设置".to_string(),
));
}
Ok(UnlimitedQrCodeArgs {
page,
scene,
check_path: self.check_path,
width: self.width,
auto_color: self.auto_color,
line_color: self.line_color,
is_hyaline: self.is_hyaline,
env_version: self.env_version,
})
}
}
impl Qr {
pub async fn unlimited_qr_code(&self, args: UnlimitedQrCodeArgs) -> Result<QrCode> {
debug!("get unlimited qr code args {:?}", &args);
let token = format!("access_token={}", self.client.token().await?);
let mut url = url::Url::parse(constants::UNLIMITIED_QR_CODE_ENDPOINT)?;
url.set_query(Some(&token));
let mut body = HashMap::new();
body.insert("page", args.page);
body.insert("scene", args.scene);
if let Some(width) = args.width {
body.insert("width", width.to_string());
}
if let Some(check_path) = args.check_path {
body.insert("check_path", check_path.to_string());
}
if let Some(auto_color) = args.auto_color {
body.insert("auto_color", auto_color.to_string());
}
if let Some(line_color) = args.line_color {
let value = serde_json::to_string(&line_color)?;
body.insert("line_color", value);
}
if let Some(is_hyaline) = args.is_hyaline {
body.insert("is_hyaline", is_hyaline.to_string());
}
if let Some(env_version) = args.env_version {
body.insert("env_version", env_version.into());
}
let client = &self.client.client;
let req_body = serde_json::to_vec(&body)?;
let request = Request::builder()
.uri(url.as_str())
.method(Method::POST)
.header("encoding", HeaderValue::from_static("null"))
.header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
.header(
"User-Agent",
HeaderValue::from_static(constants::HTTP_CLIENT_USER_AGENT),
)
.body(req_body)?;
let response = client.execute(request).await?;
debug!("get unlimited qr code response: {:#?}", response);
if response.status().is_success() {
Ok(QrCode {
buffer: response.into_body(),
})
} else {
let (_parts, body) = response.into_parts();
let message = String::from_utf8_lossy(&body).to_string();
Err(InternalServer(message))
}
}
}