# EventHandler

`EventHandler` 是你需要实现的 async trait，用于响应网关事件。每个方法都有一个空的默认实现，因此只需要重写自己关心的事件——一个空结构体也能编译通过。

```rust
#[async_trait::async_trait]
pub trait EventHandler: Send + Sync {
    async fn ready(&self, _ctx: Context, _ready: Ready) {}
    async fn message_create(&self, _ctx: Context, _message: Message) {}
    /* … */
}
```

框架会根据网关事件类型分发到对应方法，传入新构造的 `Context`（克隆成本很低）以及类型化的载荷。所有方法返回 `()`；如果需要上报错误，请在本地记录日志——网关事件的回调错误不会中断连接。

## 方法目录

按事件类别分组列出。

### 生命周期

- `ready(ctx, Ready)` —— identify 握手成功后调用一次；此时 `ctx.bot_info` 已被填充。
- `resumed(ctx)` —— resume 成功后调用。
- `error_notify(ctx, BotError)` —— 网关层错误被捕获时触发。
- `plain_event(ctx, GatewayEvent)` —— 通过 `RegisterHandlers` 注册的全量原始事件兜底回调。

### 频道消息

- `message_create(ctx, Message)` —— 频道消息及 `@mention`。
- `message_delete(ctx, MessageDelete)` —— 频道消息被删除。
- `public_message_delete(ctx, MessageDelete)` —— 公域消息删除。
- `at_message_create(ctx, Message)` —— 单独配置 `@mention` 时使用的别名事件。

### 私信

- `direct_message_create(ctx, Message)`
- `direct_message_delete(ctx, MessageDelete)`

### 群 / C2C

- `group_message_create(ctx, GroupMessage)`
- `c2c_message_create(ctx, C2CMessage)`
- `friend_add(ctx, C2CManageEvent)` / `friend_del(ctx, C2CManageEvent)`
- `c2c_msg_reject` / `c2c_msg_receive`
- `subscribe_message_status(ctx, SubscribeMessageStatusData)`
- `enter_aio(ctx, EnterAioEvent)`

### 群管理

- `group_add_robot` / `group_del_robot`
- `group_msg_reject` / `group_msg_receive`

### 表情回应

- `message_reaction_add(ctx, Reaction)` / `message_reaction_remove(ctx, Reaction)`

### 互动

- `interaction_create(ctx, Interaction)` —— 按钮、应用互动事件；通过 `ctx.put_interaction(...)` 应答。

### 音频 / 语音

- `audio_start` / `audio_finish` / `on_mic` / `off_mic` —— 载荷为 `Audio`。
- `audio_or_live_channel_member_enter` / `audio_or_live_channel_member_exit` —— 载荷为 `PublicAudio`。

### 频道 / 子频道

- `guild_create` / `guild_update` / `guild_delete`
- `channel_create` / `channel_update` / `channel_delete`
- `guild_member_add` / `guild_member_update` / `guild_member_remove`

### 审核

- `message_audit_pass` / `message_audit_reject`

### 论坛

- `forum_thread_create` / `forum_thread_update` / `forum_thread_delete`
- `forum_post_create` / `forum_post_delete`
- `forum_reply_create` / `forum_reply_delete`
- `forum_publish_audit_result(ctx, ForumAuditResult)`
- 开放论坛等价方法：`open_forum_thread_*`、`open_forum_post_*`、`open_forum_reply_*`。

## 最小实现

```rust
use botrs::{Client, Context, EventHandler, Intents, Message, Ready, Token};

struct MyBot;

#[async_trait::async_trait]
impl EventHandler for MyBot {
    async fn ready(&self, _ctx: Context, ready: Ready) {
        info!("logged in as {}", ready.user.username);
    }

    async fn message_create(&self, ctx: Context, message: Message) {
        if message.is_from_bot() { return; }
        if let Some(content) = &message.content {
            if content.trim() == "!ping" {
                let _ = message.reply(&ctx.api, &ctx.token, "Pong!").await;
            }
        }
    }
}
```

`MyBot` 只处理两种事件，其他网关事件都会走默认的空实现。

## 并发

每个回调都在派发该事件的运行时任务上执行。耗时操作应当 spawn 出去，避免阻塞后续派发：

```rust
let ctx = ctx.clone();
tokio::spawn(async move {
    if let Err(e) = run_long_task(&ctx).await {
        warn!("background task failed: {e}");
    }
});
```

`Context` 是 `Clone` 的，`BotApi` 内部用 `Arc` 包裹，所以常见路径几乎不产生分配。

## 参见

- [Client](./client.md) —— 如何构造和启动 `Client<H: EventHandler>`。
- [Context](./context.md) —— 每个方法都会收到的上下文对象。
- [Intents](./intents.md) —— 决定哪些方法可能被触发。
