use super::Qr;
use crate::utils::{RequestBuilder, ResponseExt};
use crate::{Result, constants, error::Error, new_type::PagePath};
use serde::{Deserialize, Serialize};
use tracing::debug;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct QrCode {
pub buffer: Vec<u8>,
}
impl QrCode {
pub fn buffer(&self) -> &Vec<u8> {
&self.buffer
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct QrCodeArgs {
path: String,
#[serde(skip_serializing_if = "Option::is_none")]
width: Option<i16>,
#[serde(skip_serializing_if = "Option::is_none")]
auto_color: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
line_color: Option<Rgb>,
#[serde(skip_serializing_if = "Option::is_none")]
is_hyaline: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
env_version: Option<MinappEnvVersion>,
}
#[derive(Debug, Deserialize)]
pub struct QrCodeArgBuilder {
path: Option<String>,
width: Option<i16>,
auto_color: Option<bool>,
line_color: Option<Rgb>,
is_hyaline: Option<bool>,
env_version: Option<MinappEnvVersion>,
}
#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct Rgb {
r: i16,
g: i16,
b: i16,
}
impl Rgb {
pub fn new(r: i16, g: i16, b: i16) -> Self {
Rgb { r, g, b }
}
}
impl QrCodeArgs {
pub fn builder() -> QrCodeArgBuilder {
QrCodeArgBuilder::new()
}
pub fn path(&self) -> String {
self.path.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 QrCodeArgBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MinappEnvVersion {
Release,
Trial,
Develop,
}
impl From<MinappEnvVersion> for String {
fn from(value: MinappEnvVersion) -> Self {
match value {
MinappEnvVersion::Develop => "develop".to_string(),
MinappEnvVersion::Release => "release".to_string(),
MinappEnvVersion::Trial => "trial".to_string(),
}
}
}
impl QrCodeArgBuilder {
pub fn new() -> Self {
QrCodeArgBuilder {
path: None,
width: None,
auto_color: None,
line_color: None,
is_hyaline: None,
env_version: None,
}
}
pub fn path(mut self, path: impl Into<String>) -> Self {
self.path = Some(path.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<QrCodeArgs> {
let path = self.path.map_or_else(
|| {
Err(Error::InvalidParameter(
"小程序页面路径不能为空".to_string(),
))
},
|v| {
let valid_path = PagePath::try_from(v)?;
Ok(valid_path.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(QrCodeArgs {
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 qr_code(&self, args: QrCodeArgs) -> Result<QrCode> {
debug!("get qr code args {:?}", &args);
let query = serde_json::json!({
"access_token":self.client.token().await?
});
let body = serde_json::to_value(QrCodeArgs {
path: args.path,
width: args.width,
auto_color: args.auto_color,
line_color: args.line_color,
is_hyaline: args.is_hyaline,
env_version: args.env_version,
})?;
let request = RequestBuilder::new(constants::QR_CODE_ENDPOINT)
.query(query)
.body(body)
.build()?;
let client = &self.client.client;
let response = client.execute(request).await?;
debug!("response: {:#?}", response);
let buffer = response.to_raw()?;
if buffer.len() > 2048 {
return Ok(QrCode { buffer });
}
Err(Error::InternalServer(
String::from_utf8_lossy(&buffer).to_string(),
))
}
}