Files
Gitea/services/websocket/websocket.go
T
silverwind b60da6d876 enhance(websocket): improve client synchronization (#38847) (#40340)
Backport of https://github.com/go-gitea/gitea/pull/38847, which fixes
the stopwatch push flake in
https://github.com/go-gitea/gitea/actions/runs/43200377380/job/131122930118.

The stopwatch e2e test keeps its v28 flow, since main reworked it in a
separate change.

Assisted-by: Claude Code:claude-opus-5-5
2026-11-12 14:00:15 +00:00

72 lines
1.8 KiB
Go

// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package websocket
import (
"bytes"
"context"
user_model "gitea.dev/models/user"
"gitea.dev/modules/json"
"gitea.dev/modules/setting"
notify_service "gitea.dev/services/notify"
"gitea.dev/services/pubsub"
)
type wsNotifier struct {
notify_service.NullNotifier
}
var _ notify_service.Notifier = &wsNotifier{}
func Init() error {
// the pubsub broker must be ready before the notifier starts publishing to it
if err := pubsub.Init(); err != nil {
return err
}
notify_service.RegisterNotifier(&wsNotifier{})
return nil
}
func UserData(ctx context.Context, user *user_model.User) (data [][]byte) {
for _, event := range [][]byte{notificationCountEvent(ctx, user.ID), stopwatchesEvent(ctx, user)} {
if event != nil {
data = append(data, event)
}
}
return data
}
func EventForSession(brokerPayload []byte, sessionID string) []byte {
target, eventData, _ := bytes.Cut(brokerPayload, []byte("\n"))
if len(target) > 0 && string(target) != sessionID {
return nil
}
return eventData
}
// makeEventMessage prefixes the client JSON with its target session, empty for all sessions.
func makeEventMessage(eventType, targetSession string, eventData any) []byte {
buf := bytes.NewBufferString(targetSession + "\n")
err := json.MarshalWriteRelaxed(buf, &struct {
EventType string `json:"eventType"`
EventData any `json:"eventData,omitzero"`
}{eventType, eventData})
if err != nil {
setting.PanicInDevOrTesting("websocket: marshal event: %v", err)
return nil
}
return buf.Bytes()
}
func publishUserEvent(userID int64, build func() []byte) {
topic := pubsub.UserTopic(userID)
if !pubsub.DefaultBroker.HasTopicSubscribers(topic) {
return
}
if event := build(); event != nil {
pubsub.DefaultBroker.Publish(topic, event)
}
}