When you dispatch an event, it is identified by a unique name (e.g. "user.created"). Each listener registered for that name will receive an Event instance, which may implement additional interfaces for advanced behavior.
The simplest event type is the empty Event interface. For stoppable events, embed BaseEvent:
type MyEvent struct {
BaseEvent // provides StopPropagation, IsPropagationStopped
UserID string // custom payload
}
func (e *MyEvent) EventName() string {
return "my_event"
}
e.StopPropagation() in a listener to prevent further listeners from running."" to Dispatch.The EventDispatcher is the central hub. It maintains per-event listener lists (sharded locks + copy-on-write).
d := eventdispatcher.NewEventDispatcher()
sync.Map and per-event RWMutex for minimal contention.Register a listener function with optional priority:
unsubscribe := d.AddListener("user.created",
func(e eventdispatcher.Event) {
evt := e.(*UserCreated)
fmt.Println("User created:", evt.UserID)
},
10, // higher priority executes earlier
)
Parameters:
eventName (string)Listener (func(Event))priority (int, default 0)Unsubscribe: call the returned unsubscribe() closure to remove this listener by unique ID.
RemoveListener: remove by function pointer:
d.RemoveListener("user.created", yourFunc)
Define an event struct embedding BaseEvent or implementing EventName():
type OrderPlacedEvent struct {
BaseEvent
OrderID string
}
func (e *OrderPlacedEvent) EventName() string {
return "order.placed"
}
Send the event:
evt := &OrderPlacedEvent{OrderID: "1234"}
d.Dispatch(evt, "") // uses EventName()
Or explicitly:
d.Dispatch(evt, "order.placed")
For dynamic data or simple payloads, use GenericEvent with pooling:
// Acquire from pool
ge := eventdispatcher.AcquireGenericEvent("dynamic.event", map[string]interface{}{
"foo": 42,
})
// optional: ge.Subject = yourSubject
defer eventdispatcher.ReleaseGenericEvent(ge)
d.AddListener("dynamic.event", func(e eventdispatcher.Event) {
gev := e.(*eventdispatcher.GenericEvent)
fmt.Println("Arg foo:", gev.OffsetGet("foo"))
}, 0)
d.Dispatch(ge, "")
Arguments API:
GetArguments(), SetArguments(map)HasArgument, GetArgument, SetArgumentOffsetExists, OffsetGet, OffsetSet, OffsetUnset, GetIteratorPooling: reuse GenericEvent instances to reduce GC.
Group multiple event handlers in one struct:
type MySubscriber struct {
called map[string]int
}
func (s *MySubscriber) SubscribedEvents() []eventdispatcher.Subscription {
return []eventdispatcher.Subscription{
{"user.created", s.onUserCreated, 0},
{"order.placed", s.onOrderPlaced, 5},
}
}
sub := &MySubscriber{called: make(map[string]int)}
unsubs := d.AddSubscriber(sub)
// Remove a single listener
unsubs[0]()
// Remove all subscriber listeners
d.RemoveSubscriber(sub)
AddSubscriber returns individual unsubscribe closures if needed.RemoveSubscriber unsubscribes all registered handlers for that subscriber.Create a read-only proxy that panics on mutators:
imm := eventdispatcher.NewImmutableEventDispatcher(d)
imm.Dispatch(evt, "name") // works
imm.AddListener("x", nil,0) // panic
Use when you need to expose dispatcher without mutation rights.
EventDispatcher
NewEventDispatcher()AddListener(name string, fn Listener, prio int) func()RemoveListener(name string, fn Listener)Dispatch(event Event, name string) EventHasListeners(name string) boolListeners(name string) []ListenerAddSubscriber(sub Subscriber) []func()RemoveSubscriber(sub interface{})GenericEvent
NewGenericEvent(subject interface{}, args map[string]interface{}) *GenericEventGetSubject()/SetSubject()GetArguments()/SetArguments(map[string]interface{})HasArgument/GetArgument()SetArgument()OffsetExists/OffsetGet/OffsetSet/OffsetUnsetGetIterator()Pooling
AcquireGenericEvent(name string, payload interface{}) *GenericEventReleaseGenericEvent(*GenericEvent)ImmutableEventDispatcher
NewImmutableEventDispatcher(*EventDispatcher)Subscriber & Subscription
See full examples and tests in the examples/ directory of the repository.
// Complete sample
package main
import (
"fmt"
"github.com/lemric/eventdispatcher-go"
)
type MsgEvent struct {
eventdispatcher.BaseEvent
Msg string
}
func (e *MsgEvent) EventName() string { return "msg.event" }
func main() {
d := eventdispatcher.NewEventDispatcher()
d.AddListener("msg.event", func(evt eventdispatcher.Event) {
e := evt.(*MsgEvent)
fmt.Println("Received:", e.Msg)
}, 0)
d.Dispatch(&MsgEvent{Msg: "Hello"}, "")
}