|
@@ -0,0 +1,73 @@
|
|
|
|
+package broadcast
|
|
|
|
+
|
|
|
|
+type Broadcast struct {
|
|
|
|
+ listeners []chan interface{}
|
|
|
|
+ reg chan (chan interface{})
|
|
|
|
+ unreg chan (chan interface{})
|
|
|
|
+ in chan interface{}
|
|
|
|
+ stop chan int64
|
|
|
|
+ stopStatus bool
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func NewBroadcast() *Broadcast {
|
|
|
|
+ b := &Broadcast{
|
|
|
|
+ listeners: make([]chan interface{}, 0),
|
|
|
|
+ reg: make(chan (chan interface{})),
|
|
|
|
+ unreg: make(chan (chan interface{})),
|
|
|
|
+ in: make(chan interface{}),
|
|
|
|
+ stop: make(chan int64),
|
|
|
|
+ stopStatus: false,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ go func() {
|
|
|
|
+ for {
|
|
|
|
+ select {
|
|
|
|
+ case l := <-b.unreg:
|
|
|
|
+ // remove L from b.listeners
|
|
|
|
+ // this operation is slow: O(n) but not used frequently
|
|
|
|
+ // unlike iterating over listeners
|
|
|
|
+ oldListeners := b.listeners
|
|
|
|
+ b.listeners = make([]chan interface{}, 0, len(oldListeners))
|
|
|
|
+ for _, oldL := range oldListeners {
|
|
|
|
+ if l != oldL {
|
|
|
|
+ b.listeners = append(b.listeners, oldL)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ case l := <-b.reg:
|
|
|
|
+ b.listeners = append(b.listeners, l)
|
|
|
|
+
|
|
|
|
+ case item := <-b.in:
|
|
|
|
+ for _, l := range b.listeners {
|
|
|
|
+ l <- item
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ case _ = <-b.stop:
|
|
|
|
+ b.stopStatus = true
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ return b
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (b *Broadcast) In() chan interface{} {
|
|
|
|
+ return b.in
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (b *Broadcast) Reg() chan interface{} {
|
|
|
|
+ listener := make(chan interface{})
|
|
|
|
+ b.reg <- listener
|
|
|
|
+ return listener
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (b *Broadcast) UnReg(listener chan interface{}) {
|
|
|
|
+ b.unreg <- listener
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (b *Broadcast) Close() {
|
|
|
|
+ if b.stopStatus == false {
|
|
|
|
+ b.stop <- 1
|
|
|
|
+ }
|
|
|
|
+}
|