From 3bcbfd99b98fae8d3ed2e5975a00721dc4b61365 Mon Sep 17 00:00:00 2001 From: Alix-007 Date: Thu, 12 Mar 2026 14:31:00 +0800 Subject: [PATCH] fix(channels): stop stale typing loops on overwrite (#1392) Co-authored-by: XYSK-lilong007 <267018309+XYSK-lilong007@users.noreply.github.com> --- pkg/channels/manager.go | 7 ++++++- pkg/channels/manager_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/pkg/channels/manager.go b/pkg/channels/manager.go index 472895a7a..df430e4d3 100644 --- a/pkg/channels/manager.go +++ b/pkg/channels/manager.go @@ -127,7 +127,12 @@ func (m *Manager) SendPlaceholder(ctx context.Context, channel, chatID string) b // Implements PlaceholderRecorder. func (m *Manager) RecordTypingStop(channel, chatID string, stop func()) { key := channel + ":" + chatID - m.typingStops.Store(key, typingEntry{stop: stop, createdAt: time.Now()}) + entry := typingEntry{stop: stop, createdAt: time.Now()} + if previous, loaded := m.typingStops.Swap(key, entry); loaded { + if oldEntry, ok := previous.(typingEntry); ok && oldEntry.stop != nil { + oldEntry.stop() + } + } } // RecordReactionUndo registers a reaction undo function for later invocation. diff --git a/pkg/channels/manager_test.go b/pkg/channels/manager_test.go index 1f3a628c2..e0f55288a 100644 --- a/pkg/channels/manager_test.go +++ b/pkg/channels/manager_test.go @@ -616,6 +616,37 @@ func TestRecordTypingStop_ConcurrentSafe(t *testing.T) { wg.Wait() } +func TestRecordTypingStop_ReplacesExistingStop(t *testing.T) { + m := newTestManager() + var oldStopCalls int + var newStopCalls int + + m.RecordTypingStop("test", "123", func() { + oldStopCalls++ + }) + + m.RecordTypingStop("test", "123", func() { + newStopCalls++ + }) + + if oldStopCalls != 1 { + t.Fatalf("expected previous typing stop to be called once when replaced, got %d", oldStopCalls) + } + if newStopCalls != 0 { + t.Fatalf("expected replacement typing stop to stay active until preSend, got %d calls", newStopCalls) + } + + msg := bus.OutboundMessage{Channel: "test", ChatID: "123", Content: "hello"} + m.preSend(context.Background(), "test", msg, &mockChannel{}) + + if newStopCalls != 1 { + t.Fatalf("expected replacement typing stop to be called by preSend, got %d", newStopCalls) + } + if oldStopCalls != 1 { + t.Fatalf("expected previous typing stop to not be called again, got %d", oldStopCalls) + } +} + func TestSendWithRetry_PreSendEditsPlaceholder(t *testing.T) { m := newTestManager() var sendCalled bool