github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/gossip/comm/demux.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package comm 18 19 import ( 20 "sync" 21 "sync/atomic" 22 23 "github.com/hyperledger/fabric/gossip/common" 24 ) 25 26 // ChannelDeMultiplexer is a struct that can receive channel registrations (AddChannel) 27 // and publications (DeMultiplex) and it broadcasts the publications to registrations 28 // according to their predicate 29 type ChannelDeMultiplexer struct { 30 channels []*channel 31 lock *sync.RWMutex 32 closed int32 33 } 34 35 // NewChannelDemultiplexer creates a new ChannelDeMultiplexer 36 func NewChannelDemultiplexer() *ChannelDeMultiplexer { 37 return &ChannelDeMultiplexer{ 38 channels: make([]*channel, 0), 39 lock: &sync.RWMutex{}, 40 closed: int32(0), 41 } 42 } 43 44 type channel struct { 45 pred common.MessageAcceptor 46 ch chan interface{} 47 } 48 49 func (m *ChannelDeMultiplexer) isClosed() bool { 50 return atomic.LoadInt32(&m.closed) == int32(1) 51 } 52 53 // Close closes this channel, which makes all channels registered before 54 // to close as well. 55 func (m *ChannelDeMultiplexer) Close() { 56 defer func() { 57 // recover closing an already closed channel 58 recover() 59 }() 60 atomic.StoreInt32(&m.closed, int32(1)) 61 m.lock.Lock() 62 defer m.lock.Unlock() 63 for _, ch := range m.channels { 64 close(ch.ch) 65 } 66 } 67 68 // AddChannel registers a channel with a certain predicate 69 func (m *ChannelDeMultiplexer) AddChannel(predicate common.MessageAcceptor) chan interface{} { 70 m.lock.Lock() 71 defer m.lock.Unlock() 72 ch := &channel{ch: make(chan interface{}, 10), pred: predicate} 73 m.channels = append(m.channels, ch) 74 return ch.ch 75 } 76 77 // DeMultiplex broadcasts the message to all channels that were returned 78 // by AddChannel calls and that hold the respected predicates. 79 func (m *ChannelDeMultiplexer) DeMultiplex(msg interface{}) { 80 defer func() { 81 recover() 82 }() // recover from sending on a closed channel 83 84 if m.isClosed() { 85 return 86 } 87 88 m.lock.RLock() 89 channels := m.channels 90 m.lock.RUnlock() 91 92 for _, ch := range channels { 93 if ch.pred(msg) { 94 ch.ch <- msg 95 } 96 } 97 }