1use chrono::Local;
2use json::{JsonValue, object};
3use log::{error, info};
4use crate::{WechatMethod};
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 Ok(self.access_token.clone())
29 } else {
30 Err(res["errmsg"].to_string())
31 }
32 }
33}
34
35impl WechatMethod for Applet {
36 fn access_token(&mut self) -> Result<JsonValue, String> {
37 let dt = Local::now();
38 let timestamp = dt.timestamp_millis();
39 if self.expires_in > timestamp {
40 return Ok(object! {
41 appid: self.appid.clone(),
42 access_token: self.access_token.clone(),
43 expires_in: self.expires_in
44 });
45 }
46 let url = format!("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", self.appid, self.secret);
47 let mut http = br_reqwest::Client::new();
48 http.get(url.as_str());
49 let res = http.send()?.json()?;
50 if res["errcode"].is_empty() {
51 self.access_token = res["access_token"].to_string();
52 self.expires_in = timestamp + res["expires_in"].as_i64().unwrap();
53 Ok(object! {
54 appid: self.appid.clone(),
55 access_token: self.access_token.clone(),
56 expires_in: self.expires_in,
57 })
58 } else {
59 Err(res["errmsg"].to_string())
60 }
61 }
62
63
64 fn check(&mut self) -> Result<bool, String> {
65 match self.access_token() {
66 Ok(_) => Ok(true),
67 Err(e) => Err(e),
68 }
69 }
70 fn code2_session(&mut self, code: &str) -> Result<JsonValue, String> {
72 let url = "https://api.weixin.qq.com/sns/jscode2session".to_string();
73 let mut http = br_reqwest::Client::new();
74 http.get(url.as_str()).raw_json(object! {
75 appid:self.appid.clone(),
76 secret:self.secret.clone(),
77 js_code:code,
78 grant_type:"authorization_code"
79 });
80 let res = http.send()?;
81 let res = res.json()?;
82 let mut user_info = object! {};
83 let res = json::parse(res.as_str().unwrap()).unwrap();
84 if res["errcode"].is_empty() {
85 user_info["session_key"] = res["session_key"].clone();
86 user_info["unionid"] = res["unionid"].as_str().unwrap_or("").into();
87 user_info["openid"] = res["openid"].clone();
88 } else {
89 info!("code2_session: {}", res["errmsg"].as_str().unwrap());
90 }
91 Ok(user_info)
92 }
93 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
94 let mut http = br_reqwest::Client::new();
95 http.get("https://api.weixin.qq.com/sns/jscode2session".to_string().as_str());
96 http.header("Accept", "application/json");
97 http.header("User-Agent", "api");
98 http.header("Content-Type", "application/json");
99 http.query(object! {
100 appid: self.appid.as_str(),
101 secret: self.secret.as_str(),
102 js_code:code,
103 grant_type:"authorization_code",
104 });
105 match http.send()?.json() {
106 Ok(e) => Ok(e),
107 Err(e) => Err(e),
108 }
109 }
110 fn get_phone_number(&mut self, iv: &str, encrypted_data: &str, session_key: &str) -> Result<JsonValue, String> {
112 let data = br_crypto::aes::aes_128_cbc(iv, encrypted_data, session_key)?;
113 let mut data = json::parse(&data).unwrap();
114 data["phone"] = data["purePhoneNumber"].clone();
115 Ok(data)
116 }
117
118 fn getuserinfo(&mut self, code: &str) -> Result<JsonValue, String> {
120 self.access_token()?;
121 let url = format!("https://api.weixin.qq.com/wxa/getpluginopenpid?access_token={}", self.access_token);
122 let mut http = br_reqwest::Client::new();
123 http.post(url.as_str());
124 http.raw_json(object! {
125 code:code
126 });
127 let res = http.send()?;
128 let res = res.json()?;
129 let mut user_info = object! {};
130 if res["errcode"].as_i32().unwrap() == 0 {
131 user_info["userid"] = res["userid"].clone();
132 user_info["user_ticket"] = res["user_ticket"].clone();
133 Ok(user_info)
134 } else {
135 error!("getuserinfo: {}", res["errmsg"].as_str().unwrap());
136 Err(res["errmsg"].to_string())
137 }
138 }
139 fn send_message(&mut self, template_id: &str, page: &str, touser: &str, data: JsonValue, miniprogram_state: &str, lang: &str) -> Result<JsonValue, String> {
140 self.access_token()?;
141 let lang = if lang.is_empty() { "zh_CN" } else { lang };
142 let miniprogram_state = if miniprogram_state.is_empty() { "formal" } else { miniprogram_state };
143 let url = format!("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={}", self.access_token);
144 let mut http = br_reqwest::Client::new();
145 http.post(url.as_str());
146 http.raw_json(object! {
147 access_token:self.access_token()?,
148 template_id:template_id,
149 page:page,
150 touser:touser,
151 data:data,
152 miniprogram_state:miniprogram_state,
153 lang:lang
154 });
155 let res = http.send()?;
156 let res = res.json()?;
157 if res["errcode"].as_i32().unwrap() == 0 {
158 Ok(res["errmsg"].clone())
159 } else {
160 Err(res["errmsg"].to_string())
161 }
162 }
163}