github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/comm/demux.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package comm 8 9 import ( 10 "sync" 11 "sync/atomic" 12 13 "github.com/hyperledger/fabric/gossip/common" 14 ) 15 16 // ChannelDeMultiplexer is a struct that can receive channel registrations (AddChannel) 17 // and publications (DeMultiplex) and it broadcasts the publications to registrations 18 // according to their predicate 19 type ChannelDeMultiplexer struct { 20 channels []*channel 21 lock *sync.RWMutex 22 closed int32 23 } 24 25 // NewChannelDemultiplexer creates a new ChannelDeMultiplexer 26 func NewChannelDemultiplexer() *ChannelDeMultiplexer { 27 return &ChannelDeMultiplexer{ 28 channels: make([]*channel, 0), 29 lock: &sync.RWMutex{}, 30 closed: int32(0), 31 } 32 } 33 34 type channel struct { 35 pred common.MessageAcceptor 36 ch chan interface{} 37 } 38 39 func (m *ChannelDeMultiplexer) isClosed() bool { 40 return atomic.LoadInt32(&m.closed) == int32(1) 41 } 42 43 // Close closes this channel, which makes all channels registered before 44 // to close as well. 45 func (m *ChannelDeMultiplexer) Close() { 46 defer func() { 47 // recover closing an already closed channel 48 recover() 49 }() 50 atomic.StoreInt32(&m.closed, int32(1)) 51 m.lock.Lock() 52 defer m.lock.Unlock() 53 for _, ch := range m.channels { 54 close(ch.ch) 55 } 56 } 57 58 // AddChannel registers a channel with a certain predicate 59 func (m *ChannelDeMultiplexer) AddChannel(predicate common.MessageAcceptor) chan interface{} { 60 m.lock.Lock() 61 defer m.lock.Unlock() 62 ch := &channel{ch: make(chan interface{}, 10), pred: predicate} 63 m.channels = append(m.channels, ch) 64 return ch.ch 65 } 66 67 // DeMultiplex broadcasts the message to all channels that were returned 68 // by AddChannel calls and that hold the respected predicates. 69 func (m *ChannelDeMultiplexer) DeMultiplex(msg interface{}) { 70 defer func() { 71 recover() 72 }() // recover from sending on a closed channel 73 74 if m.isClosed() { 75 return 76 } 77 78 m.lock.RLock() 79 channels := m.channels 80 m.lock.RUnlock() 81 82 for _, ch := range channels { 83 if ch.pred(msg) { 84 ch.ch <- msg 85 } 86 } 87 }