Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ license = "MIT"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
redis = { version = "0.21.0", features = ["r2d2"]}
redis = { version = "0.23.1", features = ["r2d2","streams"] }
reqwest = { version = "0.11.0", features = ["blocking", "json","native-tls","__rustls", "native-tls-crate", "multipart"] }
bytes = { version = "1.1.0", features = ["serde"] }

r2d2 = {version = "0.8.9"}
chrono = { version = "0.4", features = ["serde"]}

time = "0.3.26"
rand = "0.7.3"
uuid = { version = "0.7.4", features = ["serde", "v4"] }
byteorder = {version = "1.3.4"}
Expand All @@ -45,6 +45,7 @@ sha2 = { version = "0.10" }
hmac = { version = "0.12" }
hex = { version = "0.4.3" }
aes = { version = "0.7.5" }
cfb-mode = "0.7"
aes-gcm = { version = "0.10" }
base64 = "0.12"
bincode = "1.3.3"
Expand Down
2 changes: 1 addition & 1 deletion src/alipay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ impl <T: SessionStore> AlipayClient<T> {
}
let key = self.encrypt_key.to_owned().unwrap_or_default();
let prp = PrpCrypto::new(key.into_bytes());
let encrypt_content = prp.aes_128_cbc_encrypt_data(biz_content, Some(&get_nonce_str()))?;
let encrypt_content = prp.aes_128_cbc_encrypt_data(biz_content, Some(get_nonce_str().into_bytes()))?;
let encrypt_content = String::from_utf8_lossy(&encrypt_content).to_string();
app_params.insert(constants::BIZ_CONTENT_KEY.to_string(), encrypt_content);
}
Expand Down
8 changes: 4 additions & 4 deletions src/alipay/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ pub struct AlipayTradePayModel {
/// 结算信息、
/// json格式,详见结算参数说明。
/// 直付通模式下必传。
pub settle_info: Option<SettleInfo>,
pub settle_info: Option<AlipaySettleInfo>,
/// 二级商户信息。
/// 直付通模式和机构间连模式下必传,其它场景下不需要传入。。
pub sub_merchant: Option<SubMerchantInfo>,
Expand Down Expand Up @@ -934,7 +934,7 @@ pub struct AlipayTradePrecreateModel {
/// 结算信息、
/// json格式,详见结算参数说明。
/// 直付通模式下必传。
pub settle_info: Option<SettleInfo>,
pub settle_info: Option<AlipaySettleInfo>,
/// 订单包含的商品列表信息,json格式,其它说明详见商品明细说明
pub goods_detail: Option<AlipayGoodsDetail>,
/// 业务扩展参数
Expand Down Expand Up @@ -1134,7 +1134,7 @@ pub struct AlipayTradeCreateModel {
/// 结算信息、
/// json格式,详见结算参数说明。
/// 直付通模式下必传。
pub settle_info: Option<SettleInfo>,
pub settle_info: Option<AlipaySettleInfo>,
/// 订单包含的商品列表信息,json格式,其它说明详见商品明细说明
pub goods_detail: Option<AlipayGoodsDetail>,
/// 业务扩展参数
Expand Down Expand Up @@ -1304,7 +1304,7 @@ pub struct PromoParam {

/// 外部指定买家
#[derive(Debug, Serialize, Deserialize)]
pub struct SettleInfo {
pub struct AlipaySettleInfo {
/// 结算详细信息,json数组,目前只支持一条。
pub settle_detail_infos: Option<Vec<SettleDetailInfo>>,
/// 该笔订单的超期自动确认结算时间,到达期限后,将自动确认结算。此字段只在签约账期结算模式时有效。取值范围:1d~365d。d-天。 该参数数值不接受小数点。
Expand Down
7 changes: 7 additions & 0 deletions src/alipay/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::{BTreeMap};
use json::JsonValue;
use serde::{Deserialize, Serialize};
use serde::de::{DeserializeOwned};
use crate::amount_serde;

use crate::{errors::LabraError, AlipayResponse, LabradorResult, RequestMethod};
use crate::alipay::constants::{ALIPAY_CERT_SN, ERROR_RESPONSE_KEY, SIGN};
Expand Down Expand Up @@ -778,16 +779,22 @@ pub struct AlipayNotifyResponse {
/// </pre>
pub trade_status: Option<String>,
/// 订单金额。本次交易支付订单金额,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub total_amount: Option<f64>,
/// 实收金额。商家在交易中实际收到的款项,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub receipt_amount: Option<f64>,
/// 开票金额。用户在交易中支付的可开发票的金额,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub invoice_amount: Option<f64>,
/// 用户在交易中支付的金额,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub buyer_pay_amount: Option<f64>,
/// 使用集分宝支付金额,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub point_amount: Option<f64>,
/// 总退款金额。退款通知中,返回总退款金额,单位为人民币(元),精确到小数点后 2 位
#[serde(with = "amount_serde")]
pub refund_fee: Option<f64>,
/// 订单标题/商品标题/交易标题/订单关键字等,是请求时对应参数,会在通知中原样传回
pub subject: Option<String>,
Expand Down
5 changes: 5 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ impl From<DecodeError> for LabraError {
LabraError::InvalidSignature(format!("字符编码出错:{}", err.to_string()))
}
}
impl From<cfb_mode::cipher::errors::InvalidLength> for LabraError {
fn from(err: cfb_mode::cipher::errors::InvalidLength) -> Self {
LabraError::InvalidSignature(format!("InvalidLength:{}", err.to_string()))
}
}
impl From<r2d2::Error> for LabraError {
fn from(err: r2d2::Error) -> Self {
LabraError::RequestError(format!("redis连接错误:{}", err.to_string()))
Expand Down
90 changes: 88 additions & 2 deletions src/qiniu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl<'a> Qiniu<'a> {
}


pub fn get_access_token(&self, filename: &str) -> String {
pub fn get_upload_token(&self, filename: &str) -> String {
// 1.构造上传策略
// let setting = &SETTINGS;
let bucket_name = self.bucket.to_owned();
Expand All @@ -97,6 +97,47 @@ impl<'a> Qiniu<'a> {
data
}


pub fn get_access_token(&self, method: &str, req_url: &str, req_content_type: Option<&str>, req_keys: Option<Vec<(String, String)>>, req_body: Option<&str>) -> String {
let secret_key = self.secret_key.to_owned();
let access_key = self.access_key.to_owned();

let mut signing_str = format!("{} {}\nHost: ", method.to_uppercase(), req_url);
if let Some(content_type) = req_content_type {
signing_str.push_str("\n");
signing_str.push_str("Content-Type: ");
signing_str.push_str(content_type);
}
if let Some(req_keys) = req_keys {
for (k, v) in req_keys.iter() {
signing_str.push_str("\n");
signing_str.push_str(k);
signing_str.push_str(": ");
signing_str.push_str(v);
}
}

signing_str.push_str("\n");
signing_str.push_str("\n");

if let Some(body) = req_body {
let content_type = req_content_type.unwrap_or_default();
if !content_type.contains("application/octet-stream") {
signing_str.push_str(body);
}

}
debug!("七牛云管理凭证待签名字符串: {}", &signing_str);
// 使用访问密钥(AK/SK)对上一步生成的待签名字符串计算HMAC-SHA1签名
let prp = PrpCrypto::new(secret_key.as_bytes().to_vec());
let result = prp.hmac_sha1_sign(&signing_str).unwrap_or_default();
// 对签名进行URL安全的Base64编码
let encoded_sign = safe_base64(result);//base64::encode(result.code());
let data = format!("{}:{}",access_key, encoded_sign);
debug!("七牛云管理凭证: {}", &data);
data
}

pub fn host(&self, bucket: &str, object: &str, resources_str: &str) -> String {
if self.endpoint.starts_with("https") {
format!(
Expand All @@ -118,7 +159,7 @@ impl<'a> Qiniu<'a> {
}

pub async fn upload(&self, file: Bytes, filename: String) -> LabradorResult<String> {
let upload_token = self.get_access_token(filename.as_str());
let upload_token = self.get_upload_token(filename.as_str());
let mut headers = HeaderMap::new();
headers.insert("Host", "up-z2.qiniup.com".parse().unwrap());
let client = reqwest::Client::new();
Expand All @@ -138,6 +179,51 @@ impl<'a> Qiniu<'a> {
Ok(result)
}

pub async fn delete_obj(&self, obj_name: String) -> LabradorResult<String> {
let mut headers = HeaderMap::new();
headers.insert("Host", "rs.qiniup.com".parse().unwrap());
headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
let client = reqwest::Client::new();
let entry = format!("{}:{}", self.bucket(), &obj_name);
let encoded_entry_uri = safe_base64(entry);
let url = format!("/delete/{}", encoded_entry_uri);
let token = self.get_access_token("POST", &url, Some("application/x-www-form-urlencoded"), None, None);
headers.insert("Authorization", format!("Qiniu {}", token).parse().unwrap());
let result = client
.post(format!("{}{}", self.endpoint(), url))
.form(&serde_json::Value::Null)
.headers(headers.to_owned()).send().await.map_err(|err| LabraError::ApiError(err.to_string()))?
.text().await.map_err(|err| LabraError::ApiError(err.to_string()))?;
Ok(result)
}

pub async fn get_obj(&self, obj_name: &str) -> LabradorResult<Bytes> {
let domains = self.domains().await?;
let domain = domains.first().map(ToString::to_string).unwrap_or_default();
let client = reqwest::Client::new();
let result = client
.get(format!("{}/{}", domain, obj_name)).send().await.map_err(|err| LabraError::ApiError(err.to_string()))?
.bytes().await.map_err(|err| LabraError::ApiError(err.to_string()))?;
Ok(result)
}

pub async fn domains(&self) -> LabradorResult<Vec<String>> {
let bucket = self.bucket.to_string();
let mut headers = HeaderMap::new();
headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
headers.insert("Host", "rs.qiniup.com".parse().unwrap());
let client = reqwest::Client::new();
let url = format!("/v2/domains?tbl={}", bucket);
let token = self.get_access_token("POST", &url, Some("application/x-www-form-urlencoded"), None, None);
headers.insert("Authorization", format!("Qiniu {}", token).parse().unwrap());
let result = client
.post(format!("{}{}", self.endpoint(), url))
.form(&serde_json::Value::Null)
.headers(headers.to_owned()).send().await.map_err(|err| LabraError::ApiError(err.to_string()))?
.json::<Vec<String>>().await.map_err(|err| LabraError::ApiError(err.to_string()))?;
Ok(result)
}

}


Expand Down
3 changes: 2 additions & 1 deletion src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ impl <T> LabraRequest <T> where T: Serialize {
request = request.header(k, HeaderValue::from_str(v)?);
}
}
tracing::info!("[请求第三方接口参数] url: {}, data:{}", http_url.as_str(), data);

tracing::info!("[请求第三方接口参数] url: {}, \n headers:{:?},\n data:{}", http_url.as_str(), &self.headers, data);
let result = request.send().await?;
let status = result.status();
let remote_addr = result.remote_addr();
Expand Down
11 changes: 4 additions & 7 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ pub mod redis_store {
}
}

fn get_connect(&self) -> RedisPool {
pub fn get_connect(&self) -> RedisPool {
let pool = self.client_pool.to_owned();
pool
}
Expand All @@ -448,8 +448,7 @@ pub mod redis_store {
if !client.check_connection() {
return Err(LabraError::ApiError("error to get redis connection".to_string()))
}
let s = client.del(key.as_ref())?;
Ok(())
client.del(key.as_ref()).map_err(LabraError::from)
}

pub fn zlcount<K: AsRef<str>, M: ToRedisArgs, MM: ToRedisArgs, RV: FromRedisValue>(&self, key: K, min: M, max: MM) -> LabradorResult<RV> {
Expand Down Expand Up @@ -888,12 +887,10 @@ pub mod redis_store {
return Err(LabraError::ApiError("error to get redis connection".to_string()))
}
if let Some(seconds) = ttl {
let _ = client.set_ex(key, value.to_store(), seconds)?;
client.set_ex(key, value.to_store(), seconds).map_err(LabraError::from)
} else {
let _ = client.set(key, value.to_store())?;
client.set(key, value.to_store()).map_err(LabraError::from)
}

Ok(())
}
}
}
Expand Down
31 changes: 31 additions & 0 deletions src/util/amount_serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use serde::{Serializer, Deserializer, Deserialize};
use serde::de::Error;

pub fn serialize<S>(value: &Option<f64>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match value {
Some(v) => {
// 序列化时格式化为2位小数
serializer.serialize_str(&format!("{:.2}", v))
},
None => serializer.serialize_none(),
}
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
where
D: Deserializer<'de>,
{
let s: Option<String> = Option::deserialize(deserializer)?;
match s {
Some(str_val) => {
// 解析为f64
str_val.parse::<f64>()
.map(Some)
.map_err(D::Error::custom)
},
None => Ok(None),
}
}
5 changes: 3 additions & 2 deletions src/util/md5.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

//!
//!
//! MD5加密类
//!
use std::ops::Deref;


#[allow(unused)]
static SALT: &'static str = "labrador";
Expand All @@ -28,6 +28,7 @@ pub fn md5<S:Into<String>>(input: S) -> String {

#[cfg(not(feature = "openssl-crypto"))]
fn crypto_md5(input: String) -> String {
use std::ops::Deref;
let mut input_salt: String = String::new();
input_salt.push_str(input.as_str());
let result = md5::compute(input_salt.as_bytes());
Expand Down
2 changes: 1 addition & 1 deletion src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::prp::PrpCrypto;

pub mod md5;
pub mod prp;

pub mod amount_serde;

/// 请求参数
#[derive(Debug, Clone)]
Expand Down
Loading