github.com/rentongzhang/docker@v1.8.2-rc1/pkg/pubsub/publisher.go (about) 1 package pubsub 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // NewPublisher creates a new pub/sub publisher to broadcast messages. 9 // The duration is used as the send timeout as to not block the publisher publishing 10 // messages to other clients if one client is slow or unresponsive. 11 // The buffer is used when creating new channels for subscribers. 12 func NewPublisher(publishTimeout time.Duration, buffer int) *Publisher { 13 return &Publisher{ 14 buffer: buffer, 15 timeout: publishTimeout, 16 subscribers: make(map[subscriber]struct{}), 17 } 18 } 19 20 type subscriber chan interface{} 21 22 // Publisher is basic pub/sub structure. Allows to send events and subscribe 23 // to them. Can be safely used from multiple goroutines. 24 type Publisher struct { 25 m sync.RWMutex 26 buffer int 27 timeout time.Duration 28 subscribers map[subscriber]struct{} 29 } 30 31 // Len returns the number of subscribers for the publisher 32 func (p *Publisher) Len() int { 33 p.m.RLock() 34 i := len(p.subscribers) 35 p.m.RUnlock() 36 return i 37 } 38 39 // Subscribe adds a new subscriber to the publisher returning the channel. 40 func (p *Publisher) Subscribe() chan interface{} { 41 ch := make(chan interface{}, p.buffer) 42 p.m.Lock() 43 p.subscribers[ch] = struct{}{} 44 p.m.Unlock() 45 return ch 46 } 47 48 // Evict removes the specified subscriber from receiving any more messages. 49 func (p *Publisher) Evict(sub chan interface{}) { 50 p.m.Lock() 51 delete(p.subscribers, sub) 52 close(sub) 53 p.m.Unlock() 54 } 55 56 // Publish sends the data in v to all subscribers currently registered with the publisher. 57 func (p *Publisher) Publish(v interface{}) { 58 p.m.RLock() 59 for sub := range p.subscribers { 60 // send under a select as to not block if the receiver is unavailable 61 if p.timeout > 0 { 62 select { 63 case sub <- v: 64 case <-time.After(p.timeout): 65 } 66 continue 67 } 68 select { 69 case sub <- v: 70 default: 71 } 72 } 73 p.m.RUnlock() 74 } 75 76 // Close closes the channels to all subscribers registered with the publisher. 77 func (p *Publisher) Close() { 78 p.m.Lock() 79 for sub := range p.subscribers { 80 delete(p.subscribers, sub) 81 close(sub) 82 } 83 p.m.Unlock() 84 }