use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::sync::Arc;
use crate::auth::Signer;
use crate::config::WxPayConfig;
use crate::error::{WxPayError, WxPayResult};
use crate::http::{HttpClient, HttpMethod};
use crate::services::transport::{ServiceTransport, TransportObserver};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CertificateInfo {
pub serial_no: String,
pub effective_time: String,
pub expire_time: String,
}
#[allow(dead_code)]
pub struct CertificateService {
config: Arc<WxPayConfig>,
http_client: Arc<dyn HttpClient>,
signer: Arc<dyn Signer>,
transport: ServiceTransport,
}
impl CertificateService {
pub fn new(
config: Arc<WxPayConfig>,
http_client: Arc<dyn HttpClient>,
signer: Arc<dyn Signer>,
) -> Self {
Self::new_with_observer(config.clone(), http_client.clone(), signer.clone(), None)
}
pub fn new_with_observer(
config: Arc<WxPayConfig>,
http_client: Arc<dyn HttpClient>,
signer: Arc<dyn Signer>,
transport_observer: Option<Arc<dyn TransportObserver>>,
) -> Self {
Self {
config: config.clone(),
http_client: http_client.clone(),
signer: signer.clone(),
transport: ServiceTransport::new_with_observer(
config,
http_client,
signer,
transport_observer,
),
}
}
pub async fn get_certificates(&self) -> WxPayResult<Vec<CertificateInfo>> {
let response_json: Value = self
.transport
.request(
HttpMethod::Get,
"/v3/certificates",
None,
"certificate.get_certificates",
)
.await?;
let certificate_items = response_json
.get("data")
.and_then(|v| v.as_array())
.or_else(|| response_json.as_array())
.ok_or_else(|| {
WxPayError::CertificateParseError("证书接口响应缺少 data 字段".to_string())
})?;
let mut certificates = Vec::with_capacity(certificate_items.len());
for item in certificate_items {
let info: CertificateInfo = serde_json::from_value(item.clone()).map_err(|e| {
WxPayError::CertificateParseError(format!("证书信息解析失败:{}", e))
})?;
certificates.push(info);
}
Ok(certificates)
}
}
impl std::fmt::Debug for CertificateService {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CertificateService").finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_certificate_info_serialization() {
let cert_info = CertificateInfo {
serial_no: "CERT123456".to_string(),
effective_time: "2024-01-01T00:00:00+08:00".to_string(),
expire_time: "2025-01-01T00:00:00+08:00".to_string(),
};
let json = serde_json::to_string(&cert_info).unwrap();
assert!(json.contains("CERT123456"));
assert!(json.contains("2024-01-01T00:00:00+08:00"));
}
#[test]
fn test_certificate_info_deserialization() {
let json = r#"{
"serial_no": "CERT123456",
"effective_time": "2024-01-01T00:00:00+08:00",
"expire_time": "2025-01-01T00:00:00+08:00"
}"#;
let cert_info: CertificateInfo = serde_json::from_str(json).unwrap();
assert_eq!(cert_info.serial_no, "CERT123456");
}
}