botrs 0.2.9

A Rust QQ Bot framework based on QQ Guild Bot API
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
# 令牌 API 参考

`Token` 结构体管理 QQ 频道机器人的身份验证凭据,包括应用 ID 和密钥,以及访问令牌的管理。

## 概述

```rust
pub struct Token {
    app_id: String,
    secret: String,
    access_token: Option<String>,
    expires_at: Option<u64>,
    refresh_mutex: Arc<Mutex<()>>,
}
```

`Token` 包含:
- 应用 ID 和密钥(由 QQ 提供)
- 访问令牌(从 QQ API 获取)
- 令牌过期时间和刷新互斥锁

## 构造函数

### `new`

使用给定的应用 ID 和密钥创建新令牌。

```rust
pub fn new<S1: Into<String>, S2: Into<String>>(app_id: S1, secret: S2) -> Self
```

#### 参数

- `app_id`: 机器人的应用 ID
- `secret`: 机器人的应用密钥

#### 返回值

返回新的 `Token` 实例。

#### 示例

```rust
use botrs::Token;

let token = Token::new("你的应用ID", "你的密钥");
```

### `from_env`

从环境变量创建令牌。

```rust
pub fn from_env() -> Result<Self, BotError>
```

期望的环境变量:
- `QQ_BOT_APP_ID`: 应用 ID
- `QQ_BOT_SECRET`: 应用密钥

#### 返回值

返回 `Result<Token, BotError>` - 成功时返回令牌,环境变量缺失时返回错误。

#### 示例

```rust
// 设置环境变量
std::env::set_var("QQ_BOT_APP_ID", "你的应用ID");
std::env::set_var("QQ_BOT_SECRET", "你的密钥");

let token = Token::from_env()?;
```

## 方法

### `validate`

验证令牌的格式和有效性。

```rust
pub fn validate(&self) -> Result<(), BotError>
```

检查:
- 应用 ID 不为空且格式正确
- 密钥不为空且长度足够

#### 返回值

验证成功时返回 `Ok(())`,否则返回描述错误的 `BotError`。

#### 示例

```rust
let token = Token::new("应用ID", "密钥");

match token.validate() {
    Ok(_) => println!("令牌有效"),
    Err(e) => eprintln!("令牌无效: {}", e),
}
```

### `authorization_header`

生成用于 API 请求的授权头。

```rust
pub fn authorization_header(&self) -> String
```

#### 返回值

返回格式为 `"Bot {app_id}.{secret}"` 的授权字符串。

#### 示例

```rust
let token = Token::new("123456", "secret123");
let auth_header = token.authorization_header();
println!("Authorization: {}", auth_header);
// 输出: Authorization: Bot 123456.secret123
```

### `get_access_token`

获取当前的访问令牌,如果过期则自动刷新。

```rust
pub async fn get_access_token(&self, http_client: &HttpClient) -> Result<String, BotError>
```

#### 参数

- `http_client`: HTTP 客户端用于刷新令牌

#### 返回值

返回有效的访问令牌或错误。

#### 示例

```rust
use botrs::{Token, HttpClient};

let token = Token::new("应用ID", "密钥");
let http_client = HttpClient::new();

match token.get_access_token(&http_client).await {
    Ok(access_token) => println!("访问令牌: {}", access_token),
    Err(e) => eprintln!("获取访问令牌失败: {}", e),
}
```

### `refresh_access_token`

强制刷新访问令牌。

```rust
pub async fn refresh_access_token(&self, http_client: &HttpClient) -> Result<(), BotError>
```

#### 参数

- `http_client`: HTTP 客户端用于 API 请求

#### 返回值

成功时返回 `Ok(())`,失败时返回 `BotError`。

### `is_access_token_expired`

检查当前访问令牌是否已过期。

```rust
pub fn is_access_token_expired(&self) -> bool
```

#### 返回值

如果令牌已过期或不存在返回 `true`,否则返回 `false`。

## 访问器

### `app_id`

获取应用 ID。

```rust
pub fn app_id(&self) -> &str
```

#### 示例

```rust
let token = Token::new("123456", "secret");
println!("应用 ID: {}", token.app_id());
```

### `secret`

获取应用密钥(出于安全考虑,实际实现可能会限制访问)。

```rust
pub fn secret(&self) -> &str
```

## 序列化支持

`Token` 支持 serde 序列化和反序列化,但访问令牌等敏感信息会被跳过。

```rust
use serde_json;

let token = Token::new("应用ID", "密钥");
let json = serde_json::to_string(&token)?;
let deserialized: Token = serde_json::from_str(&json)?;
```

## 使用示例

### 基础用法

```rust
use botrs::{Token, Client, Intents};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建令牌
    let token = Token::new("你的应用ID", "你的密钥");
    
    // 验证令牌
    token.validate()?;
    
    // 使用令牌创建客户端
    let intents = Intents::default();
    let client = Client::new(token, intents, handler, false)?;
    
    Ok(())
}
```

### 从环境变量加载

```rust
use botrs::Token;

fn load_token() -> Result<Token, Box<dyn std::error::Error>> {
    // 方法1: 直接从环境变量
    let token = Token::from_env()?;
    
    // 方法2: 手动读取环境变量
    let app_id = std::env::var("QQ_BOT_APP_ID")?;
    let secret = std::env::var("QQ_BOT_SECRET")?;
    let token = Token::new(app_id, secret);
    
    token.validate()?;
    Ok(token)
}
```

### 配置文件加载

```rust
use serde::{Deserialize, Serialize};
use std::fs;

#[derive(Serialize, Deserialize)]
struct Config {
    app_id: String,
    secret: String,
}

fn load_token_from_config(path: &str) -> Result<Token, Box<dyn std::error::Error>> {
    let config_data = fs::read_to_string(path)?;
    let config: Config = toml::from_str(&config_data)?;
    
    let token = Token::new(config.app_id, config.secret);
    token.validate()?;
    
    Ok(token)
}
```

### 访问令牌管理

```rust
use botrs::{Token, HttpClient};

async fn token_management_example() -> Result<(), Box<dyn std::error::Error>> {
    let token = Token::new("应用ID", "密钥");
    let http_client = HttpClient::new();
    
    // 检查令牌是否过期
    if token.is_access_token_expired() {
        println!("访问令牌已过期,正在刷新...");
        token.refresh_access_token(&http_client).await?;
    }
    
    // 获取有效的访问令牌
    let access_token = token.get_access_token(&http_client).await?;
    println!("当前访问令牌: {}", access_token);
    
    Ok(())
}
```

### 安全处理

```rust
use botrs::Token;
use std::fmt;

// 创建一个包装器来安全显示令牌信息
struct SafeTokenDisplay<'a>(&'a Token);

impl<'a> fmt::Display for SafeTokenDisplay<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Token {{ app_id: \"{}\", secret: \"***\" }}", 
               self.0.app_id())
    }
}

fn safe_token_logging() {
    let token = Token::new("123456", "secret123");
    
    // 安全地显示令牌信息
    println!("令牌信息: {}", SafeTokenDisplay(&token));
    
    // 避免直接打印令牌
    // println!("令牌: {:?}", token); // 不推荐
}
```

## 错误处理

### 常见错误类型

```rust
use botrs::{Token, BotError};

async fn handle_token_errors() {
    let token = Token::new("", ""); // 无效令牌
    
    match token.validate() {
        Ok(_) => println!("令牌有效"),
        Err(BotError::Authentication(msg)) => {
            eprintln!("身份验证错误: {}", msg);
        }
        Err(BotError::InvalidInput(msg)) => {
            eprintln!("输入无效: {}", msg);
        }
        Err(e) => {
            eprintln!("其他错误: {}", e);
        }
    }
}
```

### 访问令牌刷新错误

```rust
use botrs::{Token, HttpClient, BotError};

async fn handle_refresh_errors() {
    let token = Token::new("应用ID", "密钥");
    let http_client = HttpClient::new();
    
    match token.refresh_access_token(&http_client).await {
        Ok(_) => println!("令牌刷新成功"),
        Err(BotError::Authentication(_)) => {
            eprintln!("身份验证失败,检查应用ID和密钥");
        }
        Err(BotError::Network(_)) => {
            eprintln!("网络错误,稍后重试");
        }
        Err(BotError::RateLimited(retry_after)) => {
            eprintln!("速率限制,{}秒后重试", retry_after);
        }
        Err(e) => {
            eprintln!("刷新失败: {}", e);
        }
    }
}
```

## 最佳实践

### 安全存储

```rust
// 推荐:使用环境变量
std::env::set_var("QQ_BOT_APP_ID", "应用ID");
std::env::set_var("QQ_BOT_SECRET", "密钥");

// 推荐:使用配置文件(不提交到版本控制)
// config.toml (添加到 .gitignore)
// app_id = "应用ID"
// secret = "密钥"

// 不推荐:硬编码在源代码中
// let token = Token::new("hardcoded_id", "hardcoded_secret");
```

### 令牌验证

```rust
fn create_validated_token(app_id: &str, secret: &str) -> Result<Token, BotError> {
    let token = Token::new(app_id, secret);
    token.validate()?;
    Ok(token)
}
```

### 生产环境配置

```rust
use botrs::Token;

fn production_token_setup() -> Result<Token, Box<dyn std::error::Error>> {
    // 从环境变量或安全的配置服务加载
    let token = Token::from_env()
        .or_else(|_| load_from_secure_config())?;
    
    // 验证令牌
    token.validate()?;
    
    println!("令牌配置完成,应用ID: {}", token.app_id());
    Ok(token)
}

fn load_from_secure_config() -> Result<Token, BotError> {
    // 从安全配置服务、加密文件等加载
    todo!("实现安全配置加载")
}
```

### 开发环境助手

```rust
#[cfg(debug_assertions)]
fn development_token() -> Token {
    Token::new(
        std::env::var("DEV_APP_ID").unwrap_or_else(|_| "dev_app_id".to_string()),
        std::env::var("DEV_SECRET").unwrap_or_else(|_| "dev_secret".to_string())
    )
}

#[cfg(not(debug_assertions))]
fn development_token() -> Token {
    panic!("开发令牌仅在调试模式下可用");
}
```

## 线程安全

`Token` 是线程安全的,可以在多个线程间共享:

```rust
use std::sync::Arc;
use tokio::task;

async fn shared_token_usage() {
    let token = Arc::new(Token::new("应用ID", "密钥"));
    
    let handles: Vec<_> = (0..5).map(|i| {
        let token = token.clone();
        task::spawn(async move {
            println!("任务 {} 使用令牌: {}", i, token.app_id());
        })
    }).collect();
    
    for handle in handles {
        handle.await.unwrap();
    }
}
```

## 另请参阅

- [`Client`]./client.md - 使用令牌创建客户端
- [`BotApi`]./bot-api.md - API 请求中的令牌使用
- [配置指南]/zh/guide/configuration.md - 令牌配置最佳实践
- [安全指南]/zh/guide/security.md - 令牌安全存储和使用