async_wechat/official_account/
token.rs1use deadpool_redis::redis::cmd;
2use serde::{Deserialize, Serialize};
3use url::{Url, form_urlencoded};
4
5use crate::OfficialAccount;
6use crate::constants::keys;
7
8pub(crate) const TOKEN_URL: &str = "https://api.weixin.qq.com/cgi-bin/token";
9
10#[derive(Serialize, Deserialize, Debug)]
11pub struct TokenResponse {
12 pub access_token: String,
13 expires_in: u64,
14}
15
16impl OfficialAccount {
17 pub async fn token(&self) -> Result<String, Box<dyn std::error::Error>> {
33 let mut rdb = self.rdb_pool.get().await?;
34
35 let value: Option<String> = cmd("GET")
36 .arg(keys::GLOBAL_TOKEN)
37 .query_async(&mut rdb)
38 .await
39 .unwrap_or(None);
40 if let Some(bytes) = value {
41 let at: TokenResponse = serde_json::from_str(&bytes).unwrap();
42 return Ok(at.access_token);
43 }
44
45 let mut url = Url::parse(TOKEN_URL).unwrap();
46 let query = form_urlencoded::Serializer::new(String::new())
47 .append_pair("appid", &self.config.appid)
48 .append_pair("secret", &self.config.app_secret)
49 .append_pair("grant_type", "client_credential")
50 .finish();
51
52 url.set_query(Some(&query));
53 let url = url.to_string();
54
55 let response = self.client.get(&url).send().await?;
56 let at: TokenResponse = response.json::<TokenResponse>().await?;
57 cmd("SETEX")
58 .arg(keys::GLOBAL_TOKEN)
59 .arg(60 * 50 * 2)
60 .arg(serde_json::to_string(&at).unwrap())
61 .query_async::<()>(&mut rdb)
62 .await
63 .unwrap();
64
65 Ok(at.access_token)
66 }
67}