forked from Team254/cheesy-arena
-
Notifications
You must be signed in to change notification settings - Fork 0
/
notifier.go
57 lines (48 loc) · 1.86 KB
/
notifier.go
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
// Copyright 2014 Team 254. All Rights Reserved.
// Author: [email protected] (Patrick Fairbank)
//
// Publish-subscribe model for nonblocking notification of server events to websocket clients.
package main
import (
"log"
)
// Allow the listeners to buffer a small number of notifications to streamline delivery.
const notifyBufferSize = 3
type Notifier struct {
// The map is essentially a set; the value is ignored.
listeners map[chan interface{}]struct{}
}
func NewNotifier() *Notifier {
notifier := new(Notifier)
notifier.listeners = make(map[chan interface{}]struct{})
return notifier
}
// Registers and returns a channel that can be read from to receive notification messages. The caller is
// responsible for closing the channel, which will cause it to be reaped from the list of listeners.
func (notifier *Notifier) Listen() chan interface{} {
listener := make(chan interface{}, notifyBufferSize)
notifier.listeners[listener] = struct{}{}
return listener
}
// Sends the given message to all registered listeners, and cleans up any listeners that have closed.
func (notifier *Notifier) Notify(message interface{}) {
for listener, _ := range notifier.listeners {
notifier.notifyListener(listener, message)
}
}
func (notifier *Notifier) notifyListener(listener chan interface{}, message interface{}) {
defer func() {
// If channel is closed sending to it will cause a panic; recover and remove it from the list.
if r := recover(); r != nil {
delete(notifier.listeners, listener)
}
}()
// Do a non-blocking send. This guarantees that sending notifications won't interrupt the main event loop,
// at the risk of clients missing some messages if they don't read them all promptly.
select {
case listener <- message:
// The notification was sent and received successfully.
default:
log.Println("Failed to send a notification due to blocked listener.")
}
}