1use chrono::Local;
2use json::{JsonValue, object};
3use log::info;
4use crate::{WechatMethod, ACCOUNT};
5
6#[derive(Clone)]
7pub struct Applet {
8 pub appid: String,
9 pub secret: String,
10 pub access_token: String,
11 pub expires_in: i64,
12}
13
14impl Applet {
15 fn access_token(&mut self) -> Result<String, String> {
16 let dt = Local::now();
17 let timestamp = dt.timestamp_millis();
18 if self.expires_in > timestamp {
19 return Ok(self.access_token.clone());
20 }
21 let url = format!("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", self.appid, self.secret);
22 let mut http = br_reqwest::Client::new();
23 http.get(url.as_str());
24 let res = http.send()?.json()?;
25 if res["errcode"].is_empty() {
26 self.access_token = res["access_token"].to_string();
27 self.expires_in = timestamp + res["expires_in"].as_i64().unwrap();
28 {
29 ACCOUNT.write().unwrap().get_mut(&self.appid.clone()).unwrap().access_token = self.access_token.clone();
30 ACCOUNT.write().unwrap().get_mut(&self.appid.clone()).unwrap().expires_in = self.expires_in;
31 }
32 Ok(self.access_token.clone())
33 } else {
34 Err(res["errmsg"].to_string())
35 }
36 }
37}
38
39impl WechatMethod for Applet {
40 fn check(&mut self) -> Result<bool, String> {
41 match self.access_token() {
42 Ok(_) => Ok(true),
43 Err(e) => Err(e),
44 }
45 }
46 fn code2_session(&mut self, code: &str) -> Result<JsonValue, String> {
48 let url = "https://api.weixin.qq.com/sns/jscode2session".to_string();
49 let mut http = br_reqwest::Client::new();
50 http.get(url.as_str()).raw_json(object! {
51 appid:self.appid.clone(),
52 secret:self.secret.clone(),
53 js_code:code,
54 grant_type:"authorization_code"
55 });
56 let res = http.send()?;
57 let res = res.json()?;
58 let mut user_info = object! {};
59 let res = json::parse(res.as_str().unwrap()).unwrap();
60 if res["errcode"].is_empty() {
61 user_info["session_key"] = res["session_key"].clone();
62 user_info["unionid"] = res["unionid"].as_str().unwrap_or("").into();
63 user_info["openid"] = res["openid"].clone();
64 } else {
65 info!("code2_session: {}", res["errmsg"].as_str().unwrap());
66 }
67 Ok(user_info)
68 }
69 fn getuserinfo(&mut self, code: &str) -> Result<JsonValue, String> {
71 let url = format!("https://api.weixin.qq.com/wxa/getpluginopenpid?access_token={}", self.access_token()?);
72 let mut http = br_reqwest::Client::new();
73 http.post(url.as_str());
74 http.raw_json(object! {
75 code:code
76 });
77 let res = http.send()?;
78 let res = res.json()?;
79 let mut user_info = object! {};
80 if res["errcode"].as_i32().unwrap() == 0 {
81 user_info["userid"] = res["userid"].clone();
82 user_info["user_ticket"] = res["user_ticket"].clone();
83 } else {
84 info!("getuserinfo: {}", res["errmsg"].as_str().unwrap());
85 }
86 Ok(user_info)
87 }
88 fn get_phone_number(&mut self, iv: &str, encrypted_data: &str, session_key: &str) -> Result<JsonValue, String> {
90 let data = br_crypto::aes::aes_128_cbc(iv, encrypted_data, session_key)?;
91 let mut data = json::parse(&data).unwrap();
92 data["phone"] = data["purePhoneNumber"].clone();
93 Ok(data)
94 }
95
96 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
97 let mut http = br_reqwest::Client::new();
98 http.get("https://api.weixin.qq.com/sns/jscode2session".to_string().as_str());
99 http.header("Accept", "application/json");
100 http.header("User-Agent", "api");
101 http.header("Content-Type", "application/json");
102 http.query(object! {
103 appid: self.appid.as_str(),
104 secret: self.secret.as_str(),
105 js_code:code,
106 grant_type:"authorization_code",
107 });
108 match http.send()?.json() {
109 Ok(e) => Ok(e),
110 Err(e) => Err(e),
111 }
112 }
113}