feat(channels): 非消息事件接入(notice 归一化 + 传入前审查,fail-safe 静默)与入站脱敏帧日志/日志轮转
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- notice:adapter 归一化 seam + 结构化分类 + 净化(ANSI/控制/零宽/双向字符、200 runes 截断)
  + fail-safe 写死为「静默」(未装配审查/超时/失败 ⇒ 仅登记、不驱动 loop)
- 身份面零改动:notice 发送者恒 RoleSystem + SenderID=system
- 复用策略四的同一个审查模型(Options.Review),未另造第二套
- 入站帧脱敏 DEBUG(post_type/message_type/sub_type/self_id/user_id/sender_id/group_id/段类型/at 目标)
- ctrl.bat 启动前归档轮转(保留 20 份)+ bash 侧改追加(不再重启即截断)
This commit is contained in:
AskaEth committed 2026-10-05 11:55:05 +08:00
1 parent 85abb90067
commit 5139945bfe
15 files changed
+1604 -21

No files matched your search

+13 -8
View File
@@ -17,12 +17,20 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
)
const platformName = "qq-obv11"
const (
platformName = "qq-obv11"
// atSegmentType 是「@某人」在**数组段**里的段类型(`{"type":"at"}`),cqPrefix 则是
// **CQ 码**形态里每个码的起始(`[CQ:at,qq=...]`)。归一解析与入站帧脱敏日志
// (inbound_debug.go)共用这两个字面量,避免同一处协议知识各写一份。
atSegmentType = "at"
cqPrefix = "[CQ:"
)
// OneBot v11 event as delivered over WebSocket.
type obEvent struct {
PostType string `json:"post_type"`
MessageType string `json:"message_type"`
NoticeType string `json:"notice_type"`
Time int64 `json:"time"`
SelfID int64 `json:"self_id"`
MessageID int64 `json:"message_id"`
@@ -143,10 +151,7 @@ func (a *Adapter) toUnified(ev *obEvent, raw []byte) adapter.UnifiedMessage {
// reports whether the message carries any real text (as opposed to only media /
// placeholder markers), which drives ContentType selection.
func (a *Adapter) parseMessage(ev *obEvent) (text string, media []adapter.Media, mentions []adapter.Mention, replyID, replyText string, hasText bool) {
raw := ev.Message
if len(raw) == 0 {
raw = []byte(ev.RawMessage)
}
raw := eventRawMessage(ev)
if len(raw) > 0 {
switch raw[0] {
case '[':
@@ -180,7 +185,7 @@ func parseSegmentArray(raw []byte) (string, []adapter.Media, []adapter.Mention,
if t != "" {
hasText = true
}
case "at":
case atSegmentType:
qq := segStr(s.Data, "qq")
if qq != "" {
mentions = append(mentions, adapter.Mention{UserID: qq})
@@ -230,7 +235,7 @@ func parseCQMessage(s string) (string, []adapter.Media, []adapter.Mention, strin
last := 0
for i := 0; i < len(s); {
if !strings.HasPrefix(s[i:], "[CQ:") {
if !strings.HasPrefix(s[i:], cqPrefix) {
i++
continue
}
@@ -246,7 +251,7 @@ func parseCQMessage(s string) (string, []adapter.Media, []adapter.Mention, strin
code := s[i : i+end+1]
typ, params := decodeCQCode(code)
switch typ {
case "at":
case atSegmentType:
if qq := params["qq"]; qq != "" {
mentions = append(mentions, adapter.Mention{UserID: qq})
b.WriteString("@" + qq)