Skip to content

Commit f47051f

Browse files
ernadoclaude
andcommitted
fix(updates): drop the bot's own outgoing messages
MTProto echoes the bot's own sends back on the update stream with Out=true (the HTTP Bot API never does). Without filtering them, a bot that replies to messages answers its own replies in an infinite loop. Skip Out messages in dispatchMessage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 432bc7a commit f47051f

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

on.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ func (b *Bot) installHandlers() {
4141
// field. Channel-broadcast messages become channel posts; everything else is a
4242
// regular message. edited selects the edited_* fields.
4343
func (b *Bot) dispatchMessage(ctx context.Context, msg tg.MessageClass, edited bool) {
44+
// Drop the bot's own outgoing messages. MTProto echoes them back on the
45+
// update stream, but the HTTP Bot API never delivers them — without this a
46+
// bot that replies to messages would answer its own replies in a loop.
47+
if tgm, ok := msg.(*tg.Message); ok && tgm.Out {
48+
return
49+
}
50+
4451
m, err := b.messageFromTg(ctx, msg)
4552
if err != nil {
4653
b.log.Error("Convert message", zap.Error(err))

on_self_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package botapi
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gotd/td/tg"
8+
)
9+
10+
// TestDispatchSkipsOwnOutgoingMessage guards against the self-reply loop: the
11+
// bot's own messages arrive on the MTProto update stream with Out=true and must
12+
// not be dispatched to handlers.
13+
func TestDispatchSkipsOwnOutgoingMessage(t *testing.T) {
14+
b := newTestBot(t)
15+
fired := false
16+
b.OnMessage(func(*Context) error { fired = true; return nil })
17+
18+
own := &tg.Message{
19+
Out: true,
20+
ID: 1,
21+
Message: "echo",
22+
PeerID: &tg.PeerUser{UserID: 42},
23+
}
24+
b.dispatchMessage(context.Background(), own, false)
25+
26+
if fired {
27+
t.Fatal("handler fired for the bot's own outgoing message")
28+
}
29+
}

0 commit comments

Comments
 (0)