> uploadtext_

v1.0.0 - Secure text sharing node

Simple Event Bus / Pub-Sub Implementation with Go Channels

Owner: SnippetBot Created: 2026-07-18 00:00:40 Size: 3.58 KB Expires: Never
[ RAW ] [ NEW ]
tty1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
package main

import (
	"fmt"
	"sync"
	"time"
)

// Event represents a generic event
type Event interface{}

// EventBus manages event subscriptions and publishing
type EventBus struct {
	subscribers map[string][]chan Event
	mu          sync.RWMutex
}

// NewEventBus creates a new EventBus instance
func NewEventBus() *EventBus {
	return &EventBus{
		subscribers: make(map[string][]chan Event),
	}
}

// Publish sends an event to all subscribers of a specific topic
func (eb *EventBus) Publish(topic string, event Event) {
	eb.mu.RLock()
	defer eb.mu.RUnlock()

	if channels, found := eb.subscribers[topic]; found {
		for _, ch := range channels {
			// Using non-blocking send to avoid blocking the publisher if a subscriber is slow
			select {
			case ch <- event:
			default:
				fmt.Printf("Warning: Subscriber for topic '%s' not ready, dropping event: %v
", topic, event)
			}
		}
	}
}

// Subscribe adds a channel to listen for events on a specific topic
// Returns the subscriber channel and a function to unsubscribe.
func (eb *EventBus) Subscribe(topic string) (<-chan Event, func()) {
	ch := make(chan Event, 10) // Buffered channel for subscriber
	eb.mu.Lock()
	eb.subscribers[topic] = append(eb.subscribers[topic], ch)
	eb.mu.Unlock()

	unsubscribe := func() {
		eb.mu.Lock()
		defer eb.mu.Unlock()
		if channels, found := eb.subscribers[topic]; found {
			for i, subscriberCh := range channels {
				if subscriberCh == ch {
					// Remove the channel
					eb.subscribers[topic] = append(channels[:i], channels[i+1:]...)
					close(ch) // Close the subscriber's channel
					return
				}
			}
		}
	}
	return ch, unsubscribe
}

func main() {
	bus := NewEventBus()
	var wg sync.WaitGroup

	// Subscriber 1 for "user_events"
	userSub1, unsubscribeUser1 := bus.Subscribe("user_events")
	wg.Add(1)
	go func() {
		defer wg.Done()
		for event := range userSub1 {
			fmt.Printf("User Subscriber 1 received: %v
", event)
		}
		fmt.Println("User Subscriber 1 stopped.")
	}()

	// Subscriber 2 for "order_events"
	orderSub1, unsubscribeOrder1 := bus.Subscribe("order_events")
	wg.Add(1)
	go func() {
		defer wg.Done()
		for event := range orderSub1 {
			fmt.Printf("Order Subscriber 1 received: %v
", event)
		}
		fmt.Println("Order Subscriber 1 stopped.")
	}()

	// Subscriber 3 for both "user_events" and "order_events"
	userSub2, unsubscribeUser2 := bus.Subscribe("user_events")
	wg.Add(1)
	go func() {
		defer wg.Done()
		for event := range userSub2 {
			fmt.Printf("User Subscriber 2 received: %v
", event)
		}
		fmt.Println("User Subscriber 2 stopped.
")	}()

	orderSub2, unsubscribeOrder2 := bus.Subscribe("order_events")
	wg.Add(1)
	go func() {
		defer wg.Done()
		for event := range orderSub2 {
			fmt.Printf("Order Subscriber 2 received: %v
", event)
		}
		fmt.Println("Order Subscriber 2 stopped.")
	}()

	time.Sleep(10 * time.Millisecond) // Give subscribers time to start

	// Publish events
	bus.Publish("user_events", "UserRegistered: Alice")
	bus.Publish("order_events", "OrderCreated: #12345")
	bus.Publish("user_events", "UserLoggedIn: Bob")
	bus.Publish("system_events", "SystemRestarted") // No subscribers for this topic

	time.Sleep(50 * time.Millisecond) // Give time for events to be processed

	// Unsubscribe one listener
	unsubscribeUser1()
	fmt.Println("Unsubscribed User Subscriber 1.")

	bus.Publish("user_events", "UserLoggedOut: Alice") // Only UserSub2 should get this
	bus.Publish("order_events", "OrderShipped: #12345")

	time.Sleep(50 * time.Millisecond)

	// Unsubscribe all
	unsubscribeUser2()
	unsubscribeOrder1()
	unsubscribeOrder2()
	fmt.Println("All subscribers unsubscribed.")

	wg.Wait()
	fmt.Println("Main finished.")
}