Broadcaster for Multi-Sink Distribution

The Broadcaster is a core component of the go-events library, responsible for distributing events to multiple sinks.

Why Multi-Sink Distribution?

The Broadcaster enables a publish-subscribe model for events, allowing multiple components within a system to register as event listeners, receive and process the same events. This architecture offers significant benefits:

  • Decoupling: Event producers and consumers operate independently, reducing dependencies and promoting modularity.
  • Scalability: New listeners can be added without impacting existing code, facilitating growth and expansion.
  • Flexibility: Different components can subscribe to specific events based on their requirements, enabling tailored responses.
  • Resilience: If a listener fails, the event distribution continues without interruption, ensuring system reliability.

Broadcaster Implementation

The Broadcaster uses a concurrent approach, allowing multiple listeners to process events simultaneously.

Key Components:

  • Event Interface: Defines the contract for events, requiring a Type() method to identify the event type.
  • Sink Interface: Defines the contract for event listeners, requiring a Receive(Event) method to handle received events.
  • Broadcaster Struct: Manages the event distribution, containing a map of event types to a list of sinks registered for each type.

Core Functionality:

  1. Registering Sinks: Sinks are registered using the Register(EventType, Sink) method, associating the sink with a specific event type.
  2. Broadcasting Events: Events are broadcast using the Broadcast(Event) method. The broadcaster first identifies the event type and then dispatches the event to all registered sinks for that type.
  3. Unregistering Sinks: Sinks can be removed using the Unregister(EventType, Sink) method, ensuring they no longer receive events of the specified type.

Usage Examples

Example 1: Simple Event Broadcasting

package main
          
          import (
              "fmt"
              "github.com/docker/go-events"
          )
          
          // Define a custom event type.
          type MyEvent struct {
              Message string
          }
          
          // Implement the Event interface.
          func (e MyEvent) Type() string {
              return "my.event"
          }
          
          // Define a sink that prints received events.
          type PrintSink struct{}
          
          func (s PrintSink) Receive(e events.Event) {
              myEvent, ok := e.(MyEvent)
              if ok {
                  fmt.Println("Received event:", myEvent.Message)
              }
          }
          
          func main() {
              // Create a broadcaster.
              broadcaster := events.NewBroadcaster()
          
              // Register a sink for "my.event".
              broadcaster.Register("my.event", PrintSink{})
          
              // Create an event instance.
              myEvent := MyEvent{Message: "Hello, world!"}
          
              // Broadcast the event.
              broadcaster.Broadcast(myEvent)
          }
          

Example 2: Multi-Sink Event Handling

package main
          
          import (
              "fmt"
              "github.com/docker/go-events"
          )
          
          // Define a custom event type.
          type MyEvent struct {
              Message string
          }
          
          // Implement the Event interface.
          func (e MyEvent) Type() string {
              return "my.event"
          }
          
          // Define two sinks that handle events differently.
          type PrintSink struct{}
          
          func (s PrintSink) Receive(e events.Event) {
              myEvent, ok := e.(MyEvent)
              if ok {
                  fmt.Println("PrintSink:", myEvent.Message)
              }
          }
          
          type LogSink struct{}
          
          func (s LogSink) Receive(e events.Event) {
              myEvent, ok := e.(MyEvent)
              if ok {
                  fmt.Println("LogSink:", myEvent.Message)
              }
          }
          
          func main() {
              // Create a broadcaster.
              broadcaster := events.NewBroadcaster()
          
              // Register both sinks for "my.event".
              broadcaster.Register("my.event", PrintSink{})
              broadcaster.Register("my.event", LogSink{})
          
              // Create an event instance.
              myEvent := MyEvent{Message: "Hello, world!"}
          
              // Broadcast the event.
              broadcaster.Broadcast(myEvent)
          }
          

Example 3: Event Type Specific Sinks

package main
          
          import (
              "fmt"
              "github.com/docker/go-events"
          )
          
          // Define two event types.
          type EventOne struct{}
          
          func (e EventOne) Type() string {
              return "event.one"
          }
          
          type EventTwo struct{}
          
          func (e EventTwo) Type() string {
              return "event.two"
          }
          
          // Define sinks for each event type.
          type SinkOne struct{}
          
          func (s SinkOne) Receive(e events.Event) {
              fmt.Println("SinkOne received EventOne")
          }
          
          type SinkTwo struct{}
          
          func (s SinkTwo) Receive(e events.Event) {
              fmt.Println("SinkTwo received EventTwo")
          }
          
          func main() {
              // Create a broadcaster.
              broadcaster := events.NewBroadcaster()
          
              // Register sinks for specific event types.
              broadcaster.Register("event.one", SinkOne{})
              broadcaster.Register("event.two", SinkTwo{})
          
              // Broadcast different events.
              broadcaster.Broadcast(EventOne{})
              broadcaster.Broadcast(EventTwo{})
          }
          

Source: broadcaster.go