better handler registration and dispatch

This commit is contained in:
admin 2025-07-10 10:23:03 +02:00
parent f27890e55e
commit c6bf54943a
15 changed files with 190 additions and 81 deletions

View File

@ -2,10 +2,11 @@ package serverevents
import ( import (
gocontext "context" gocontext "context"
di "git.apihub24.de/admin/generic-di"
"github.com/coder/websocket"
"sync" "sync"
"time" "time"
di "git.apihub24.de/admin/generic-di"
"github.com/coder/websocket"
) )
func init() { func init() {
@ -21,7 +22,7 @@ type IContext interface {
Get(key string) (any, bool) Get(key string) (any, bool)
RemoveMetaData(key string) RemoveMetaData(key string)
CleanupIn(lifetime time.Duration) CleanupIn(lifetime time.Duration)
Dispatch(eventName string, data any, filter func(c IContext) bool) Dispatch(event IEvent, filter func(c IContext) bool)
IsCaller(c IContext) bool IsCaller(c IContext) bool
} }
@ -84,9 +85,7 @@ func (context *context) RemoveMetaData(key string) {
context.mutex.Lock() context.mutex.Lock()
defer context.mutex.Unlock() defer context.mutex.Unlock()
if _, ok := context.metadata[key]; ok { delete(context.metadata, key)
delete(context.metadata, key)
}
} }
func (context *context) CleanupIn(lifetime time.Duration) { func (context *context) CleanupIn(lifetime time.Duration) {
@ -110,10 +109,10 @@ func (context *context) CleanupIn(lifetime time.Duration) {
}(context.id) }(context.id)
} }
func (context *context) Dispatch(eventName string, data any, filter func(c IContext) bool) { func (context *context) Dispatch(event IEvent, filter func(c IContext) bool) {
ev := Event{ ev := Event{
Type: eventName, Type: event.GetEventName(),
Data: data, Data: event.GetEventData(),
IsBackendOnly: filter == nil, IsBackendOnly: filter == nil,
Filter: filter, Filter: filter,
} }

View File

@ -6,3 +6,8 @@ type Event struct {
IsBackendOnly bool `json:"-"` IsBackendOnly bool `json:"-"`
Filter func(c IContext) bool `json:"-"` Filter func(c IContext) bool `json:"-"`
} }
type IEvent interface {
GetEventName() string
GetEventData() any
}

View File

@ -1,6 +1,7 @@
package serverevents package serverevents
type IEventHandler interface { type IEventHandler interface {
GetConnectedEventName() string
CanExecute(IContext) bool CanExecute(IContext) bool
Handle(IContext, any) Handle(IContext, any)
} }

View File

@ -0,0 +1,5 @@
package dto
type Greeting struct {
Message string `json:"message"`
}

View File

@ -0,0 +1,26 @@
package definitions
import (
serverevents "git.apihub24.de/admin/server_events/v2"
"git.apihub24.de/admin/server_events/v2/implementation_test/data/dto"
)
const GreeterEventName = "greet"
type greetEvent struct {
data dto.Greeting
}
func NewGreetEvent(data dto.Greeting) serverevents.IEvent {
return &greetEvent{
data: data,
}
}
func (ev *greetEvent) GetEventName() string {
return GreeterEventName
}
func (ev *greetEvent) GetEventData() any {
return ev.data
}

View File

@ -0,0 +1,23 @@
package definitions
import serverevents "git.apihub24.de/admin/server_events/v2"
const GreetMeEventName = "greet me"
type greetMeEvent struct {
data string
}
func NewGreetMeEvent(name string) serverevents.IEvent {
return &greetMeEvent{
data: name,
}
}
func (ev *greetMeEvent) GetEventName() string {
return GreetMeEventName
}
func (ev *greetMeEvent) GetEventData() any {
return ev.data
}

View File

@ -0,0 +1,19 @@
package definitions
import serverevents "git.apihub24.de/admin/server_events/v2"
const PingEventName = "ping"
type pingEvent struct{}
func NewPingEvent() serverevents.IEvent {
return &pingEvent{}
}
func (ev *pingEvent) GetEventName() string {
return PingEventName
}
func (ev *pingEvent) GetEventData() any {
return nil
}

View File

@ -0,0 +1,19 @@
package definitions
import serverevents "git.apihub24.de/admin/server_events/v2"
const PongEventName = "pong"
type pongEvent struct{}
func NewPongEvent() serverevents.IEvent {
return &pongEvent{}
}
func (ev *pongEvent) GetEventName() string {
return PongEventName
}
func (ev *pongEvent) GetEventData() any {
return nil
}

View File

@ -1,39 +0,0 @@
package events
import (
"fmt"
serverevents "git.apihub24.de/admin/server_events/v2"
)
func withSameUserName(context serverevents.IContext) func(context serverevents.IContext) bool {
return serverevents.CreateMetaDataFilter(context, func(c serverevents.IContext) string {
userName, _ := serverevents.MetadataAs[string](context, "UserName")
return userName
}, func(a string, b string) bool {
return a == b
})
}
type greeting struct {
Message string
}
type greeterEventHandler struct{}
func (handler greeterEventHandler) CanExecute(_ serverevents.IContext) bool {
return true
}
func (handler greeterEventHandler) Handle(context serverevents.IContext, data any) {
userName, ok := serverevents.ValueAs[string](data)
if !ok || len(userName) < 1 {
userName = "Anonymous"
}
context.Dispatch("greet", greeting{
Message: fmt.Sprintf("Hello, %s", userName),
}, withSameUserName(context))
}
func NewGreeterEventHandler() serverevents.IEventHandler {
return &greeterEventHandler{}
}

View File

@ -0,0 +1,34 @@
package handler
import (
"fmt"
serverevents "git.apihub24.de/admin/server_events/v2"
"git.apihub24.de/admin/server_events/v2/implementation_test/data/dto"
"git.apihub24.de/admin/server_events/v2/implementation_test/events/definitions"
"git.apihub24.de/admin/server_events/v2/implementation_test/filter"
)
type greetMeEventHandler struct{}
func NewGreetMeEventHandler() serverevents.IEventHandler {
return &greetMeEventHandler{}
}
func (handler *greetMeEventHandler) GetConnectedEventName() string {
return definitions.GreetMeEventName
}
func (handler *greetMeEventHandler) CanExecute(_ serverevents.IContext) bool {
return true
}
func (handler *greetMeEventHandler) Handle(context serverevents.IContext, data any) {
userName, ok := serverevents.ValueAs[string](data)
if !ok || len(userName) < 1 {
userName = "Anonymous"
}
context.Dispatch(definitions.NewGreetEvent(dto.Greeting{
Message: fmt.Sprintf("Hello, %s", userName),
}), filter.WithSameUserName(context))
}

View File

@ -0,0 +1,24 @@
package handler
import (
serverevents "git.apihub24.de/admin/server_events/v2"
"git.apihub24.de/admin/server_events/v2/implementation_test/events/definitions"
)
type pingEventHandler struct{}
func NewPingEventHandler() serverevents.IEventHandler {
return &pingEventHandler{}
}
func (handler *pingEventHandler) GetConnectedEventName() string {
return definitions.PingEventName
}
func (handler *pingEventHandler) CanExecute(_ serverevents.IContext) bool {
return true
}
func (handler *pingEventHandler) Handle(context serverevents.IContext, _ any) {
context.Dispatch(definitions.NewPongEvent(), context.IsCaller)
}

View File

@ -1,19 +0,0 @@
package events
import (
serverevents "git.apihub24.de/admin/server_events/v2"
)
type pingEventHandler struct{}
func NewPingEventHandler() serverevents.IEventHandler {
return &pingEventHandler{}
}
func (p pingEventHandler) CanExecute(_ serverevents.IContext) bool {
return true
}
func (p pingEventHandler) Handle(context serverevents.IContext, _ any) {
context.Dispatch("pong", nil, context.IsCaller)
}

View File

@ -0,0 +1,12 @@
package filter
import serverevents "git.apihub24.de/admin/server_events/v2"
func WithSameUserName(context serverevents.IContext) func(context serverevents.IContext) bool {
return serverevents.CreateMetaDataFilter(context, func(c serverevents.IContext) string {
userName, _ := serverevents.MetadataAs[string](context, "UserName")
return userName
}, func(a string, b string) bool {
return a == b
})
}

View File

@ -1,20 +1,21 @@
package main package main
import ( import (
di "git.apihub24.de/admin/generic-di"
serverevents "git.apihub24.de/admin/server_events/v2"
"git.apihub24.de/admin/server_events/v2/implementation_test/events"
"log" "log"
"net/http" "net/http"
"time" "time"
di "git.apihub24.de/admin/generic-di"
serverevents "git.apihub24.de/admin/server_events/v2"
"git.apihub24.de/admin/server_events/v2/implementation_test/events/handler"
) )
func main() { func main() {
serverEventsMiddleware := di.Inject[serverevents.IMiddleware]() serverEventsMiddleware := di.Inject[serverevents.IMiddleware]()
eventRegistration := di.Inject[serverevents.IEventHandlerRegistration]() eventRegistration := di.Inject[serverevents.IEventHandlerRegistration]()
eventRegistration.Add("ping", events.NewPingEventHandler) eventRegistration.Use(handler.NewPingEventHandler)
eventRegistration.Add("greet me", events.NewGreeterEventHandler) eventRegistration.Use(handler.NewGreetMeEventHandler)
router := http.NewServeMux() router := http.NewServeMux()

View File

@ -2,8 +2,9 @@ package serverevents
import ( import (
"fmt" "fmt"
di "git.apihub24.de/admin/generic-di"
"sync" "sync"
di "git.apihub24.de/admin/generic-di"
) )
func init() { func init() {
@ -11,7 +12,7 @@ func init() {
} }
type IEventHandlerRegistration interface { type IEventHandlerRegistration interface {
Add(eventType string, creator func() IEventHandler) Use(creator func() IEventHandler)
GetHandler(eventType string) (IEventHandler, error) GetHandler(eventType string) (IEventHandler, error)
} }
@ -29,16 +30,14 @@ func newEventHandlerRegistration() IEventHandlerRegistration {
} }
} }
func (registration *eventHandlerRegistration) Add(eventType string, creator func() IEventHandler) { func (registration *eventHandlerRegistration) Use(creator func() IEventHandler) {
registration.mutex.Lock() registration.mutex.Lock()
defer registration.mutex.Unlock() defer registration.mutex.Unlock()
if _, ok := registration.instances[eventType]; ok { tmp := creator()
delete(registration.instances, eventType) eventType := tmp.GetConnectedEventName()
} delete(registration.instances, eventType)
if _, ok := registration.creators[eventType]; ok { delete(registration.creators, eventType)
delete(registration.creators, eventType)
}
registration.creators[eventType] = creator registration.creators[eventType] = creator
} }