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 login(&mut self, code: &str) -> Result<JsonValue, String> {
70 let mut http = br_reqwest::Client::new();
71 http.get("https://api.weixin.qq.com/sns/jscode2session".to_string().as_str());
72 http.header("Accept", "application/json");
73 http.header("User-Agent", "api");
74 http.header("Content-Type", "application/json");
75 http.query(object! {
76 appid: self.appid.as_str(),
77 secret: self.secret.as_str(),
78 js_code:code,
79 grant_type:"authorization_code",
80 });
81 match http.send()?.json() {
82 Ok(e) => Ok(e),
83 Err(e) => Err(e),
84 }
85 }
86 fn get_phone_number(&mut self, iv: &str, encrypted_data: &str, session_key: &str) -> Result<JsonValue, String> {
88 let data = br_crypto::aes::aes_128_cbc(iv, encrypted_data, session_key)?;
89 let mut data = json::parse(&data).unwrap();
90 data["phone"] = data["purePhoneNumber"].clone();
91 Ok(data)
92 }
93
94 fn getuserinfo(&mut self, code: &str) -> Result<JsonValue, String> {
96 let url = format!("https://api.weixin.qq.com/wxa/getpluginopenpid?access_token={}", self.access_token()?);
97 let mut http = br_reqwest::Client::new();
98 http.post(url.as_str());
99 http.raw_json(object! {
100 code:code
101 });
102 let res = http.send()?;
103 let res = res.json()?;
104 let mut user_info = object! {};
105 if res["errcode"].as_i32().unwrap() == 0 {
106 user_info["userid"] = res["userid"].clone();
107 user_info["user_ticket"] = res["user_ticket"].clone();
108 } else {
109 info!("getuserinfo: {}", res["errmsg"].as_str().unwrap());
110 }
111 Ok(user_info)
112 }
113 fn send_message(&mut self, template_id: &str, page: &str, touser: &str, data: JsonValue, miniprogram_state: &str, lang: &str) -> Result<JsonValue, String> {
114 let lang = if lang.is_empty() { "zh_CN" } else { lang };
115 let miniprogram_state = if miniprogram_state.is_empty() { "formal" } else { miniprogram_state };
116 let url = format!("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={}", self.access_token()?);
117 let mut http = br_reqwest::Client::new();
118 http.post(url.as_str());
119 http.raw_json(object! {
120 access_token:self.access_token()?,
121 template_id:template_id,
122 page:page,
123 touser:touser,
124 data:data,
125 miniprogram_state:miniprogram_state,
126 lang:lang
127 });
128 let res = http.send()?;
129 let res = res.json()?;
130 if res["errcode"].as_i32().unwrap() == 0 {
131 Ok(res)
132 } else {
133 Err(res["errmsg"].to_string())
134 }
135 }
136}