memos/server/router/api/v1/sse_event_helpers.go
memoclaw c53677fcba fix(api): improve SSE hub design and fix double-broadcast on comments
- Fix duplicate SSE event on comment creation: CreateMemoComment now
  suppresses the redundant memo.created broadcast from the inner
  CreateMemo call, emitting only memo.comment.created
- Extract reaction event-building IIFEs into buildMemoReactionSSEEvent
  helper, removing duplicated inline DB-fetch logic
- Promote resolveSSEAudienceCreatorID from method to free function
  (resolveSSECreatorID) since it never used the receiver
- Add userID to SSE connect/disconnect log lines for traceability
- Change canReceive default from permissive (return true) to
  deny-with-warning for unknown visibility types
- Add comprehensive tests covering all new helpers, visibility edge
  cases, slow-client drop behavior, and the double-broadcast fix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 07:33:40 +08:00

40 lines
1.1 KiB
Go

package v1
import "github.com/usememos/memos/store"
func buildMemoName(uid string) string {
return MemoNamePrefix + uid
}
// resolveSSECreatorID returns the CreatorID used for SSE delivery filtering.
// For a comment memo, it returns the parent memo's CreatorID so that private
// parent-memo events are scoped to the parent owner.
func resolveSSECreatorID(memo *store.Memo, parentMemo *store.Memo) int32 {
if memo == nil {
return 0
}
if parentMemo != nil {
return parentMemo.CreatorID
}
return memo.CreatorID
}
// buildMemoReactionSSEEvent constructs an SSEEvent for a reaction on a memo.
// Pass parentMemo when the memo is a comment (memo.ParentUID != nil).
func buildMemoReactionSSEEvent(eventType SSEEventType, contentID string, memo *store.Memo, parentMemo *store.Memo) *SSEEvent {
parent := ""
if memo != nil && memo.ParentUID != nil {
parent = buildMemoName(*memo.ParentUID)
}
visibility := store.Visibility("")
if memo != nil {
visibility = memo.Visibility
}
return &SSEEvent{
Type: eventType,
Name: contentID,
Parent: parent,
Visibility: visibility,
CreatorID: resolveSSECreatorID(memo, parentMemo),
}
}