package accesslog // LogChan describes the log channel. // See `Broker` for details. type LogChan chan Log // A Broker holds the active listeners, // incoming logs on its Notifier channel // and broadcast event data to all registered listeners. // // Exports the `NewListener` and `CloseListener` methods. type Broker struct { // Logs are pushed to this channel // by the main events-gathering `run` routine. Notifier LogChan // NewListener action. newListeners chan LogChan // CloseListener action. closingListeners chan LogChan // listeners store. listeners map[LogChan]bool // force-terminate all listeners. close chan struct{} } // newBroker returns a new broker factory. func newBroker() *Broker { b := &Broker{ Notifier: make(LogChan, 1), newListeners: make(chan LogChan), closingListeners: make(chan LogChan), listeners: make(map[LogChan]bool), close: make(chan struct{}), } // Listens and Broadcasts events. go b.run() return b } // run listens on different channels and act accordingly. func (b *Broker) run() { for { select { case s := <-b.newListeners: // A new channel has started to listen. b.listeners[s] = true case s := <-b.closingListeners: // A listener has dettached. // Stop sending them the logs. delete(b.listeners, s) case log := <-b.Notifier: // A new log sent by the logger. // Send it to all active listeners. for clientMessageChan := range b.listeners { clientMessageChan <- log } case <-b.close: for clientMessageChan := range b.listeners { delete(b.listeners, clientMessageChan) close(clientMessageChan) } } } } // notify sends the "log" to all active listeners. func (b *Broker) notify(log Log) { b.Notifier <- log } // NewListener returns a new log channel listener. // The caller SHALL NOT use this to write logs. func (b *Broker) NewListener() LogChan { // Each listener registers its own message channel with the Broker's connections registry. logs := make(LogChan) // Signal the broker that we have a new listener. b.newListeners <- logs return logs } // CloseListener removes the "ln" listener from the active listeners. func (b *Broker) CloseListener(ln LogChan) { b.closingListeners <- ln } // As we cant export a read-only and pass it as closing client // we will return a read-write channel on NewListener and add a note that the user // should NOT send data back to the channel, its use is read-only. // func (b *Broker) CloseListener(ln <-chan *Log) { // b.closingListeners <- ln // }