其他类型 API 参考
该模块涵盖了在 QQ 频道机器人 API 中使用的其他数据结构和工具类型。
音频和语音类型
Audio
表示语音子频道中的音频控制和状态。
rust
pub struct Audio {
pub audio_control: Option<AudioControl>,
pub audio_status: Option<AudioStatus>,
}
字段
audio_control
: 音频播放的控制操作audio_status
: 子频道中音频的当前状态
AudioControl
音频控制操作。
rust
pub struct AudioControl {
pub audio_url: Option<String>,
pub text: Option<String>,
pub status: Option<u32>,
}
字段
audio_url
: 要播放的音频文件 URLtext
: 音频的文本描述status
: 音频播放状态(0: 暂停,1: 播放)
AudioStatus
当前音频播放状态。
rust
pub struct AudioStatus {
pub start_time: Option<String>,
pub end_time: Option<String>,
pub status: Option<u32>,
}
字段
start_time
: 音频开始时间end_time
: 音频结束时间status
: 播放状态
示例
rust
async fn control_audio(ctx: Context, channel_id: &str) -> Result<()> {
let audio_control = AudioControl {
audio_url: Some("https://example.com/audio.mp3".to_string()),
text: Some("播放背景音乐".to_string()),
status: Some(1), // 开始播放
};
let audio = Audio {
audio_control: Some(audio_control),
audio_status: None,
};
// 控制音频播放
ctx.control_audio(channel_id, audio).await?;
println!("音频播放已开始");
Ok(())
}
时间和日期类型
Timestamp
表示时间戳,基于 chrono::DateTime<chrono::Utc>
。
rust
pub type Timestamp = chrono::DateTime<chrono::Utc>;
示例
rust
use chrono::Utc;
fn create_timestamp() -> Timestamp {
Utc::now()
}
fn format_timestamp(ts: &Timestamp) -> String {
ts.format("%Y-%m-%d %H:%M:%S UTC").to_string()
}
Snowflake
QQ API 中使用的雪花 ID 类型。
rust
pub type Snowflake = String;
字段说明
雪花 ID 是 QQ API 中用于唯一标识资源的字符串格式 ID,包括:
- 用户 ID
- 频道 ID
- 子频道 ID
- 消息 ID
- 身份组 ID
示例
rust
fn parse_snowflake_timestamp(snowflake: &Snowflake) -> Option<Timestamp> {
// 雪花 ID 包含时间戳信息
// 实际解析逻辑取决于 QQ 的雪花算法实现
snowflake.parse::<u64>().ok().map(|id| {
// 简化示例 - 实际实现会更复杂
let timestamp = (id >> 22) + 1420070400000; // QQ epoch
chrono::DateTime::from_timestamp_millis(timestamp as i64)
.unwrap_or_default()
.with_timezone(&chrono::Utc)
})
}
API 响应类型
ApiResponse<T>
标准 API 响应包装器。
rust
pub struct ApiResponse<T> {
pub code: i32,
pub message: String,
pub data: Option<T>,
}
字段
code
: 响应状态码message
: 响应消息data
: 响应数据(可选)
示例
rust
async fn handle_api_response<T>(response: ApiResponse<T>) -> Result<T, String> {
match response.code {
0 => {
if let Some(data) = response.data {
Ok(data)
} else {
Err("响应数据为空".to_string())
}
}
_ => Err(format!("API 错误 {}: {}", response.code, response.message))
}
}
PaginatedResponse<T>
分页响应类型。
rust
pub struct PaginatedResponse<T> {
pub items: Vec<T>,
pub total: Option<u32>,
pub has_more: bool,
pub next_cursor: Option<String>,
}
字段
items
: 当前页的项目列表total
: 总项目数(如果可用)has_more
: 是否还有更多页面next_cursor
: 下一页的游标
示例
rust
async fn fetch_all_items<T>(
ctx: Context,
fetch_fn: impl Fn(&str) -> Result<PaginatedResponse<T>>
) -> Result<Vec<T>> {
let mut all_items = Vec::new();
let mut cursor: Option<String> = None;
loop {
let response = fetch_fn(cursor.as_deref().unwrap_or(""))?;
all_items.extend(response.items);
if !response.has_more {
break;
}
cursor = response.next_cursor;
}
Ok(all_items)
}
权限类型
Permission
表示权限值。
rust
pub type Permission = u64;
常见权限常量
rust
pub mod permissions {
use super::Permission;
pub const VIEW_CHANNEL: Permission = 1 << 0;
pub const MANAGE_CHANNEL: Permission = 1 << 1;
pub const SEND_MESSAGES: Permission = 1 << 2;
pub const MANAGE_MESSAGES: Permission = 1 << 3;
pub const EMBED_LINKS: Permission = 1 << 4;
pub const ATTACH_FILES: Permission = 1 << 5;
pub const READ_MESSAGE_HISTORY: Permission = 1 << 6;
pub const MENTION_EVERYONE: Permission = 1 << 7;
pub const CONNECT: Permission = 1 << 8;
pub const SPEAK: Permission = 1 << 9;
pub const MUTE_MEMBERS: Permission = 1 << 10;
pub const DEAFEN_MEMBERS: Permission = 1 << 11;
}
示例
rust
use crate::permissions::*;
fn check_permissions(user_permissions: Permission, required: Permission) -> bool {
(user_permissions & required) == required
}
fn has_basic_permissions(permissions: Permission) -> bool {
check_permissions(permissions, VIEW_CHANNEL | SEND_MESSAGES)
}
fn can_moderate(permissions: Permission) -> bool {
check_permissions(permissions, MANAGE_MESSAGES | MUTE_MEMBERS)
}
async fn validate_user_action(
ctx: Context,
channel_id: &str,
user_id: &str,
action: &str
) -> Result<bool> {
let perms = ctx.get_channel_user_permissions(channel_id, user_id).await?;
let permission_value = perms.permissions.parse::<Permission>().unwrap_or(0);
match action {
"send_message" => Ok(check_permissions(permission_value, SEND_MESSAGES)),
"attach_file" => Ok(check_permissions(permission_value, ATTACH_FILES)),
"moderate" => Ok(can_moderate(permission_value)),
_ => Ok(false),
}
}
枚举类型
EventType
事件类型枚举。
rust
#[derive(Debug, Clone, PartialEq)]
pub enum EventType {
Ready,
GuildCreate,
GuildUpdate,
GuildDelete,
ChannelCreate,
ChannelUpdate,
ChannelDelete,
MessageCreate,
MessageUpdate,
MessageDelete,
DirectMessageCreate,
GroupMessageCreate,
C2CMessageCreate,
MemberAdd,
MemberUpdate,
MemberRemove,
Unknown(String),
}
示例
rust
impl EventType {
pub fn from_string(event: &str) -> Self {
match event {
"READY" => EventType::Ready,
"GUILD_CREATE" => EventType::GuildCreate,
"MESSAGE_CREATE" => EventType::MessageCreate,
"DIRECT_MESSAGE_CREATE" => EventType::DirectMessageCreate,
"GROUP_AT_MESSAGE_CREATE" => EventType::GroupMessageCreate,
"C2C_MESSAGE_CREATE" => EventType::C2CMessageCreate,
_ => EventType::Unknown(event.to_string()),
}
}
pub fn is_message_event(&self) -> bool {
matches!(self,
EventType::MessageCreate |
EventType::DirectMessageCreate |
EventType::GroupMessageCreate |
EventType::C2CMessageCreate
)
}
}
ChannelType
子频道类型枚举(重新导出以便引用)。
rust
#[derive(Debug, Clone, PartialEq)]
pub enum ChannelType {
Text = 0,
Voice = 1,
Category = 4,
Announcement = 5,
Forum = 10,
Live = 11,
Application = 12,
}
错误类型
BotError
主要错误类型。
rust
#[derive(Debug, thiserror::Error)]
pub enum BotError {
#[error("HTTP 错误: {0}")]
Http(u16),
#[error("频率限制: 请在 {0} 秒后重试")]
RateLimit(u64),
#[error("无效数据: {0}")]
InvalidData(String),
#[error("认证失败: {0}")]
Authentication(String),
#[error("权限不足")]
Insufficient Permissions,
#[error("网络错误: {0}")]
Network(String),
#[error("JSON 解析错误: {0}")]
Json(#[from] serde_json::Error),
#[error("WebSocket 错误: {0}")]
WebSocket(String),
#[error("超时")]
Timeout,
#[error("未知错误: {0}")]
Unknown(String),
}
示例
rust
impl BotError {
pub fn is_retryable(&self) -> bool {
matches!(self,
BotError::Network(_) |
BotError::Timeout |
BotError::Http(500..=599)
)
}
pub fn retry_delay(&self) -> Option<std::time::Duration> {
match self {
BotError::RateLimit(seconds) => Some(std::time::Duration::from_secs(*seconds)),
BotError::Network(_) => Some(std::time::Duration::from_secs(5)),
BotError::Timeout => Some(std::time::Duration::from_secs(3)),
_ => None,
}
}
}
配置类型
ClientConfig
客户端配置。
rust
pub struct ClientConfig {
pub timeout: std::time::Duration,
pub max_retries: u32,
pub retry_delay: std::time::Duration,
pub enable_cache: bool,
pub cache_size: usize,
pub user_agent: String,
}
默认实现
rust
impl Default for ClientConfig {
fn default() -> Self {
Self {
timeout: std::time::Duration::from_secs(30),
max_retries: 3,
retry_delay: std::time::Duration::from_secs(1),
enable_cache: true,
cache_size: 1000,
user_agent: format!("BotRS/{}", env!("CARGO_PKG_VERSION")),
}
}
}
示例
rust
fn create_custom_config() -> ClientConfig {
ClientConfig {
timeout: std::time::Duration::from_secs(60),
max_retries: 5,
retry_delay: std::time::Duration::from_millis(500),
enable_cache: true,
cache_size: 2000,
user_agent: "MyBot/1.0".to_string(),
}
}
实用工具类型
HasId
为具有 ID 的类型提供的 trait。
rust
pub trait HasId {
fn id(&self) -> &str;
}
实现示例
rust
impl HasId for Message {
fn id(&self) -> &str {
self.id.as_deref().unwrap_or("")
}
}
impl HasId for Channel {
fn id(&self) -> &str {
&self.id
}
}
impl HasId for Guild {
fn id(&self) -> &str {
&self.id
}
}
Cacheable
可缓存类型的 trait。
rust
pub trait Cacheable: HasId + Clone {
fn cache_key(&self) -> String {
format!("{}:{}", std::any::type_name::<Self>(), self.id())
}
fn is_expired(&self, max_age: std::time::Duration) -> bool {
// 默认实现 - 具体类型可以重写
false
}
}
常见使用模式
错误处理
rust
async fn handle_api_call<F, T>(operation: F) -> Result<T, BotError>
where
F: FnOnce() -> Result<T, BotError>,
{
let mut retries = 3;
loop {
match operation() {
Ok(result) => return Ok(result),
Err(error) => {
if error.is_retryable() && retries > 0 {
retries -= 1;
if let Some(delay) = error.retry_delay() {
tokio::time::sleep(delay).await;
}
continue;
}
return Err(error);
}
}
}
}
权限检查
rust
async fn ensure_permissions(
ctx: Context,
channel_id: &str,
user_id: &str,
required: Permission,
) -> Result<(), BotError> {
let perms = ctx.get_channel_user_permissions(channel_id, user_id).await?;
let permission_value = perms.permissions.parse::<Permission>()
.map_err(|e| BotError::InvalidData(format!("权限解析失败: {}", e)))?;
if !check_permissions(permission_value, required) {
return Err(BotError::InsufficientPermissions);
}
Ok(())
}
分页数据处理
rust
async fn collect_all_members(ctx: Context, guild_id: &str) -> Result<Vec<Member>> {
let mut all_members = Vec::new();
let mut after: Option<String> = None;
let limit = 100;
loop {
let members = ctx.get_guild_members(guild_id, Some(limit), after.as_deref()).await?;
if members.is_empty() {
break;
}
// 获取最后一个成员的 ID 用于分页
if let Some(last_member) = members.last() {
if let Some(user) = &last_member.user {
after = Some(user.id.clone());
}
}
all_members.extend(members);
// 如果返回的数量小于限制,说明已经是最后一页
if members.len() < limit as usize {
break;
}
}
Ok(all_members)
}