fix(kook): 丢弃自我回声消息,防 bot 把自己的回复当入站用户消息
KOOK 网关会把 bot 自己发的消息又推回给 bot(author_id=bot uid),导致 bot 把自己的 回复当成入站用户消息处理(循环/浪费token)。toUnifiedMessage 计算 senderID 后调用 isSelf(senderID) 比对 a.botID(user/me 解析出的 bot 账号 id),命中即返回 ok=false 丢弃。 - identity.go: 新增 isSelf(并发安全,botMu) - message.go: self-echo 丢弃 + debug 日志 - message_test.go: TestToUnified_DropsSelfEcho 验收: go build/vet/test ./... 全绿
This commit is contained in:
1 parent
2c4ade5f28
commit
db8465f68b
3 files changed
+34
No files matched your search
@@ -81,6 +81,19 @@ func (a *Adapter) botIdentitySnapshot() (id, username, nickname string) {
|
||||
return a.botID, a.botUsername, a.botNickname
|
||||
}
|
||||
|
||||
// isSelf reports whether senderID is the bot's own account id. KOOK delivers the
|
||||
// bot's own messages back over the gateway, so an inbound event whose author_id equals
|
||||
// the bot's user id is a self-echo and must be dropped — otherwise the bridge would
|
||||
// process the bot's replies as inbound user messages and loop (or burn tokens).
|
||||
func (a *Adapter) isSelf(senderID string) bool {
|
||||
if senderID == "" {
|
||||
return false
|
||||
}
|
||||
a.botMu.RLock()
|
||||
defer a.botMu.RUnlock()
|
||||
return a.botID != "" && senderID == a.botID
|
||||
}
|
||||
|
||||
// BotIdentity returns the resolved bot account (id/username/nickname). The values
|
||||
// are non-sensitive (the bot's public handle and display name) so the admin panel
|
||||
// may show them.
|
||||
|
||||
@@ -82,6 +82,12 @@ func (a *Adapter) toUnifiedMessage(data json.RawMessage, frame []byte) (adapter.
|
||||
_ = json.Unmarshal(ev.Extra, &ex)
|
||||
|
||||
senderID, senderName := senderOf(&ev, &ex)
|
||||
// Self-echo: KOOK pushes the bot's own channel messages back to it via the gateway.
|
||||
// Drop them so the bridge never treats the bot's replies as inbound user messages.
|
||||
if a.isSelf(senderID) {
|
||||
a.log.Debug("self message dropped (echo)", "sender_id", senderID, "channel", ev.TargetID)
|
||||
return adapter.UnifiedMessage{}, false
|
||||
}
|
||||
ct, media := messageKind(ev.Type, content)
|
||||
group := channelIsGroup(ev.ChannelType)
|
||||
|
||||
|
||||
@@ -7,6 +7,21 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/adapter"
|
||||
)
|
||||
|
||||
func TestToUnified_DropsSelfEcho(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := New(Config{BotToken: "x"})
|
||||
a.setBotIdentity(botIdentity{ID: "bot-1", Username: "Cyrene", Nickname: "Cyrene"})
|
||||
// KOOK pushes the bot's own channel message back to it; author_id == bot id.
|
||||
data := json.RawMessage(`{
|
||||
"channel_type":"GROUP","type":1,"target_id":"chan-1","author_id":"bot-1",
|
||||
"content":"咦,亲爱的这是想戳人家哪里呀♪","msg_id":"m-self","msg_timestamp":1700000000000,"nonce":"",
|
||||
"extra":{"type":1,"guild_id":"g-1","mention":[],"author":{"id":"bot-1","username":"Cyrene","nickname":"Cyrene"}}
|
||||
}`)
|
||||
if _, ok := a.toUnifiedMessage(data, nil); ok {
|
||||
t.Fatal("self-echo message should be dropped (ok=false)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestToUnified_GroupText(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := New(Config{BotToken: "x"})
|
||||
|
||||
Reference in new issue
Block a user