#![allow(unused)]
use gostd::{net::url, strings};
use serde::{Deserialize, Serialize};
use crate::{
biz::BizContenter,
error::AliPayResult,
pay::{PayClient, Payer},
sign::{builder, Signer},
util::{get_biz_content_str, get_now_beijing_time_str},
};
use std::{
borrow::{Borrow, BorrowMut},
collections::HashMap,
hash::BuildHasher,
io::Result,
};
pub trait Requester {
fn new_with_config(pay_config: &PayClient) -> Self;
fn set_method(&mut self, method: &str) -> &mut Self;
fn method(&self) -> String;
fn set_biz_content(&mut self, b: &impl BizContenter) -> &mut Self;
fn encode_payload(&mut self) -> AliPayResult<String>;
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Request {
#[serde(skip_serializing)]
private_key: String, #[serde(skip_serializing)]
public_key: String, app_cert_sn: String, alipay_root_cert_sn: String, app_id: String, app_auth_token: String, method: String, format: String, charset: String, sign_type: String, sign: String, timestamp: String, version: String, notify_url: String, return_url: String, biz_content: String, }
impl Request {
fn set_timestamp(&mut self) {
self.timestamp = get_now_beijing_time_str()
}
fn get_sorted_sign_source(&self) -> AliPayResult<String> {
let mut m = HashMap::<String, String>::new();
let v = serde_json::to_string(self)?;
m = serde_json::from_str(v.as_str())?;
let mut query_list = Vec::<String>::new();
m.iter().for_each(|(k, v)| {
if !v.is_empty() && k != "sign" {
let query = format!("{}={}", k, strings::TrimSpace(v));
query_list.push(query);
}
});
query_list.sort();
Ok(strings::Join(query_list, "&"))
}
}
impl Requester for Request {
fn new_with_config(pay_config: &PayClient) -> Self {
Self {
private_key: pay_config.private_key(),
public_key: pay_config.alipay_public_key(),
app_cert_sn: pay_config.app_cert_sn(),
alipay_root_cert_sn: pay_config.alipay_root_cert_sn(),
app_id: pay_config.app_id(),
format: pay_config.format(),
charset: pay_config.charset(),
sign_type: pay_config.sign_type(),
version: pay_config.version(),
timestamp: get_now_beijing_time_str(),
notify_url: pay_config.notify_url(),
..Default::default()
}
}
fn set_method(&mut self, method: &str) -> &mut Self {
self.method = method.to_owned();
self.borrow_mut()
}
fn method(&self) -> String {
self.method.to_string()
}
fn set_biz_content(&mut self, b: &impl BizContenter) -> &mut Self {
self.biz_content = get_biz_content_str(b);
self.borrow_mut()
}
fn encode_payload(&mut self) -> AliPayResult<String> {
let mut signer = builder().set_sign_type(&self.sign_type).build();
signer.set_private_key(&self.private_key)?;
let sign_sorted_source = self.get_sorted_sign_source()?;
let signture = signer.sign(&sign_sorted_source)?;
let mut encode_list = Vec::<String>::new();
strings::Split(&sign_sorted_source, "&")
.iter()
.for_each(|v| {
let mut splites: Vec<String> = strings::Split(v, "=")
.iter()
.map(|x| x.to_string())
.collect();
splites[1] = url::QueryEscape(&splites[1]);
encode_list.push(strings::Join(splites, "="));
});
let encode_query =
strings::Join(encode_list, "&") + "&sign=" + &url::QueryEscape(&signture);
Ok(encode_query)
}
}