From 5e783adf7ac54c45d6c10093b9c03ebbedefbaab Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 15 Aug 2026 01:10:35 +0800 Subject: [PATCH] feat: implement chat merging and logging in Safew - Introduced a new function `mergeAndLog` in the Watcher to handle merging Safew chats and logging newly discovered chats. - Added a test `TestNewSafewChatsSkipsKnownIDs` to ensure that known chat IDs are skipped during the merging process. - Enhanced the polling mechanism to improve chat management and reduce duplicates. --- internal/safew/watcher.go | 39 +++++++++++++++++++++++++++++++++- internal/safew/watcher_test.go | 12 +++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/internal/safew/watcher.go b/internal/safew/watcher.go index ad11136..60087cc 100644 --- a/internal/safew/watcher.go +++ b/internal/safew/watcher.go @@ -188,7 +188,7 @@ func (w *Watcher) pollOnce(ctx context.Context, token string, timeout int) error if err != nil { return err } - if err := w.store.MergeSafewChats(ctx, token, chats); err != nil { + if err := w.mergeAndLog(ctx, token, chats); err != nil { return err } if next != offset { @@ -197,6 +197,43 @@ func (w *Watcher) pollOnce(ctx context.Context, token string, timeout int) error return nil } +func (w *Watcher) mergeAndLog(ctx context.Context, token string, chats []adapter.SafewChat) error { + if len(chats) == 0 { + return nil + } + existing, err := w.store.ListSafewChats(ctx, token) + if err != nil { + return w.store.MergeSafewChats(ctx, token, chats) + } + known := map[string]struct{}{} + for _, c := range existing { + known[c.ID] = struct{}{} + } + if err := w.store.MergeSafewChats(ctx, token, chats); err != nil { + return err + } + for _, c := range newSafewChats(known, chats) { + slog.Info("safew chat discovered", "id", c.ID, "type", c.Type, "title", c.Title) + } + return nil +} + +func newSafewChats(known map[string]struct{}, chats []adapter.SafewChat) []adapter.SafewChat { + var out []adapter.SafewChat + seen := map[string]struct{}{} + for _, c := range chats { + if _, ok := known[c.ID]; ok { + continue + } + if _, ok := seen[c.ID]; ok { + continue + } + seen[c.ID] = struct{}{} + out = append(out, c) + } + return out +} + func isSafewAuth(err error) bool { var e *adapter.SafewAuthError return errors.As(err, &e) diff --git a/internal/safew/watcher_test.go b/internal/safew/watcher_test.go index a4cd641..3c18371 100644 --- a/internal/safew/watcher_test.go +++ b/internal/safew/watcher_test.go @@ -115,6 +115,18 @@ func TestEnsurePollsInBackground(t *testing.T) { w.Stop() } +func TestNewSafewChatsSkipsKnownIDs(t *testing.T) { + known := map[string]struct{}{"1": {}} + got := newSafewChats(known, []adapter.SafewChat{ + {ID: "1", Title: "old"}, + {ID: "2", Title: "测试AI", Type: "group"}, + {ID: "2", Title: "dup"}, + }) + if len(got) != 1 || got[0].ID != "2" || got[0].Title != "测试AI" { + t.Fatalf("%#v", got) + } +} + func TestPollConflictIsRetryable(t *testing.T) { err := errors.New("safew getUpdates status 400: BAD_REQUEST: Conflict: terminated by other getUpdates request; make sure that only one bot instance is running") if !isGetUpdatesConflict(err) {