mirror of
https://github.com/zhamao-robot/go-cqhttp-adapter-plugin.git
synced 2026-03-17 20:24:51 +08:00
update to 1.1.0 version
This commit is contained in:
parent
934ebbec42
commit
33ae4dbf82
304
README.md
304
README.md
@ -1,152 +1,152 @@
|
|||||||
# go-cqhttp-adapter-plugin
|
# go-cqhttp-adapter-plugin
|
||||||
|
|
||||||
炸毛框架用于接入 go-cqhttp(OneBot 11)的适配器插件。
|
炸毛框架用于接入 go-cqhttp(OneBot 11)的适配器插件。
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
|
|
||||||
该插件将 gocq 的反向 WebSocket 接入信息全部转换为 OneBot 12 标准,安装该插件后几乎无需修改任何代码即可接入。
|
该插件将 gocq 的反向 WebSocket 接入信息全部转换为 OneBot 12 标准,安装该插件后几乎无需修改任何代码即可接入。
|
||||||
|
|
||||||
如果你想在其他项目上使用,也可以单独使用内部的 Converter 相关类进行转换。
|
如果你想在其他项目上使用,也可以单独使用内部的 Converter 相关类进行转换。
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Composer 安装稳定版
|
# Composer 安装稳定版
|
||||||
composer require zhamao/go-cqhttp-adapter-plugin
|
composer require zhamao/go-cqhttp-adapter-plugin
|
||||||
|
|
||||||
# GitHub 安装 Nightly 版
|
# GitHub 安装 Nightly 版
|
||||||
./zhamao plugin:install https://github.com/zhamao-robot/go-cqhttp-adapter-plugin.git
|
./zhamao plugin:install https://github.com/zhamao-robot/go-cqhttp-adapter-plugin.git
|
||||||
```
|
```
|
||||||
|
|
||||||
## 转换注意事项
|
## 转换注意事项
|
||||||
|
|
||||||
由于 OneBot 11 和 OneBot 12 有较多差异,而这些差异也导致两者不能无损相互转换。
|
由于 OneBot 11 和 OneBot 12 有较多差异,而这些差异也导致两者不能无损相互转换。
|
||||||
例如 OneBot 11 中未规定要求文件分片上传和下载的动作,那么在使用本插件时也无法使用这些动作。
|
例如 OneBot 11 中未规定要求文件分片上传和下载的动作,那么在使用本插件时也无法使用这些动作。
|
||||||
|
|
||||||
由于 OneBot 11 的实现较多,而且和 OneBot 11 本身相差较大,该插件也时重点针对 go-cqhttp 进行适配转换,这也是插件不叫 onebot-11-adapter 的原因。
|
由于 OneBot 11 的实现较多,而且和 OneBot 11 本身相差较大,该插件也时重点针对 go-cqhttp 进行适配转换,这也是插件不叫 onebot-11-adapter 的原因。
|
||||||
|
|
||||||
本插件下方列举的事件转换规则仅为自身的一些转换细节处理方案,不代表 OneBot 11 和 OneBot 12 的事件定义。
|
本插件下方列举的事件转换规则仅为自身的一些转换细节处理方案,不代表 OneBot 11 和 OneBot 12 的事件定义。
|
||||||
但是本插件的转换规则也是 OneBot 11 和 OneBot 12 事件定义的一个参考,如果你想了解 OneBot 11 和 12 的差异,也可以阅读下方的转换规则。
|
但是本插件的转换规则也是 OneBot 11 和 OneBot 12 事件定义的一个参考,如果你想了解 OneBot 11 和 12 的差异,也可以阅读下方的转换规则。
|
||||||
|
|
||||||
## 事件转换规则(11 转 12)
|
## 事件转换规则(11 转 12)
|
||||||
|
|
||||||
下面是 `post_type` 转换规则:
|
下面是 `post_type` 转换规则:
|
||||||
|
|
||||||
- 字段名 `post_type` 转换为 `type`。
|
- 字段名 `post_type` 转换为 `type`。
|
||||||
- 如果 `post_type` 值为 `meta_event`,转换为 `meta`。
|
- 如果 `post_type` 值为 `meta_event`,转换为 `meta`。
|
||||||
- 如果 `post_type` 值为 `message_sent`,转换为 `message`。
|
- 如果 `post_type` 值为 `message_sent`,转换为 `message`。
|
||||||
|
|
||||||
下面是 `XXX_type` 转换规则:
|
下面是 `XXX_type` 转换规则:
|
||||||
|
|
||||||
- 如果 `post_type` 为 `message` 或 `message_sent`,将字段名 `message_type` 转换为 `detail_type`。
|
- 如果 `post_type` 为 `message` 或 `message_sent`,将字段名 `message_type` 转换为 `detail_type`。
|
||||||
- 如果 `post_type` 为 `meta_event`,将字段名 `meta_event_type` 转换为 `detail_type`。
|
- 如果 `post_type` 为 `meta_event`,将字段名 `meta_event_type` 转换为 `detail_type`。
|
||||||
- 如果 `post_type` 为 `notice`,将字段名 `notice_type` 转换为 `detail_type`。
|
- 如果 `post_type` 为 `notice`,将字段名 `notice_type` 转换为 `detail_type`。
|
||||||
- 如果 `post_type` 为 `request`,将字段名 `request_type` 转换为 `detail_type`。
|
- 如果 `post_type` 为 `request`,将字段名 `request_type` 转换为 `detail_type`。
|
||||||
|
|
||||||
下面是 `self_id` 转换规则:
|
下面是 `self_id` 转换规则:
|
||||||
|
|
||||||
- 如果存在 `self_id` 字段,将该字段删除,替换为 `"self" => ["user_id" => $user_id, "platform" => "qq"]`,其中 `$user_id` 的值等于 `self_id` 的字符串值。
|
- 如果存在 `self_id` 字段,将该字段删除,替换为 `"self" => ["user_id" => $user_id, "platform" => "qq"]`,其中 `$user_id` 的值等于 `self_id` 的字符串值。
|
||||||
- 如果不存在 `self_id` 字段,将该字段删除,替换为和上方一样的格式,`$user_id` 的值等于该连接请求握手时 `X-Self-ID` 的值。
|
- 如果不存在 `self_id` 字段,将该字段删除,替换为和上方一样的格式,`$user_id` 的值等于该连接请求握手时 `X-Self-ID` 的值。
|
||||||
|
|
||||||
下面是 `user_id`、`group_id`、`guild_id`、`channel_id`、`message_id` 转换规则:
|
下面是 `user_id`、`group_id`、`guild_id`、`channel_id`、`message_id` 转换规则:
|
||||||
|
|
||||||
- 以上列举的值都取字符串值,即转换为字符串。
|
- 以上列举的值都取字符串值,即转换为字符串。
|
||||||
|
|
||||||
下面是其他字段的一些转换规则:
|
下面是其他字段的一些转换规则:
|
||||||
|
|
||||||
- 如果 `post_type` 为 `message` 或 `message_sent`,则将 `raw_message` 转换为 `alt_message`。
|
- 如果 `post_type` 为 `message` 或 `message_sent`,则将 `raw_message` 转换为 `alt_message`。
|
||||||
- go-cqhttp 的消息事件中默认带有 `sender`,将其字段名转换为 `qq.sender`,内部参数不变。
|
- go-cqhttp 的消息事件中默认带有 `sender`,将其字段名转换为 `qq.sender`,内部参数不变。
|
||||||
- go-cqhttp 未提供事件的 ID,因此该插件会自动生成一个随机的 UUID 作为事件 ID。
|
- go-cqhttp 未提供事件的 ID,因此该插件会自动生成一个随机的 UUID 作为事件 ID。
|
||||||
|
|
||||||
下面是消息事件(`message`)的一些转换规则:
|
下面是消息事件(`message`)的一些转换规则:
|
||||||
|
|
||||||
- `message` 字段如果为字符串,会先将 CQ 码无损转换为 OneBot 11 的等价消息段,然后再将消息段转换为 OneBot 12 标准的消息段。
|
- `message` 字段如果为字符串,会先将 CQ 码无损转换为 OneBot 11 的等价消息段,然后再将消息段转换为 OneBot 12 标准的消息段。
|
||||||
- CQ 码的转换基本按照 OneBot 11 的规范进行,但是由于 OneBot 11 的规范不完整,因此可能会有一些不同。例如,CQ 码在解码参数时未考虑参数内带有等号,该适配器仅会获取第一个等号前的参数,后面的等号会被当作值的一部分。
|
- CQ 码的转换基本按照 OneBot 11 的规范进行,但是由于 OneBot 11 的规范不完整,因此可能会有一些不同。例如,CQ 码在解码参数时未考虑参数内带有等号,该适配器仅会获取第一个等号前的参数,后面的等号会被当作值的一部分。
|
||||||
- 转换为 OneBot 12 的消息段时,仅保留 `type` 和 `data`,如果存在其他字段,将丢弃。
|
- 转换为 OneBot 12 的消息段时,仅保留 `type` 和 `data`,如果存在其他字段,将丢弃。
|
||||||
- `at` 类型,如果参数 `qq` 为 `all`,则类型转换为 `mention_all`,否则类型转换为 `mention` 同时 `qq` 字段名转换为 `user_id`。
|
- `at` 类型,如果参数 `qq` 为 `all`,则类型转换为 `mention_all`,否则类型转换为 `mention` 同时 `qq` 字段名转换为 `user_id`。
|
||||||
- `video`、`image`、`record` 类型,将参数 `file` 转换为 `file_id`。
|
- `video`、`image`、`record` 类型,将参数 `file` 转换为 `file_id`。
|
||||||
- `record` 类型转换为 `voice`。
|
- `record` 类型转换为 `voice`。
|
||||||
- `location` 类型,将参数 `lat` 转换为 `latitude`,将参数 `lon` 转换为 `longitude`。
|
- `location` 类型,将参数 `lat` 转换为 `latitude`,将参数 `lon` 转换为 `longitude`。
|
||||||
- `reply` 类型,将 `id` 转换为 `message_id`,如果存在参数 `qq`,将 `qq` 转换为 `user_id`。
|
- `reply` 类型,将 `id` 转换为 `message_id`,如果存在参数 `qq`,将 `qq` 转换为 `user_id`。
|
||||||
- 其他类型,类型字段名称统一添加前缀 `qq.`,例如 `forward` 转换为 `qq.forward`。
|
- 其他类型,类型字段名称统一添加前缀 `qq.`,例如 `forward` 转换为 `qq.forward`。
|
||||||
|
|
||||||
下面是通知事件(`notice`)的一些转换规则:
|
下面是通知事件(`notice`)的一些转换规则:
|
||||||
|
|
||||||
| go-cqhttp 的 `notice_type` | OneBot 12 的 `detail_type` | 描述 |
|
| go-cqhttp 的 `notice_type` | OneBot 12 的 `detail_type` | 描述 |
|
||||||
|---------------------------|---------------------------|-----------|
|
|---------------------------|---------------------------|-----------|
|
||||||
| `friend_recall` | `private_message_delete` | 撤回一条私聊消息 |
|
| `friend_recall` | `private_message_delete` | 撤回一条私聊消息 |
|
||||||
| `friend_add` | `friend_increase` | 添加好友的通知事件 |
|
| `friend_add` | `friend_increase` | 添加好友的通知事件 |
|
||||||
| `group_increase` | `group_member_increase` | 群成员增加 |
|
| `group_increase` | `group_member_increase` | 群成员增加 |
|
||||||
| `group_decrease` | `group_member_decrease` | 群成员减少 |
|
| `group_decrease` | `group_member_decrease` | 群成员减少 |
|
||||||
| `group_recall` | `group_message_delete` | 群消息撤回 |
|
| `group_recall` | `group_message_delete` | 群消息撤回 |
|
||||||
| 除上述外的其他通知事件 | `qq.` 前缀加上原名称 | |
|
| 除上述外的其他通知事件 | `qq.` 前缀加上原名称 | |
|
||||||
|
|
||||||
- `friend_recall` 转换后,仅保留 `message_id` 和 `user_id` 字段。
|
- `friend_recall` 转换后,仅保留 `message_id` 和 `user_id` 字段。
|
||||||
- `friend_add` 转换后,仅保留 `user_id` 字段。
|
- `friend_add` 转换后,仅保留 `user_id` 字段。
|
||||||
- `group_increase` 转换后,如果 `sub_type` 值为 `approve` 或空,则转换为 `join`;如果为 `invite` 则不变,如果是其他,则加上前缀 `qq.`。
|
- `group_increase` 转换后,如果 `sub_type` 值为 `approve` 或空,则转换为 `join`;如果为 `invite` 则不变,如果是其他,则加上前缀 `qq.`。
|
||||||
- `group_increase` 转换后,仅保留 `sub_type`、`group_id`、`user_id``operator_id` 且转换为字符串值。
|
- `group_increase` 转换后,仅保留 `sub_type`、`group_id`、`user_id``operator_id` 且转换为字符串值。
|
||||||
- `group_decrease` 转换后,如果 `sub_type` 值为 `kick` 或 `kick_me`,则转换为 `kick`;如果为 `leave` 则不变,如果是其他,则加上前缀 `qq.`。如果想判断是否为 `kick_me`,可以使用判断 `user_id` 和 `operator_id` 是否相同。
|
- `group_decrease` 转换后,如果 `sub_type` 值为 `kick` 或 `kick_me`,则转换为 `kick`;如果为 `leave` 则不变,如果是其他,则加上前缀 `qq.`。如果想判断是否为 `kick_me`,可以使用判断 `user_id` 和 `operator_id` 是否相同。
|
||||||
- `group_decrease` 转换后,仅保留 `sub_type`、`group_id`、`user_id``operator_id` 且转换为字符串值。
|
- `group_decrease` 转换后,仅保留 `sub_type`、`group_id`、`user_id``operator_id` 且转换为字符串值。
|
||||||
- `group_recall` 转换后,如果 `user_id` 与 `operator_id` 相同,则 `sub_type` 值设定为 `recall`,否则为 `delete`(分别代表自己撤回和被撤回)。
|
- `group_recall` 转换后,如果 `user_id` 与 `operator_id` 相同,则 `sub_type` 值设定为 `recall`,否则为 `delete`(分别代表自己撤回和被撤回)。
|
||||||
- `group_recall` 转换后,仅保留 `message_id`、`group_id`、`user_id`、`operator_id` 且转换为字符串值。
|
- `group_recall` 转换后,仅保留 `message_id`、`group_id`、`user_id`、`operator_id` 且转换为字符串值。
|
||||||
- 其他通知类事件加前缀,其他字段除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
- 其他通知类事件加前缀,其他字段除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
||||||
|
|
||||||
下面是请求事件(`request`)的一些转换规则:
|
下面是请求事件(`request`)的一些转换规则:
|
||||||
|
|
||||||
- 由于 OneBot 12 标准未规定任何 `request` 事件,故所有 `request` 事件均将 `request_type` 加上 `qq.` 前缀,并转换名称为 `detail_type`。
|
- 由于 OneBot 12 标准未规定任何 `request` 事件,故所有 `request` 事件均将 `request_type` 加上 `qq.` 前缀,并转换名称为 `detail_type`。
|
||||||
- 其他字段除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
- 其他字段除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
||||||
|
|
||||||
下面是元事件(`meta`)的一些转换规则:
|
下面是元事件(`meta`)的一些转换规则:
|
||||||
|
|
||||||
- `meta_event_type` 转换为 `detail_type`。
|
- `meta_event_type` 转换为 `detail_type`。
|
||||||
- 目前 go-cqhttp 仅有两种元事件,其中 `meta_event_type` 分别为 `lifecycle` 和 `heartbeat`。
|
- 目前 go-cqhttp 仅有两种元事件,其中 `meta_event_type` 分别为 `lifecycle` 和 `heartbeat`。
|
||||||
- 如果 `meta_event_type` 为 `lifecycle`,`sub_type` 为 `connect`,则将 `detail_type` 转换为 `connect`。
|
- 如果 `meta_event_type` 为 `lifecycle`,`sub_type` 为 `connect`,则将 `detail_type` 转换为 `connect`。
|
||||||
- 如果按照上面的规则转换为 `connect`,其中 OneBot 12 转换后的 `version` 内容为:`['impl' => 'go-cqhttp', 'version' => $user_agent, 'onebot_version' => '12']`。其中 `$user_agent` 为与 gocq 建立连接时对端发送过来的 `User-Agent` 值。
|
- 如果按照上面的规则转换为 `connect`,其中 OneBot 12 转换后的 `version` 内容为:`['impl' => 'go-cqhttp', 'version' => $user_agent, 'onebot_version' => '12']`。其中 `$user_agent` 为与 gocq 建立连接时对端发送过来的 `User-Agent` 值。
|
||||||
- 如果 `meta_event_type` 为 `heartbeat`,则参数仅保留 `interval`,类型名称不变。
|
- 如果 `meta_event_type` 为 `heartbeat`,则参数仅保留 `interval`,类型名称不变。
|
||||||
- 其他 `meta_evet_type`,不添加前缀,假设实现端有一个 `xxx` 元事件,则此处转换为 `detail_type` 依旧是 `xxx`。
|
- 其他 `meta_evet_type`,不添加前缀,假设实现端有一个 `xxx` 元事件,则此处转换为 `detail_type` 依旧是 `xxx`。
|
||||||
- 其他元事件的其他字段,除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
- 其他元事件的其他字段,除 `post_type`、`notice_type`、`sub_type`、`request_type`、`meta_event_type`、`time` 和一系列 `xxx_id` 外,均保留,并加上 `qq.` 前缀,值不变。
|
||||||
|
|
||||||
## 动作转换规则(12 转 11)
|
## 动作转换规则(12 转 11)
|
||||||
|
|
||||||
- `send_message` 动作根据参数 `detail_type` 的值,转换为对应的 `send_xxx_msg` 动作,但目前仅支持私聊和群组类型。
|
- `send_message` 动作根据参数 `detail_type` 的值,转换为对应的 `send_xxx_msg` 动作,但目前仅支持私聊和群组类型。
|
||||||
- 如果 `detail_type` 为 `group`,将保留 `group_id` 参数,并将 OneBot 12 消息段转换为 OneBot 11 消息段发送。
|
- 如果 `detail_type` 为 `group`,将保留 `group_id` 参数,并将 OneBot 12 消息段转换为 OneBot 11 消息段发送。
|
||||||
- 如果 `detail_type` 为 `private`,将保留 `user_id` 参数,如果传入的 Action 对象存在 `group_id` 参数也将会保留,然后将 OneBot 12 消息段转换为 OneBot 11 消息段发送。
|
- 如果 `detail_type` 为 `private`,将保留 `user_id` 参数,如果传入的 Action 对象存在 `group_id` 参数也将会保留,然后将 OneBot 12 消息段转换为 OneBot 11 消息段发送。
|
||||||
- `delete_message` 动作名称变更为 `delete_msg`,保留 `message_id` 参数。
|
- `delete_message` 动作名称变更为 `delete_msg`,保留 `message_id` 参数。
|
||||||
- `get_self_info` 动作名称变更为 `get_login_info`。
|
- `get_self_info` 动作名称变更为 `get_login_info`。
|
||||||
- `get_user_info` 动作名称变更为 `get_stranger_info`,保留 `user_id` 字段。
|
- `get_user_info` 动作名称变更为 `get_stranger_info`,保留 `user_id` 字段。
|
||||||
- `get_friend_list`、`get_group_info`、`get_group_list`、`get_group_member_info`、`get_group_member_list`、`set_group_name` 动作名称和参数均不变。
|
- `get_friend_list`、`get_group_info`、`get_group_list`、`get_group_member_info`、`get_group_member_list`、`set_group_name` 动作名称和参数均不变。
|
||||||
- `leave_group` 动作名称变更为 `set_group_leave`,参数不变。
|
- `leave_group` 动作名称变更为 `set_group_leave`,参数不变。
|
||||||
- `upload_file` 动作名称变更为 `download_file`,并且仅支持 URL 方式上传文件。
|
- `upload_file` 动作名称变更为 `download_file`,并且仅支持 URL 方式上传文件。
|
||||||
- `get_status` 名称和参数(好像也没有请求参数,不管了)均保持不变。
|
- `get_status` 名称和参数(好像也没有请求参数,不管了)均保持不变。
|
||||||
- `get_version` 动作名称变更为 `get_version_info`。
|
- `get_version` 动作名称变更为 `get_version_info`。
|
||||||
- 其他动作如果开头使用 `qq.` 前缀,则将其前缀去除,参数保持不变。
|
- 其他动作如果开头使用 `qq.` 前缀,则将其前缀去除,参数保持不变。
|
||||||
- `echo` 回响字段保持不变。
|
- `echo` 回响字段保持不变。
|
||||||
|
|
||||||
## 动作响应转换规则(11 转 12)
|
## 动作响应转换规则(11 转 12)
|
||||||
|
|
||||||
> 动作响应的转换在插件内部对动作请求做了缓存,通过 echo 字段进行匹配,从而确定响应对应的动作请求。
|
> 动作响应的转换在插件内部对动作请求做了缓存,通过 echo 字段进行匹配,从而确定响应对应的动作请求。
|
||||||
|
|
||||||
- `status`、`retcode`、`echo` 字段保持不变。
|
- `status`、`retcode`、`echo` 字段保持不变。
|
||||||
- `msg` 字段如果存在则转换为 `message` 字段。
|
- `msg` 字段如果存在则转换为 `message` 字段。
|
||||||
- 如果请求的动作是 `send_xxx_msg`,则响应中的 `message_id` 字段保持不变。
|
- 如果请求的动作是 `send_xxx_msg`,则响应中的 `message_id` 字段保持不变。
|
||||||
- 如果请求动作是 `get_stranger_info`,响应中的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值,`user_remark` 设置为空。
|
- 如果请求动作是 `get_stranger_info`,响应中的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值,`user_remark` 设置为空。
|
||||||
- 如果请求动作是 `get_login_info`,响应中的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值。
|
- 如果请求动作是 `get_login_info`,响应中的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值。
|
||||||
- 如果请求动作是 `get_friend_list`,每个用户元素的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值,`user_remark` 设置为空。
|
- 如果请求动作是 `get_friend_list`,每个用户元素的 `user_id` 保持不变,`nickname` 转换为 `user_name`,同时也将 `user_displayname` 设置为 `user_name` 相同的值,`user_remark` 设置为空。
|
||||||
- 如果请求动作是 `get_group_info` 或 `get_group_list`,参数保持不变。
|
- 如果请求动作是 `get_group_info` 或 `get_group_list`,参数保持不变。
|
||||||
- 如果请求动作是 `get_group_member_info`,现有参数转换规则同 `get_stranger_info` 的参数转换规则,其他参数的参数名添加前缀 `qq.`,值保持不变。
|
- 如果请求动作是 `get_group_member_info`,现有参数转换规则同 `get_stranger_info` 的参数转换规则,其他参数的参数名添加前缀 `qq.`,值保持不变。
|
||||||
- 如果请求动作是 `get_group_member_list`,每个用户元素的参数转换规则同 `get_group_member_info`。
|
- 如果请求动作是 `get_group_member_list`,每个用户元素的参数转换规则同 `get_group_member_info`。
|
||||||
- 如果请求动作是 `download_file`,响应中的 `file` 字段转换为 `file_id`。
|
- 如果请求动作是 `download_file`,响应中的 `file` 字段转换为 `file_id`。
|
||||||
- 如果请求动作是 `set_group_name`、`set_group_leave`,参数保持不变。
|
- 如果请求动作是 `set_group_name`、`set_group_leave`,参数保持不变。
|
||||||
- 如果请求动作是 `get_status`,仅保留 `good` 字段,OB12 的 `bots` 字段值为 `[['impl' => 'go-cqhttp', 'version' => $user_agent, 'onebot_version' => '12']]`。
|
- 如果请求动作是 `get_status`,仅保留 `good` 字段,OB12 的 `bots` 字段值为 `[['impl' => 'go-cqhttp', 'version' => $user_agent, 'onebot_version' => '12']]`。
|
||||||
- 如果请求动作是 `get_version_info`,`app_name` 转换为 `impl`,`app_version` 转换为 `version`,`onebot_version` 设置为 12,其他值丢弃。
|
- 如果请求动作是 `get_version_info`,`app_name` 转换为 `impl`,且 impl 值后附加 `(go-cqhttp-adapter converted)`,`app_version` 转换为 `version`,`onebot_version` 设置为 12,其他值丢弃。
|
||||||
|
|
||||||
## 其他不兼容项
|
## 其他不兼容项
|
||||||
|
|
||||||
转换器不支持转换以下 OneBot 12 动作到 OneBot 11 API:
|
转换器不支持转换以下 OneBot 12 动作到 OneBot 11 API:
|
||||||
|
|
||||||
- `get_latest_events`
|
- `get_latest_events`
|
||||||
- `get_supported_actions`
|
- `get_supported_actions`
|
||||||
- 所有二级群组动作,例如 `get_guild_info` 等
|
- 所有二级群组动作,例如 `get_guild_info` 等
|
||||||
- `upload_file_fragmented`
|
- `upload_file_fragmented`
|
||||||
- `get_file`
|
- `get_file`
|
||||||
- `get_file_fragmented`
|
- `get_file_fragmented`
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "zhamao/go-cqhttp-adapter-plugin",
|
"name": "zhamao/go-cqhttp-adapter-plugin",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"GocqAdapter\\": "src/"
|
"GocqAdapter\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~8.0 || ~8.1 || ~8.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"zhamao/framework": "dev-main"
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"extra": {
|
||||||
|
"zm-plugin-version": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "~8.0 || ~8.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"zhamao/framework": "dev-main"
|
|
||||||
},
|
|
||||||
"minimum-stability": "dev"
|
|
||||||
}
|
}
|
||||||
|
|||||||
80
src/GoActionTrait.php
Normal file
80
src/GoActionTrait.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GocqAdapter;
|
||||||
|
|
||||||
|
use OneBot\Driver\Coroutine\Adaptive;
|
||||||
|
use OneBot\V12\Object\Action;
|
||||||
|
use OneBot\V12\Object\ActionResponse;
|
||||||
|
use ZM\Annotation\AnnotationHandler;
|
||||||
|
use ZM\Annotation\OneBot\BotAction;
|
||||||
|
use ZM\Exception\OneBot12Exception;
|
||||||
|
use ZM\Plugin\OneBot\BotMap;
|
||||||
|
|
||||||
|
trait GoActionTrait
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 发送机器人动作
|
||||||
|
*
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function sendAction(string $action, array $params = [], ?array $self = null): bool|ActionResponse
|
||||||
|
{
|
||||||
|
if ($self === null && $this->self !== null) {
|
||||||
|
$self = $this->self;
|
||||||
|
}
|
||||||
|
// 声明 Action 对象
|
||||||
|
$a = new Action($action, $params, ob_uuidgen(), $self);
|
||||||
|
// 调用事件在回复之前的回调
|
||||||
|
$handler = new AnnotationHandler(BotAction::class);
|
||||||
|
container()->set(Action::class, $a);
|
||||||
|
$handler->setRuleCallback(fn (BotAction $act) => ($act->action === '' || $act->action === $action) && !$act->need_response);
|
||||||
|
$handler->handleAll();
|
||||||
|
// 被阻断时候,就不发送了
|
||||||
|
if ($handler->getStatus() === AnnotationHandler::STATUS_INTERRUPTED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从这里开始,gocq 需要做一个 12 -> 11 的转换
|
||||||
|
$action_array = GocqActionConverter::getInstance()->convertAction12To11($a);
|
||||||
|
// 将这个 action 提取出来需要记忆的 echo
|
||||||
|
GocqAdapter::$action_hold_list[$a->echo] = $action_array;
|
||||||
|
// 获取机器人的 BotMap 对应连接(前提是当前上下文有 self)
|
||||||
|
if ($self !== null) {
|
||||||
|
$fd_map = BotMap::getBotFd($self['user_id'], $self['platform']);
|
||||||
|
if ($fd_map === null) {
|
||||||
|
logger()->error("机器人 [{$self['platform']}:{$self['user_id']}] 没有连接或未就绪,无法发送数据");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$result = ws_socket($fd_map[0])->send(json_encode($action_array), $fd_map[1]);
|
||||||
|
} elseif ($this instanceof GoBotConnectContext) {
|
||||||
|
// self 为空,说明可能是发送的元动作,需要通过 fd 来查找对应的 connect 连接
|
||||||
|
$flag = $this->getFlag();
|
||||||
|
$fd = $this->getFd();
|
||||||
|
$result = ws_socket($flag)->send(json_encode($action_array), $fd);
|
||||||
|
} elseif (method_exists($this, 'emitSendAction')) {
|
||||||
|
$result = $this->emitSendAction($a);
|
||||||
|
} else {
|
||||||
|
logger()->error('未匹配到任何机器人连接');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果开启了协程,并且成功发送,那就进入协程等待,挂起等待结果返回一个 ActionResponse 对象
|
||||||
|
if (($result ?? false) === true && ($co = Adaptive::getCoroutine()) !== null) {
|
||||||
|
BotMap::$bot_coroutines[$a->echo] = $co->getCid();
|
||||||
|
$response = $co->suspend();
|
||||||
|
if ($response instanceof ActionResponse) {
|
||||||
|
$handler = new AnnotationHandler(BotAction::class);
|
||||||
|
$handler->setRuleCallback(fn(BotAction $act) => ($act->action === '' || $act->action === $action) && $act->need_response);
|
||||||
|
container()->set(ActionResponse::class, $response);
|
||||||
|
$handler->handleAll();
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isset($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
// 到这里表明你调用时候不在 WS 或 HTTP 上下文
|
||||||
|
throw new OneBot12Exception('No bot connection found.');
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/GoBotConnectContext.php
Normal file
10
src/GoBotConnectContext.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace GocqAdapter;
|
||||||
|
|
||||||
|
use ZM\Context\BotConnectContext;
|
||||||
|
|
||||||
|
class GoBotConnectContext extends BotConnectContext
|
||||||
|
{
|
||||||
|
use GoActionTrait;
|
||||||
|
}
|
||||||
@ -8,51 +8,12 @@ use OneBot\V12\Object\Action;
|
|||||||
use OneBot\V12\Object\ActionResponse;
|
use OneBot\V12\Object\ActionResponse;
|
||||||
use ZM\Annotation\AnnotationHandler;
|
use ZM\Annotation\AnnotationHandler;
|
||||||
use ZM\Annotation\OneBot\BotAction;
|
use ZM\Annotation\OneBot\BotAction;
|
||||||
|
use ZM\Context\BotConnectContext;
|
||||||
use ZM\Context\BotContext;
|
use ZM\Context\BotContext;
|
||||||
use ZM\Exception\OneBot12Exception;
|
use ZM\Exception\OneBot12Exception;
|
||||||
|
use ZM\Plugin\OneBot\BotMap;
|
||||||
|
|
||||||
class GoBotContext extends BotContext
|
class GoBotContext extends BotContext
|
||||||
{
|
{
|
||||||
public function sendAction(string $action, array $params = [], ?array $self = null): bool|ActionResponse
|
use GoActionTrait;
|
||||||
{
|
|
||||||
// 前面这里和 OneBot 12 的 sendAction 完全一样
|
|
||||||
// 声明 Action 对象
|
|
||||||
$a = new Action($action, $params, ob_uuidgen(), $self);
|
|
||||||
// 调用事件在回复之前的回调
|
|
||||||
$handler = new AnnotationHandler(BotAction::class);
|
|
||||||
container()->set(Action::class, $a);
|
|
||||||
$handler->setRuleCallback(fn (BotAction $act) => $act->action === '' || $act->action === $action && !$act->need_response);
|
|
||||||
$handler->handleAll($a);
|
|
||||||
// 被阻断时候,就不发送了
|
|
||||||
if ($handler->getStatus() === AnnotationHandler::STATUS_INTERRUPTED) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从这里开始,gocq 需要做一个 12 -> 11 的转换
|
|
||||||
$action_array = GocqActionConverter::getInstance()->convertAction12To11($a);
|
|
||||||
// 将这个 action 提取出来需要记忆的 echo
|
|
||||||
GocqAdapter::$action_hold_list[$a->echo] = $action_array;
|
|
||||||
|
|
||||||
// 调用机器人连接发送 Action
|
|
||||||
if ($this->base_event instanceof WebSocketMessageEvent) {
|
|
||||||
$result = $this->base_event->send(json_encode($action_array));
|
|
||||||
}
|
|
||||||
if (!isset($result) && container()->has('ws.message.event')) {
|
|
||||||
$result = container()->get('ws.message.event')->send(json_encode($action_array));
|
|
||||||
}
|
|
||||||
// 如果开启了协程,并且成功发送,那就进入协程等待,挂起等待结果返回一个 ActionResponse 对象
|
|
||||||
if (($result ?? false) === true && ($co = Adaptive::getCoroutine()) !== null) {
|
|
||||||
static::$coroutine_list[$a->echo] = $co->getCid();
|
|
||||||
$response = $co->suspend();
|
|
||||||
if ($response instanceof ActionResponse) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isset($result)) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
// 到这里表明你调用时候不在 WS 或 HTTP 上下文
|
|
||||||
throw new OneBot12Exception('No bot connection found.');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,13 +82,17 @@ class GocqActionConverter
|
|||||||
'thread_count' => $action->params['thread_count'] ?? 1,
|
'thread_count' => $action->params['thread_count'] ?? 1,
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
case 'get_version':
|
||||||
|
$act = 'get_version_info';
|
||||||
|
$params = $action->params;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// qq. 开头的动作,一律当作 gocq 的其他事件,这时候 params 原封不动发出
|
// qq. 开头的动作,一律当作 gocq 的其他事件,这时候 params 原封不动发出
|
||||||
if (str_starts_with($action->action, 'qq.')) {
|
if (str_starts_with($action->action, 'qq.')) {
|
||||||
$act = substr($action->action, 3);
|
$act = substr($action->action, 3);
|
||||||
$params = $action->params;
|
$params = $action->params;
|
||||||
} else {
|
} else {
|
||||||
throw new OneBot12Exception('Current action cannot send to gocq');
|
throw new OneBot12Exception('Current action cannot send to gocq: ' . $action->action);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -178,6 +182,13 @@ class GocqActionConverter
|
|||||||
'file_id' => $response['data']['file'],
|
'file_id' => $response['data']['file'],
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
|
case 'get_version_info':
|
||||||
|
$response_obj->data = [
|
||||||
|
'impl' => $response['data']['app_name'] . ' (go-cqhttp-adapter converted)',
|
||||||
|
'version' => $response['data']['app_version'],
|
||||||
|
'onebot_version' => '12',
|
||||||
|
];
|
||||||
|
break;
|
||||||
case 'set_group_name':
|
case 'set_group_name':
|
||||||
case 'set_group_leave':
|
case 'set_group_leave':
|
||||||
default:
|
default:
|
||||||
@ -195,6 +206,9 @@ class GocqActionConverter
|
|||||||
{
|
{
|
||||||
$msgs = [];
|
$msgs = [];
|
||||||
foreach ($message as $v) {
|
foreach ($message as $v) {
|
||||||
|
if (is_array($v)) {
|
||||||
|
$v = segment($v['type'], $v['data'] ?? []);
|
||||||
|
}
|
||||||
$msgs[] = GocqSegmentConverter::getInstance()->parseSegment12To11($v);
|
$msgs[] = GocqSegmentConverter::getInstance()->parseSegment12To11($v);
|
||||||
}
|
}
|
||||||
return $msgs;
|
return $msgs;
|
||||||
|
|||||||
@ -8,17 +8,22 @@ use OneBot\Driver\Event\WebSocket\WebSocketCloseEvent;
|
|||||||
use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent;
|
use OneBot\Driver\Event\WebSocket\WebSocketMessageEvent;
|
||||||
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
|
use OneBot\Driver\Event\WebSocket\WebSocketOpenEvent;
|
||||||
use OneBot\V12\Exception\OneBotException;
|
use OneBot\V12\Exception\OneBotException;
|
||||||
|
use OneBot\V12\Object\ActionResponse;
|
||||||
use OneBot\V12\Object\MessageSegment;
|
use OneBot\V12\Object\MessageSegment;
|
||||||
use OneBot\V12\Object\OneBotEvent;
|
use OneBot\V12\Object\OneBotEvent;
|
||||||
use ZM\Annotation\AnnotationHandler;
|
use ZM\Annotation\AnnotationHandler;
|
||||||
use ZM\Annotation\Framework\BindEvent;
|
use ZM\Annotation\Framework\BindEvent;
|
||||||
use ZM\Annotation\Framework\Init;
|
use ZM\Annotation\Framework\Init;
|
||||||
|
use ZM\Annotation\Middleware\Middleware;
|
||||||
use ZM\Annotation\OneBot\BotActionResponse;
|
use ZM\Annotation\OneBot\BotActionResponse;
|
||||||
use ZM\Annotation\OneBot\BotEvent;
|
use ZM\Annotation\OneBot\BotEvent;
|
||||||
use ZM\Annotation\OneBot\CommandArgument;
|
use ZM\Annotation\OneBot\CommandArgument;
|
||||||
use ZM\Container\ContainerRegistrant;
|
use ZM\Container\ContainerRegistrant;
|
||||||
use ZM\Context\BotContext;
|
use ZM\Context\BotContext;
|
||||||
|
use ZM\Exception\OneBot12Exception;
|
||||||
use ZM\Exception\WaitTimeoutException;
|
use ZM\Exception\WaitTimeoutException;
|
||||||
|
use ZM\Middleware\WebSocketFilter;
|
||||||
|
use ZM\Plugin\OneBot\BotMap;
|
||||||
use ZM\Utils\ConnectionUtil;
|
use ZM\Utils\ConnectionUtil;
|
||||||
|
|
||||||
class GocqAdapter
|
class GocqAdapter
|
||||||
@ -47,29 +52,26 @@ class GocqAdapter
|
|||||||
{
|
{
|
||||||
logger()->info('连接到 ob11');
|
logger()->info('连接到 ob11');
|
||||||
$request = $event->getRequest();
|
$request = $event->getRequest();
|
||||||
ob_dump($request);
|
|
||||||
// 判断是不是 Gocq 或 OneBot 11 标准的连接。OB11 标准必须带有 X-Client-Role 和 X-Self-ID 两个头。
|
// 判断是不是 Gocq 或 OneBot 11 标准的连接。OB11 标准必须带有 X-Client-Role 和 X-Self-ID 两个头。
|
||||||
if ($request->getHeaderLine('X-Client-Role') === 'Universal' && $request->getHeaderLine('X-Self-ID') !== '') {
|
if ($request->getHeaderLine('X-Client-Role') === 'Universal' && $request->getHeaderLine('X-Self-ID') !== '') {
|
||||||
logger()->info('检测到 OneBot 11 反向 WS 连接 ' . $request->getHeaderLine('User-Agent'));
|
logger()->info('检测到 OneBot 11 反向 WS 连接 ' . $request->getHeaderLine('User-Agent'));
|
||||||
$info = ['gocq_impl' => 'go-cqhttp', 'self_id' => $request->getHeaderLine('X-Self-ID')];
|
$info = ['gocq_impl' => 'go-cqhttp', 'self_id' => $request->getHeaderLine('X-Self-ID'), 'onebot-version' => 11];
|
||||||
// TODO: 验证 Token
|
// TODO: 验证 Token
|
||||||
ConnectionUtil::setConnection($event->getFd(), $info);
|
ConnectionUtil::setConnection($event->getFd(), $info);
|
||||||
logger()->info('已接入 go-cqhttp 的反向 WS 连接,连接 ID 为 ' . $event->getFd());
|
logger()->info('已接入 go-cqhttp 的反向 WS 连接,连接 ID 为 ' . $event->getFd());
|
||||||
|
BotMap::setCustomConnectContext($event->getSocketFlag(), $event->getFd(), new GoBotConnectContext($event->getSocketFlag(), $event->getFd()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws OneBotException
|
* @param WebSocketMessageEvent $event
|
||||||
|
* @throws \Throwable
|
||||||
|
* @throws OneBot12Exception
|
||||||
*/
|
*/
|
||||||
#[BindEvent(WebSocketMessageEvent::class)]
|
#[BindEvent(WebSocketMessageEvent::class)]
|
||||||
|
#[Middleware(WebSocketFilter::class, ['gocq_impl' => 'go-cqhttp'])]
|
||||||
public function handleWSReverseMessage(WebSocketMessageEvent $event): void
|
public function handleWSReverseMessage(WebSocketMessageEvent $event): void
|
||||||
{
|
{
|
||||||
// 忽略非 gocq 的消息
|
|
||||||
$impl = ConnectionUtil::getConnection($event->getFd())['gocq_impl'] ?? null;
|
|
||||||
if ($impl === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析 Frame 到 UTF-8 JSON
|
// 解析 Frame 到 UTF-8 JSON
|
||||||
$body = $event->getFrame()->getData();
|
$body = $event->getFrame()->getData();
|
||||||
$body = json_decode($body, true);
|
$body = json_decode($body, true);
|
||||||
@ -79,6 +81,7 @@ class GocqAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isset($body['post_type'], $body['self_id'])) {
|
if (isset($body['post_type'], $body['self_id'])) {
|
||||||
|
// 获取转换后的对象
|
||||||
$ob12 = self::getConverter($event->getFd(), strval($body['self_id']))->convertEvent($body);
|
$ob12 = self::getConverter($event->getFd(), strval($body['self_id']))->convertEvent($body);
|
||||||
if ($ob12 === null) {
|
if ($ob12 === null) {
|
||||||
logger()->debug('收到了不支持的 Event,丢弃此事件');
|
logger()->debug('收到了不支持的 Event,丢弃此事件');
|
||||||
@ -94,8 +97,10 @@ class GocqAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 绑定容器
|
// 绑定容器
|
||||||
ContainerRegistrant::registerOBEventServices($obj, GoBotContext::class);
|
ContainerRegistrant::registerOBEventServices($obj);
|
||||||
|
BotMap::registerBotWithFd($obj->self['user_id'], $obj->self['platform'], true, $event->getFd(), $event->getSocketFlag());
|
||||||
|
BotMap::setCustomContext($obj->self['user_id'], $obj->self['platform'], GoBotContext::class);
|
||||||
|
container()->set(BotContext::class, bot());
|
||||||
// 调用 BotEvent 事件
|
// 调用 BotEvent 事件
|
||||||
$handler = new AnnotationHandler(BotEvent::class);
|
$handler = new AnnotationHandler(BotEvent::class);
|
||||||
$handler->setRuleCallback(function (BotEvent $event) use ($obj) {
|
$handler->setRuleCallback(function (BotEvent $event) use ($obj) {
|
||||||
@ -104,7 +109,7 @@ class GocqAdapter
|
|||||||
&& ($event->detail_type === null || $event->detail_type === $obj->detail_type);
|
&& ($event->detail_type === null || $event->detail_type === $obj->detail_type);
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
$handler->handleAll($obj);
|
$handler->handleAll();
|
||||||
} catch (WaitTimeoutException $e) {
|
} catch (WaitTimeoutException $e) {
|
||||||
// 这里是处理 prompt() 下超时的情况的
|
// 这里是处理 prompt() 下超时的情况的
|
||||||
if ($e->getTimeoutPrompt() === null) {
|
if ($e->getTimeoutPrompt() === null) {
|
||||||
@ -125,14 +130,17 @@ class GocqAdapter
|
|||||||
$origin_action = self::$action_hold_list[$body['echo']];
|
$origin_action = self::$action_hold_list[$body['echo']];
|
||||||
unset(self::$action_hold_list[$body['echo']]);
|
unset(self::$action_hold_list[$body['echo']]);
|
||||||
$resp = GocqActionConverter::getInstance()->convertActionResponse11To12($body, $origin_action);
|
$resp = GocqActionConverter::getInstance()->convertActionResponse11To12($body, $origin_action);
|
||||||
|
|
||||||
ContainerRegistrant::registerOBActionResponseServices($resp);
|
ContainerRegistrant::registerOBActionResponseServices($resp);
|
||||||
|
|
||||||
// 调用 BotActionResponse 事件
|
// 调用 BotActionResponse 事件
|
||||||
$handler = new AnnotationHandler(BotActionResponse::class);
|
$handler = new AnnotationHandler(BotActionResponse::class);
|
||||||
$handler->setRuleCallback(function (BotActionResponse $event) use ($resp) {
|
$handler->setRuleCallback(function (BotActionResponse $event) use ($resp) {
|
||||||
return $event->retcode === null || $event->retcode === $resp->retcode;
|
return ($event->retcode === null || $event->retcode === $resp->retcode)
|
||||||
|
&& ($event->status === null || $event->status === $resp->status);
|
||||||
});
|
});
|
||||||
$handler->handleAll($resp);
|
container()->set(ActionResponse::class, $resp);
|
||||||
|
$handler->handleAll();
|
||||||
|
|
||||||
// 如果有协程,并且该 echo 记录在案的话,就恢复协程
|
// 如果有协程,并且该 echo 记录在案的话,就恢复协程
|
||||||
BotContext::tryResume($resp);
|
BotContext::tryResume($resp);
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class GocqEventConverter
|
|||||||
$message[$k] = ['type' => $type, 'data' => $data];
|
$message[$k] = ['type' => $type, 'data' => $data];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $message;
|
return json_decode(json_encode($message), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user