chimes_utils/wechat/
token.rs1use crate::ChimesClient;
2use crate::{current_timestamp_secs, json_decode, WechatResult as Result, API_DOMAIN};
3use std::{collections::HashMap, sync::Mutex};
4
5use super::errors::WechatError;
6const WECHAT_CONFIG_KEY_TOKIO: &str = "wechat_config_cache_tokio";
9lazy_static! {
11 pub static ref WECHAT_CONFIG_CACHES_ATT: Mutex<HashMap<String, TokioToken>> =
12 Mutex::new(HashMap::new());
13}
14
15#[derive(Debug, Clone, Default)]
17pub struct TokioAccessToken {
18 pub app_type: String,
20 pub app_id: String,
22 pub secret: String,
24}
25
26#[derive(Debug, Clone, Default)]
28pub struct TokioToken {
29 pub access_token: String,
31 pub create_time: u64,
33 pub expires: i64,
35}
36
37impl TokioAccessToken {
38 pub fn new(app_type: &str, app_id: &str, secret: &str) -> TokioAccessToken {
40 TokioAccessToken {
41 app_type: app_type.to_owned(),
42 app_id: app_id.to_owned(),
43 secret: secret.to_owned(),
44 }
45 }
46
47 pub async fn get_access_token(&self, grant_type: &str) -> Result<TokioToken> {
49 let url = format!(
51 "{domain}/cgi-bin/token?grant_type={grant_type}&appid={app_id}&secret={secret}",
52 domain = API_DOMAIN,
53 grant_type = if grant_type.is_empty() {
54 "client_credential"
55 } else {
56 grant_type
57 },
58 app_id = self.app_id,
59 secret = self.secret
60 );
61
62 match ChimesClient::new().get(&url).await {
64 Ok(res) => {
65 match json_decode(&res) {
66 Ok(data) => {
67 let token = match data["access_token"].as_str() {
68 Some(s) => s.to_owned(),
69 None => return Err(WechatError::msg("access token error")),
70 };
71
72 return Ok(TokioToken {
74 access_token: token,
75 create_time: current_timestamp_secs(),
76 expires: 7200,
77 });
78 }
79 Err(err) => {
80 return Err(err);
81 }
82 }
83 }
84 Err(err) => log::error!("error{:?}", err),
85 }
86
87 Err(WechatError::msg("access token is invalid"))
88 }
89
90 pub async fn set(&mut self, val: TokioToken) {
92 let key = WECHAT_CONFIG_KEY_TOKIO;
93
94 let rkey = format!("{}-{}", key, self.app_id.clone());
95
96 let mut cache = WECHAT_CONFIG_CACHES_ATT.lock().unwrap();
97
98 cache.insert(rkey.to_owned(), val);
99 }
101
102 pub fn clear() {
103 let mut cache = WECHAT_CONFIG_CACHES_ATT.lock().unwrap();
104 cache.clear();
105 }
106
107 pub async fn get(&mut self) -> Option<TokioToken> {
109 let key = WECHAT_CONFIG_KEY_TOKIO;
110 let appid = self.app_id.clone();
111 let rkey = format!("{}-{}", key, appid.clone());
112 let cache = WECHAT_CONFIG_CACHES_ATT.lock().unwrap().clone();
113
114 if let Some(mcx) = cache.get(rkey.as_str()) {
115 let now = current_timestamp_secs();
116 if now < mcx.create_time + mcx.expires as u64 - 1000u64 {
117 return Some(mcx.clone());
118 }
119 }
120
121 drop(cache);
122
123 match self.get_access_token(self.app_type.clone().as_str()).await {
124 Ok(access) => {
125 self.set(access.clone()).await;
126 return Some(access.clone());
127 }
128 Err(err) => {
129 log::info!("get access token error{:?}", err);
130 }
131 }
132 None
133 }
134}