Design and implement an event-driven messaging system in Go that supports middleware processing, similar to middleware patterns found in web frameworks like Express.js or Gin.
Build an event bus system that allows:
- Event Registration: Subscribe handlers to named events
- Middleware Pipeline: Process events through middleware before reaching handlers
- Event Emission: Trigger events with associated data
- One-time Handlers: Support handlers that automatically unsubscribe after first execution
Your implementation should support the following usage pattern:
func main() {
// Create event bus
bus := NewEventBus()
// Register middleware that runs for ALL events
bus.Use(func(event string, data EventData, next func()) {
log.Printf("[Middleware] Processing event: %s", event)
data["timestamp"] = time.Now().Unix()
next() // Call next to continue the middleware chain
})
// Register multiple handlers for the same event
bus.On("user:login", func(data EventData) {
fmt.Printf("User %v logged in at %v\n", data["username"], data["timestamp"])
})
bus.On("user:login", func(data EventData) {
fmt.Printf("Send welcome email to %v\n", data["username"])
})
// Register a one-time handler
bus.Once("app:init", func(data EventData) {
fmt.Println("Application initialized")
})
// Emit events
bus.Emit("user:login", EventData{"username": "alice", "ip": "192.168.1.1"})
bus.Emit("app:init", EventData{})
bus.Emit("app:init", EventData{}) // Should not trigger the Once handler again
}- Design a flexible approach for event data (consider generics, interfaces, or other Go patterns)
- Each middleware must call
next()to continue the chain - Middleware can modify event data before it reaches handlers
- If middleware doesn't call
next(), the chain stops
Focus on getting a working solution first, then optimize. Good luck!