# Webhook 配置说明文档

## 概述

Webhook 配置用于设置 OpenIM 服务器在特定事件发生时的回调通知。配置支持从数据库动态读取，每小时自动刷新一次。如果数据库中没有配置或配置无效，将使用 `config/webhooks.yml` 中的默认配置。

## 配置结构

### 基础字段

- **url** (string, 必填): Webhook 回调服务器的地址，所有回调请求都会发送到这个地址

### BeforeConfig（前置回调配置）

前置回调在操作执行前触发，可以阻止或修改操作。

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| enable | boolean | 是 | 是否启用该回调 |
| timeout | integer | 是 | 超时时间（秒） |
| failedContinue | boolean | 是 | 回调失败时是否继续执行原操作（true=继续，false=停止） |
| deniedTypes | array[int32] | 否 | 不触发回调的消息类型列表，空数组表示所有类型都触发 |

### AfterConfig（后置回调配置）

后置回调在操作执行后触发，用于通知和记录。

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| enable | boolean | 是 | 是否启用该回调 |
| timeout | integer | 是 | 超时时间（秒） |
| attentionIds | array[string] | 否 | 仅对指定用户ID或群组ID触发回调，空数组表示所有都触发 |
| deniedTypes | array[int32] | 否 | 不触发回调的消息类型列表，空数组表示所有类型都触发 |

## 支持的回调事件

### 消息相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeSendSingleMsg | BeforeConfig | 发送单聊消息前 |
| afterSendSingleMsg | AfterConfig | 发送单聊消息后 |
| beforeSendGroupMsg | BeforeConfig | 发送群聊消息前 |
| afterSendGroupMsg | AfterConfig | 发送群聊消息后 |
| beforeMsgModify | BeforeConfig | 修改消息前（可用于消息过滤） |
| afterMsgSaveDB | AfterConfig | 消息保存到数据库后 |
| afterRevokeMsg | AfterConfig | 撤回消息后 |
| afterGroupMsgRevoke | AfterConfig | 撤回群消息后 |
| afterGroupMsgRead | AfterConfig | 群消息已读后 |
| afterSingleMsgRead | AfterConfig | 单聊消息已读后 |

### 用户相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeUserRegister | BeforeConfig | 用户注册前 |
| afterUserRegister | AfterConfig | 用户注册后 |
| beforeUpdateUserInfo | BeforeConfig | 更新用户信息前 |
| afterUpdateUserInfo | AfterConfig | 更新用户信息后 |
| beforeUpdateUserInfoEx | BeforeConfig | 更新用户扩展信息前 |
| afterUpdateUserInfoEx | AfterConfig | 更新用户扩展信息后 |
| afterUserOnline | AfterConfig | 用户上线后 |
| afterUserOffline | AfterConfig | 用户下线后 |
| afterUserKickOff | AfterConfig | 用户被踢下线后 |

### 群组相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeCreateGroup | BeforeConfig | 创建群组前 |
| afterCreateGroup | AfterConfig | 创建群组后 |
| beforeSetGroupInfo | BeforeConfig | 设置群组信息前 |
| afterSetGroupInfo | AfterConfig | 设置群组信息后 |
| beforeSetGroupInfoEx | BeforeConfig | 设置群组扩展信息前 |
| afterSetGroupInfoEx | AfterConfig | 设置群组扩展信息后 |
| beforeMemberJoinGroup | BeforeConfig | 成员加入群组前 |
| afterJoinGroup | AfterConfig | 成员加入群组后 |
| beforeApplyJoinGroup | BeforeConfig | 申请加入群组前 |
| beforeInviteUserToGroup | BeforeConfig | 邀请用户加入群组前 |
| afterQuitGroup | AfterConfig | 退出群组后 |
| afterKickGroupMember | AfterConfig | 踢出群成员后 |
| afterDismissGroup | AfterConfig | 解散群组后 |
| afterTransferGroupOwner | AfterConfig | 转移群主后 |
| beforeSetGroupMemberInfo | BeforeConfig | 设置群成员信息前 |
| afterSetGroupMemberInfo | AfterConfig | 设置群成员信息后 |

### 好友相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeAddFriend | BeforeConfig | 添加好友前 |
| afterAddFriend | AfterConfig | 添加好友后 |
| beforeAddFriendAgree | BeforeConfig | 同意好友申请前 |
| afterAddFriendAgree | AfterConfig | 同意好友申请后 |
| afterDeleteFriend | AfterConfig | 删除好友后 |
| beforeSetFriendRemark | BeforeConfig | 设置好友备注前 |
| afterSetFriendRemark | AfterConfig | 设置好友备注后 |
| beforeImportFriends | BeforeConfig | 导入好友前 |
| afterImportFriends | AfterConfig | 导入好友后 |
| beforeAddBlack | BeforeConfig | 加入黑名单前 |
| afterRemoveBlack | AfterConfig | 移除黑名单后 |

### 推送相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeOfflinePush | BeforeConfig | 离线推送前 |
| beforeOnlinePush | BeforeConfig | 在线推送前 |
| beforeGroupOnlinePush | BeforeConfig | 群组在线推送前 |

### 会话相关

| 事件名称 | 类型 | 说明 |
|---------|------|------|
| beforeCreateSingleChatConversations | BeforeConfig | 创建单聊会话前 |
| afterCreateSingleChatConversations | AfterConfig | 创建单聊会话后 |
| beforeCreateGroupChatConversations | BeforeConfig | 创建群聊会话前 |
| afterCreateGroupChatConversations | AfterConfig | 创建群聊会话后 |

## JSON 配置示例

### 完整配置示例

```json
{
  "url": "http://your-webhook-server:8080/callback",
  "beforeSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeSendGroupMsg": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSendGroupMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeMsgModify": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterMsgSaveDB": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterUserOnline": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterUserOffline": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterUserKickOff": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeOfflinePush": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "beforeOnlinePush": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "beforeGroupOnlinePush": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "beforeAddFriend": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "beforeUpdateUserInfo": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterUpdateUserInfo": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeCreateGroup": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterCreateGroup": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeMemberJoinGroup": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "beforeSetGroupMemberInfo": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSetGroupMemberInfo": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterQuitGroup": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterKickGroupMember": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterDismissGroup": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeApplyJoinGroup": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterGroupMsgRead": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterSingleMsgRead": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeUserRegister": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterUserRegister": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterTransferGroupOwner": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeSetFriendRemark": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSetFriendRemark": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterGroupMsgRevoke": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterJoinGroup": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeInviteUserToGroup": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSetGroupInfo": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeSetGroupInfo": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSetGroupInfoEx": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeSetGroupInfoEx": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterRevokeMsg": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeAddBlack": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterAddFriend": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeAddFriendAgree": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterAddFriendAgree": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterDeleteFriend": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeImportFriends": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterImportFriends": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "afterRemoveBlack": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeCreateSingleChatConversations": {
    "enable": false,
    "timeout": 5,
    "failedContinue": false,
    "deniedTypes": []
  },
  "afterCreateSingleChatConversations": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeCreateGroupChatConversations": {
    "enable": false,
    "timeout": 5,
    "failedContinue": false,
    "deniedTypes": []
  },
  "afterCreateGroupChatConversations": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeUpdateUserInfoEx": {
    "enable": false,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterUpdateUserInfoEx": {
    "enable": false,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  }
}
```

### 最小配置示例（仅启用消息回调）

```json
{
  "url": "http://your-webhook-server:8080/callback",
  "beforeSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  },
  "beforeSendGroupMsg": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": []
  },
  "afterSendGroupMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": [],
    "deniedTypes": []
  }
}
```

### 过滤特定消息类型示例

```json
{
  "url": "http://your-webhook-server:8080/callback",
  "beforeSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "failedContinue": true,
    "deniedTypes": [101, 102]
  }
}
```

### 仅关注特定用户/群组示例

```json
{
  "url": "http://your-webhook-server:8080/callback",
  "afterSendSingleMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": ["user001", "user002"],
    "deniedTypes": []
  },
  "afterSendGroupMsg": {
    "enable": true,
    "timeout": 5,
    "attentionIds": ["group001", "group002"],
    "deniedTypes": []
  }
}
```

## 配置说明

### URL 配置

- **格式**: `http://host:port/path` 或 `https://host:port/path`
- **示例**: 
  - `http://127.0.0.1:8080/callback`
  - `http://webhook.example.com:8080/callback`
  - `https://webhook.example.com/callback`

### timeout（超时时间）

- **单位**: 秒
- **建议值**: 5-30 秒
- **说明**: 如果回调服务器在超时时间内没有响应，将根据 `failedContinue` 决定是否继续执行

### failedContinue（失败是否继续）

- **仅适用于**: BeforeConfig 类型的事件
- **true**: 回调失败时继续执行原操作
- **false**: 回调失败时停止执行原操作

### deniedTypes（拒绝的消息类型）

- **类型**: 整数数组
- **说明**: 列表中的消息类型不会触发回调
- **空数组**: 表示所有消息类型都触发回调
- **常用消息类型**:
  - 101: 文本消息
  - 102: 图片消息
  - 103: 语音消息
  - 104: 视频消息
  - 105: 文件消息

### attentionIds（关注ID列表）

- **仅适用于**: AfterConfig 类型的事件
- **类型**: 字符串数组
- **说明**: 
  - 对于消息回调：仅对指定的用户ID或群组ID触发回调
  - 空数组表示所有用户/群组都触发回调
- **示例**: `["user001", "user002", "group001"]`

## 配置存储

### 数据库存储

配置可以存储在 MongoDB 的 `system_configs` 表中：

- **表名**: `system_configs`
- **配置键**: `webhook_config`
- **值类型**: JSON (ValueType = 4)

### 配置优先级

1. **数据库配置**（如果存在且有效）
2. **文件配置**（`config/webhooks.yml`）

如果数据库中没有配置或配置无效（为空、禁用、格式错误等），将自动使用文件配置。

## 配置刷新

- **刷新间隔**: 30 秒（调试模式，生产环境建议改为1小时）
- **自动刷新**: 服务启动后自动开始定时刷新
- **立即生效**: 配置更新后，最多30秒内自动生效（无需重启服务）

## 注意事项

1. **URL 必须有效**: 配置的 URL 必须可访问，否则回调会失败
2. **超时设置**: 建议根据回调服务器的响应时间合理设置超时时间
3. **失败处理**: BeforeConfig 类型的回调建议设置 `failedContinue: true`，避免因回调失败影响正常业务
4. **性能考虑**: 启用过多回调可能影响系统性能，建议按需启用
5. **安全性**: 确保回调服务器有适当的认证机制

