moved middleware event publisher to sse package

This commit is contained in:
2026-01-24 14:06:19 -07:00
parent 720c3fb4e0
commit a6267ac189
5 changed files with 33 additions and 20 deletions
-120
View File
@@ -1,120 +0,0 @@
package middleware
import (
"context"
"fmt"
"path"
"ruben/inventory2/internal/logging"
"ruben/inventory2/internal/server/sse"
"strings"
"time"
"github.com/gin-gonic/gin"
)
type UpdateNotificationPublisher struct {
log *logging.Logger
sse *sse.Queue
trimBasePath string
basePathPattern string
}
func NewUpdateNotificationPublisher(
log *logging.Logger,
sse *sse.Queue,
) *UpdateNotificationPublisher {
return &UpdateNotificationPublisher{
log: log,
sse: sse,
}
}
// Trim produces an *UpdateNotificationPublisher with the pathPattern
// trimmed from events otherwise published by p.
func (p *UpdateNotificationPublisher) Trim(pathPattern string) *UpdateNotificationPublisher {
p2 := *p
p2.trimBasePath = path.Join(p2.trimBasePath, pathPattern)
return &p2
}
// Group produces an *UpdateNotificationPublisher with the pathPattern
// appended to the base path used by p, if any, in publishing events.
// If no base path was set to p, then pathPattern becomes the base path.
func (p *UpdateNotificationPublisher) Group(pathPattern string) *UpdateNotificationPublisher {
p2 := *p
p2.basePathPattern = path.Join(p2.basePathPattern, pathPattern)
return &p2
}
// Publish must be applied AFTER a middleware puts in the Identity into the gin.Context.
func (p *UpdateNotificationPublisher) Publish(pathPattern string) gin.HandlerFunc {
trimBasePathSegs := getPathSegments(p.trimBasePath)
trimmedBasePathPattern := path.Join(p.basePathPattern, pathPattern)
trimmedBasePathPatternSegs := getPathSegments(trimmedBasePathPattern)
fullBasePathPatternSegs := append(trimBasePathSegs, trimmedBasePathPatternSegs...)
return func(c *gin.Context) {
reqPathSegs := getPathSegments(c.Request.URL.Path)
c.Next()
if len(c.Errors) > 0 {
return
}
if len(reqPathSegs) < len(fullBasePathPatternSegs) {
p.log.Errorf("req path is less that the full path: %v, %v", c.Request.URL.Path, path.Join(p.trimBasePath, p.basePathPattern, pathPattern))
return
}
// if the path is a subpath, then emit events along the subpath.
for i, s := range trimmedBasePathPatternSegs {
if isWildcard := s[0] == ':'; isWildcard {
continue
}
rs := reqPathSegs[i]
if isSubpath := s != rs; isSubpath {
continue
}
return
}
topEventParts := reqPathSegs[len(trimBasePathSegs):len(fullBasePathPatternSegs)]
topEvent := strings.Join(topEventParts, "_")
events := make([]string, len(reqPathSegs)-len(fullBasePathPatternSegs)+1)
events[0] = topEvent
parentEvent := topEvent
for i, s := range reqPathSegs[len(fullBasePathPatternSegs):] {
e := parentEvent + "_" + s
events[i+1] = e
parentEvent = e
}
acctID := GetIdentity(c).Account.AccountID
for _, e := range events {
go func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
if err := p.sse.Send(ctx, sse.Event{
AccountID: acctID,
Type: e,
Data: []byte(fmt.Sprintf(`{"eventType": %q}`, e)),
}); err != nil {
p.log.Errorf("failed to send sse event to listener: %v", err)
}
}()
}
}
}
func getPathSegments(p string) []string {
p = path.Clean(p)
if p == "" || p == "." || p == "/" {
return nil
}
return strings.Split(strings.Trim(p, "/"), "/")
}