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  }