github.com/la5nta/wl2k-go@v0.11.8/transport/ardop/ctrl_broadcast.go (about) 1 // Copyright 2015 Martin Hebnes Pedersen (LA5NTA). All rights reserved. 2 // Use of this source code is governed by the MIT-license that can be 3 // found in the LICENSE file. 4 5 package ardop 6 7 import ( 8 "log" 9 "time" 10 ) 11 12 type receiver interface { 13 sendChan() chan<- ctrlMsg 14 doneChan() <-chan struct{} 15 } 16 17 type StateReceiver struct { 18 cs <-chan State 19 msgs chan ctrlMsg 20 done chan struct{} 21 } 22 23 func (r StateReceiver) States() <-chan State { 24 return r.cs 25 } 26 27 func (r StateReceiver) Close() { 28 close(r.done) 29 } 30 31 func (r StateReceiver) sendChan() chan<- ctrlMsg { 32 return r.msgs 33 } 34 35 func (r StateReceiver) doneChan() <-chan struct{} { 36 return r.done 37 } 38 39 type rawReceiver struct { 40 msgs chan ctrlMsg // read from this to receive broadcasts 41 done chan struct{} // close this to unregister 42 } 43 44 func (r rawReceiver) Msgs() <-chan ctrlMsg { 45 return r.msgs 46 } 47 48 func (r rawReceiver) Close() { 49 close(r.done) 50 } 51 52 func (r rawReceiver) sendChan() chan<- ctrlMsg { 53 return r.msgs 54 } 55 56 func (r rawReceiver) doneChan() <-chan struct{} { 57 return r.done 58 } 59 60 type broadcaster struct { 61 msgs chan ctrlMsg // send on this will broadcast 62 register chan receiver // send on this will register 63 } 64 65 func newBroadcaster() broadcaster { 66 receivers := make([]receiver, 0, 1) 67 68 b := broadcaster{ 69 msgs: make(chan ctrlMsg), 70 register: make(chan receiver), 71 } 72 73 go func() { 74 defer func() { 75 for _, r := range receivers { 76 close(r.sendChan()) 77 } 78 receivers = nil 79 }() 80 81 for { 82 select { 83 case r := <-b.register: 84 receivers = append(receivers, r) 85 case msg, ok := <-b.msgs: 86 if !ok { 87 return 88 } 89 for i := 0; i < len(receivers); i++ { 90 r := receivers[i] 91 select { 92 case <-r.doneChan(): 93 // the receiver is done, remove it 94 close(r.sendChan()) 95 receivers = append(receivers[:i], receivers[i+1:]...) 96 i-- //REVIEW this 97 case r.sendChan() <- msg: 98 // Message sent 99 case <-time.After(500 * time.Millisecond): // This is a hack - some of the clients don't close properly 100 if debugEnabled() { 101 log.Println("Receiver timeout!") 102 } 103 close(r.sendChan()) 104 receivers = append(receivers[:i], receivers[i+1:]...) 105 i-- //REVIEW this 106 } 107 } 108 } 109 } 110 }() 111 112 return b 113 } 114 115 func (b *broadcaster) Listen() rawReceiver { 116 r := rawReceiver{ 117 make(chan ctrlMsg, 3), 118 make(chan struct{}), 119 } 120 b.register <- r 121 return r 122 } 123 124 func (b *broadcaster) ListenState() StateReceiver { 125 cs := make(chan State) 126 r := StateReceiver{ 127 msgs: make(chan ctrlMsg), 128 done: make(chan struct{}), 129 cs: cs, 130 } 131 go func() { 132 for msg := range r.msgs { 133 if msg.cmd == cmdNewState { 134 cs <- msg.State() 135 } 136 } 137 close(cs) 138 }() 139 b.register <- r 140 return r 141 } 142 143 func (b *broadcaster) Send(msg ctrlMsg) { 144 b.msgs <- msg 145 } 146 147 func (b *broadcaster) Close() { 148 close(b.msgs) 149 }