Files
htwkalender/datamanager/backend/tools/hook/hook.go
2024-03-03 18:21:50 +01:00

60 lines
1.1 KiB
Go

package hook
import (
"datamanager/backend/tools/security"
"errors"
"fmt"
"sync"
)
type Handler[T any] func(e T) error
type handlerPair[T any] struct {
id string
handler Handler[T]
}
type Hook[T any] struct {
mux sync.RWMutex
handlers []*handlerPair[T]
}
var StopPropagation = errors.New("event hook propagation stopped")
func (h *Hook[T]) Trigger(data T, oneOffHandlers ...Handler[T]) error {
h.mux.RLock()
handlers := make([]*handlerPair[T], 0, len(h.handlers)+len(oneOffHandlers))
handlers = append(handlers, h.handlers...)
// append the one off handlers
for i, oneOff := range oneOffHandlers {
handlers = append(handlers, &handlerPair[T]{
id: fmt.Sprintf("@%d", i),
handler: oneOff,
})
}
// unlock is not deferred to avoid deadlocks in case Trigger
// is called recursively by the handlers
h.mux.RUnlock()
for _, item := range handlers {
err := item.handler(data)
if err == nil {
continue
}
if errors.Is(err, StopPropagation) {
return nil
}
return err
}
return nil
}
func generateHookId() string {
return security.PseudorandomString(8)
}