本版新增功能
本文记录本 Fork 相对上游 Gensokyo 的主要代码行为。
范围说明:
| 标记 | 含义 |
|---|---|
- | 通用能力,具体可用性取决于调用的 Action 和 QQ API 限制 |
私聊 (C2C) | QQ C2C 单聊 |
q群 (Group Chat) | QQ 群 |
q頻 (QQ Guild) | QQ 频道/子频道 |
事件
| Handler | 范围 | 行为 |
|---|---|---|
GroupMessageEventHandler | q群 (Group Chat) | 接收 GROUP_MESSAGE_CREATE 非 @ 群消息。 |
MemberEventHandler | q頻 (QQ Guild) | GUILD_MEMBER_ADD / GUILD_MEMBER_REMOVE 转 OneBot notice。 |
GroupMemberAddEventHandler | q群 (Group Chat) | GROUP_MEMBER_ADD 转 notice.group_increase。 |
GroupMemberRemoveEventHandler | q群 (Group Chat) | GROUP_MEMBER_REMOVE 转 notice.group_decrease。 |
C2CMsgRejectHandler | 私聊 (C2C) | 用户关闭 C2C 主动消息推送。 |
C2CMsgReceiveHandler | 私聊 (C2C) | 用户开启 C2C 主动消息推送。 |
FriendAddEventHandler / FriendDelEventHandler | 私聊 (C2C) | 好友关系事件。 |
text_intent 只注册写入的 handler。遇到 4014: disallowed intents 时可开启:
suppress_disallowed_intents: true该开关只在 Identify 阶段屏蔽容易被拒绝的私有/未授权 intent,不会自动启用对应 handler。
API
| Action | 范围 | 行为 |
|---|---|---|
get_avatar | - | 获取 QQ 头像直链。 |
get_robot_share_link | - | 获取机器人分享链接。 |
send_private_msg_wakeup | 私聊 (C2C) | 发送带 is_wakeup=true 的 C2C 召回消息。 |
put_interaction | - | 回复按钮交互结果。 |
set_group_card | - | OneBot 11 兼容 mock;返回 ok,不调用 QQ API。 |
set_group_add_request | - | OneBot 11 兼容 mock;返回 ok,不调用 QQ API。 |
/metrics | - | Prometheus 文本指标。 |
消息与 CQ 行为
q群 to_me
范围:q群 (Group Chat)
q群消息事件新增 to_me 字段:
GROUP_AT_MESSAGE_CREATE固定为true。GROUP_MESSAGE_CREATE根据Mentions[].IsYou判断。
非自身 @
范围:q群 (Group Chat)
GROUP_MESSAGE_CREATE 中:
@bot从文本中剥离,并设置to_me=true。@其他人转成[CQ:at,qq=<虚拟ID>],同时建立 idmap 映射。
出站 @
范围:q群 (Group Chat) / q頻 (QQ Guild)
出站 [CQ:at,qq=<虚拟ID>] 会反查 OpenID,并转换为 <qqbot-at-user id="OpenID" />(仅 Markdown 消息,普通文本不转换)。
<qqbot-at-user id="OpenID" />Markdown 内容里的 [CQ:at] 也会在发送前转换。详见 Markdown 中的 CQ at。
Markdown 图片
范围:q群 (Group Chat) / q頻 (QQ Guild)
Markdown 内容中的 :
- HTTP(S) URL 保留。
- 本地路径或
file://路径会上传到 QQ CDN 后替换为直链。
[CQ:reply]
范围:q群 (Group Chat)
send_group_msg 会从文本中提取 [CQ:reply,id=<虚拟消息ID>],尝试通过 idmap 缓存反查真实 QQ message_id,再写入 message_reference。QQ q群 API 可能接受但不显示引用样式;send_guild_channel_msg 当前没有同等处理。
[CQ:member]
范围:q群 (Group Chat)
GROUP_MEMBER_ADD / GROUP_MEMBER_REMOVE 转 OneBot notice,message 字段附带 [CQ:member]。后端用普通 send_group_msg 回复时带回该 CQ 码,Gensokyo 会重新路由到真实 q群。详见 CQ member。
delete_group_msg
范围:q群 (Group Chat)
独立 action,用于撤回指定用户在群内的消息;省略 message_id 时查找该用户最后一条消息。user_id 缺失、为 0 或负数时按 Bot 自身消息处理。详见 delete_group_msg。
[CQ:active]
范围:-
当前文本解析只处理 [CQ:active,type=...,sub_type=...],解析后移除并记录字段;代码没有消费这些字段。需要 C2C 召回消息时使用 send_private_msg_wakeup。
[CQ:remove]
范围:q群 (Group Chat)
出站 CQ 码 [CQ:remove,user_id=虚拟用户ID,msg_id=虚拟消息ID],后端通过 send_group_msg 携带此 CQ 码即可撤回指定的群消息。user_id 和 msg_id 均为虚拟 ID,Gensokyo 内部自动转换为 QQ OpenID / 真实 message_id。纯 CQ 码的消息不会发送到 QQ 频道。详见 CQ remove。
按钮权限 ID
范围:-
发送 keyboard 时,会遍历按钮 permission.specify_user_ids,把虚拟数字 ID 转成 QQ OpenID。C2C 场景中,如果 permission.type=0 且指定了用户,会改为 type=2,避免 QQ API 拒绝。
零值字段
范围:-
action.type=0、permission.type=0、render_data.style=0 会被保留,不再因为 JSON omitempty 丢失。
语音
范围:-
[CQ:record] 支持自动转 SILK v3。WAV/MP3 可走 Go 内部处理;其他格式仍可能需要 ffmpeg。目标音频为 16-bit、单声道、采样率由 record_sampleRate 控制,默认 24000。
idmap
旧版单库 idmap.db 拆为:
| 文件 | 用途 |
|---|---|
openid-map.db | OpenID/rUIN/raw 与内部 vUIN 的身份关系。 |
msgid-map.db | QQ message_id 与虚拟 message_id 的临时映射。 |
idmap.db | 旧库,仅作为一次性迁移源。 |
规则:
- 下游默认继续使用内部 vUIN。
- QQ OpenID 身份键为
openid:QQ:<appid>:<openid>。 - q群、私聊 (C2C)、好友事件、群成员事件共用同一 QQ OpenID 身份键。
- q頻 (QQ Guild) 相关 ID 继续沿用现有逻辑。
- message_id 默认保留 1 小时,由
msgid_ttl_seconds控制。
相关配置:
op_userid_type: vuin
msgid_ttl_seconds: 3600事件字段
sender.nickname
event.sender.nickname 优先级:
card_nick配置。- QQ API 的
Author.Username。 - 空字符串。
q群 sender.role
范围:q群 (Group Chat)
q群消息优先使用 QQ API 的 member_role:
member_role | sender.role |
|---|---|
owner | owner |
admin | admin |
member | member |
没有 member_role 时,再回退到 master_id 判断。
event_id
已存储 event_id 的入口:
| 事件 | 处理入口 |
|---|---|
INTERACTION_CREATE | ProcessInlineSearch |
C2C_MSG_RECEIVE | process_c2c_switch |
FRIEND_ADD | process_friend |
GROUP_ADD_ROBOT | ProcessGroupAddBot |
GROUP_MSG_RECEIVE | ProcessGroupMsgReceive |
GROUP_MEMBER_ADD | ProcessGroupMember |
日志与监控
mylog
当前内置日志支持:
- 控制台按级别着色:
log_color_enabled。 - 控制台日志格式:
2006/JAN/02 PM 03:04:05 [INFO ] [module] message。 - 本地文件日志默认关闭,
save_logs: true或启动参数run --local-logger=enable均可启用。 - 文件日志写入
log/下的纯文本文件,文件名使用 UTC 时间。 log_suffix_per_mins控制时间切分,log_max_size_mb控制单文件大小轮转。log_max_age_days控制最大保留天数,log_keep_files控制本地旧日志文件最大保留个数。
慢事件与 /metrics
runWithTimer 会按 log_slow_event_threshold_ms 判定慢事件。/metrics 输出:
gensokyo_uptime_secondsgensokyo_messages_received_totalgensokyo_messages_sent_totalgensokyo_errors_totalgensokyo_slow_events_totalgensokyo_memory_allocated_bytes
Master 指令
范围:进入 HandleFrameworkCommand 的消息事件。
权限:
master_id为空数组时不限制。- 否则要求真实用户 ID 或虚拟用户 ID 命中
master_id。
指令:
| 配置项 | 默认值 | 行为 |
|---|---|---|
status_prefix | /gskstatus | 返回版本、收发计数、慢事件/错误计数、内存、协程数、运行时间。 |
broadcast_prefix | /gskbroadcast | 向已发现的 q頻文本子频道和 idmap 中的 q群提交广播。 |
指令前缀设为 ""、/disabled 或 /disabled... 时视为禁用。
构建
CI 使用静态编译配置 CGO_ENABLED=0,降低 GLIBC 版本依赖。
构建版本由 -ldflags 注入 buildinfo.BuildType 和 buildinfo.BuildSpec,显示为 <buildtype>-<build_spec>,例如 git-2d643f4。未注入时回退为 dev-<UTC 时间戳>。启动命令 version、OneBot get_version_info 和 /gskstatus 使用同一版本值。
build.ps1 同时支持单平台构建和 -All / -LinuxOnly 多平台构建;build_all.ps1 仅保留为兼容入口。
修复
GetRemoveBotAtGroup误删用户主动发送的 @。- 入站
@bot剥离逻辑改用Mentions[i].OpenID。 ParseAndHandle增加错误日志和 panic 恢复。- 按钮零值字段序列化丢失。
- C2C 按钮指定用户权限导致发送失败。
