wx_rust_common/config/
mod.rs1use std::sync::Arc;
7use std::sync::Mutex;
8use std::sync::OnceLock;
9use tokio::sync::Mutex as AsyncMutex;
10
11use crate::clock::{SystemClock, WxClock};
12
13#[derive(Debug, Clone)]
15pub struct TokenEntry {
16 pub value: String,
18 pub expires_at: Option<i64>,
20}
21
22impl TokenEntry {
23 pub fn is_expired(&self, now: i64) -> bool {
28 match self.expires_at {
29 Some(t) => t <= now,
30 None => false,
31 }
32 }
33}
34
35pub trait WxConfigStorage: Send + Sync {
41 fn app_id(&self) -> &str;
43
44 fn secret(&self) -> &str;
46
47 fn access_token(&self) -> Option<String>;
49
50 fn is_access_token_expired(&self) -> bool;
52
53 fn expire_access_token(&self);
55
56 fn update_access_token(&self, access_token: &str, expires_in_seconds: i32);
62
63 fn access_token_lock(&self) -> Arc<AsyncMutex<()>>;
65
66 fn is_stable_access_token(&self) -> bool {
68 false
69 }
70
71 fn auto_refresh_token(&self) -> bool {
73 true
74 }
75
76 fn ticket(&self, _ticket_type: TicketType) -> Option<String> {
78 None
79 }
80
81 fn is_ticket_expired(&self, _ticket_type: TicketType) -> bool {
83 true
84 }
85
86 fn update_ticket(&self, _ticket_type: TicketType, _ticket: &str, _expires_in_seconds: i32) {}
88
89 fn ticket_lock(&self, _ticket_type: TicketType) -> Arc<AsyncMutex<()>> {
91 Arc::new(AsyncMutex::new(()))
92 }
93
94 fn expire_ticket(&self, _ticket_type: TicketType) {}
96
97 fn http_proxy_host(&self) -> Option<&str> {
99 None
100 }
101
102 fn http_proxy_port(&self) -> Option<u16> {
104 None
105 }
106
107 fn tmp_dir(&self) -> Option<&str> {
109 None
110 }
111}
112
113#[derive(Debug)]
118pub struct WxDefaultConfig {
119 pub app_id: String,
120 pub secret: String,
121 access_token: Mutex<Option<TokenEntry>>,
123 access_token_lock: Arc<AsyncMutex<()>>,
125 pub stable_access_token: bool,
127 pub auto_refresh: bool,
129 pub http_proxy_host: Option<String>,
131 pub http_proxy_port: Option<u16>,
133 clock: OnceLock<Arc<dyn WxClock>>,
135}
136
137impl WxDefaultConfig {
138 pub fn new(app_id: impl Into<String>, secret: impl Into<String>) -> Self {
144 Self {
145 app_id: app_id.into(),
146 secret: secret.into(),
147 access_token: Mutex::new(None),
148 access_token_lock: Arc::new(AsyncMutex::new(())),
149 stable_access_token: false,
150 auto_refresh: true,
151 http_proxy_host: None,
152 http_proxy_port: None,
153 clock: OnceLock::new(),
154 }
155 }
156
157 pub fn set_clock(&self, clock: Arc<dyn WxClock>) -> bool {
163 self.clock.set(clock).is_ok()
164 }
165
166 fn now_secs(&self) -> i64 {
169 self.clock
170 .get_or_init(|| Arc::new(SystemClock) as Arc<dyn WxClock>)
171 .now_ms()
172 / 1000
173 }
174}
175
176impl WxConfigStorage for WxDefaultConfig {
177 fn app_id(&self) -> &str {
178 &self.app_id
179 }
180
181 fn secret(&self) -> &str {
182 &self.secret
183 }
184
185 fn access_token(&self) -> Option<String> {
186 let guard = self.access_token.lock().unwrap();
187 guard.as_ref().map(|t| t.value.clone())
188 }
189
190 fn is_access_token_expired(&self) -> bool {
191 let guard = self.access_token.lock().unwrap();
192 match guard.as_ref() {
193 Some(t) => t.is_expired(self.now_secs()),
194 None => true,
195 }
196 }
197
198 fn expire_access_token(&self) {
199 let mut guard = self.access_token.lock().unwrap();
200 *guard = None;
201 }
202
203 fn update_access_token(&self, access_token: &str, expires_in_seconds: i32) {
204 let mut guard = self.access_token.lock().unwrap();
205 *guard = Some(TokenEntry {
206 value: access_token.to_string(),
207 expires_at: Some(self.now_secs() + expires_in_seconds as i64),
208 });
209 }
210
211 fn access_token_lock(&self) -> Arc<AsyncMutex<()>> {
212 self.access_token_lock.clone()
213 }
214
215 fn is_stable_access_token(&self) -> bool {
216 self.stable_access_token
217 }
218
219 fn auto_refresh_token(&self) -> bool {
220 self.auto_refresh
221 }
222
223 fn http_proxy_host(&self) -> Option<&str> {
224 self.http_proxy_host.as_deref()
225 }
226
227 fn http_proxy_port(&self) -> Option<u16> {
228 self.http_proxy_port
229 }
230}
231
232pub use crate::enums::TicketType;