package event import ( "context" "fmt" "sync" . "git.gorlug.de/code/ersteller" "git.gorlug.de/code/ersteller/schema/ent" ) type Listener interface { OnEvent(ctx context.Context, userId int, name string, data any) } type Service struct { entClient *ent.Client listeners []Listener mu sync.RWMutex } func NewService(entClient *ent.Client) *Service { return &Service{ entClient: entClient, listeners: make([]Listener, 0), } } func (s *Service) AddListener(listener Listener) { s.mu.Lock() defer s.mu.Unlock() s.listeners = append(s.listeners, listener) } func (s *Service) RemoveListener(listener Listener) { s.mu.Lock() defer s.mu.Unlock() for i, l := range s.listeners { if l == listener { s.listeners = append(s.listeners[:i], s.listeners[i+1:]...) return } } } func (s *Service) notifyListeners(ctx context.Context, userId int, name string, data any) { s.mu.RLock() defer s.mu.RUnlock() for _, listener := range s.listeners { go listener.OnEvent(ctx, userId, name, data) } } func (s *Service) Create(htmxContext HtmxContext, name string, data any) error { err := Create(s.entClient, htmxContext, name, data) if err == nil { var userId int ok, authContext := htmxContext.GetAuthContext() if ok { userId = authContext.UserId } else { userId = -1 } s.notifyListeners(htmxContext.GetGoContext(), userId, name, data) } return err } func Should(err error) { if err != nil { Error("should not happen: ", err) } } func Create(entClient *ent.Client, c HtmxContext, name string, data any) error { Debug("event", name, data) hasAuth, authContext := c.GetAuthContext() if !hasAuth { return fmt.Errorf("failed to get auth context") } return CreateWithSession(entClient, c.GetGoContext(), authContext, name, data) } func CreateWithSession(entClient *ent.Client, ctx context.Context, auth AuthContext, name string, data any) error { return CreateWithSessionAndNotify(entClient, ctx, auth, name, data, nil) } func CreateWithSessionAndNotify(entClient *ent.Client, ctx context.Context, auth AuthContext, name string, data any, service *Service) error { Debug("event", name, data) var mapData JSONB if data == nil { mapData = make(JSONB) } else { mappedStruct, err := StructToMap(data) if err != nil { return fmt.Errorf("failed to map data to map for event create: %w", err) } mapData = mappedStruct } _, err := entClient.Event.Create(). SetUserID(auth.UserId). SetName(name). SetData(mapData). Save(ctx) if err != nil { return fmt.Errorf("failed to create event: %w", err) } if service != nil { service.notifyListeners(ctx, auth.UserId, name, data) } return nil }