package proxy import "sync" // EventBus dispatches proxy lifecycle events to registered listeners. // Dispatch is synchronous on the calling goroutine. Listeners must not block. // // bus := proxy.NewEventBus() // bus.Subscribe(proxy.EventLogin, customDiff.OnLogin) // bus.Subscribe(proxy.EventAccept, stats.OnAccept) type EventBus struct { listeners map[EventType][]EventHandler mu sync.RWMutex } // EventType identifies the proxy lifecycle event. type EventType int const ( EventLogin EventType = iota // miner completed login EventSubmit // miner submitted a share EventAccept // pool accepted a submitted share EventReject // pool rejected a share (or share expired) EventClose // miner TCP connection closed ) // EventHandler is the callback signature for all event types. type EventHandler func(Event) // Event carries the data for any proxy lifecycle event. // Fields not relevant to the event type are zero/nil. // // bus.Dispatch(proxy.Event{Type: proxy.EventLogin, Miner: m}) type Event struct { Type EventType Miner *Miner // always set Job *Job // set for Accept and Reject events JobID string // set for Submit events Nonce string // set for Submit events Result string // set for Submit events Algo string // set for Submit events RequestID int64 // set for Submit events Diff uint64 // effective difficulty of the share (Accept and Reject) Error string // rejection reason (Reject only) Latency uint16 // pool response time in ms (Accept and Reject) Expired bool // true if the share was accepted but against the previous job } // NewEventBus builds an empty synchronous event dispatcher. // // bus := proxy.NewEventBus() func NewEventBus() *EventBus { return &EventBus{ listeners: make(map[EventType][]EventHandler), } } // Subscribe registers a handler for the given event type. Safe to call before Start. // // bus.Subscribe(proxy.EventAccept, func(e proxy.Event) { stats.OnAccept(e) }) func (b *EventBus) Subscribe(eventType EventType, handler EventHandler) { if handler == nil { return } b.mu.Lock() defer b.mu.Unlock() b.listeners[eventType] = append(b.listeners[eventType], handler) } // Dispatch calls all registered handlers for the event's type in subscription order. // // bus.Dispatch(proxy.Event{Type: proxy.EventLogin, Miner: m}) func (b *EventBus) Dispatch(event Event) { b.mu.RLock() handlers := append([]EventHandler(nil), b.listeners[event.Type]...) b.mu.RUnlock() for _, handler := range handlers { handler(event) } }