github.com/vmware/transport-go@v1.3.4/bus/channel.go (about) 1 // Copyright 2019-2020 VMware, Inc. 2 // SPDX-License-Identifier: BSD-2-Clause 3 4 package bus 5 6 import ( 7 "github.com/google/uuid" 8 "github.com/vmware/transport-go/bridge" 9 "github.com/vmware/transport-go/model" 10 "sync" 11 "sync/atomic" 12 ) 13 14 // Channel represents the stream and the subscribed event handlers waiting for ticks on the stream 15 type Channel struct { 16 Name string `json:"string"` 17 eventHandlers []*channelEventHandler 18 galactic bool 19 galacticMappedDestination string 20 private bool 21 channelLock sync.Mutex 22 wg sync.WaitGroup 23 brokerSubs []*connectionSub 24 brokerConns []bridge.Connection 25 brokerMappedEvent chan bool 26 } 27 28 // Create a new Channel with the supplied Channel name. Returns a pointer to that Channel. 29 func NewChannel(channelName string) *Channel { 30 c := &Channel{ 31 Name: channelName, 32 eventHandlers: []*channelEventHandler{}, 33 channelLock: sync.Mutex{}, 34 galactic: false, 35 private: false, 36 wg: sync.WaitGroup{}, 37 brokerMappedEvent: make(chan bool, 10), 38 brokerConns: []bridge.Connection{}, 39 brokerSubs: []*connectionSub{}} 40 return c 41 } 42 43 // Mark the Channel as private 44 func (channel *Channel) SetPrivate(private bool) { 45 channel.private = private 46 } 47 48 // Mark the Channel as galactic 49 func (channel *Channel) SetGalactic(mappedDestination string) { 50 channel.galactic = true 51 channel.galacticMappedDestination = mappedDestination 52 } 53 54 // Mark the Channel as local 55 func (channel *Channel) SetLocal() { 56 channel.galactic = false 57 channel.galacticMappedDestination = "" 58 } 59 60 // Returns true is the Channel is marked as galactic 61 func (channel *Channel) IsGalactic() bool { 62 return channel.galactic 63 } 64 65 // Returns true if the Channel is marked as private 66 func (channel *Channel) IsPrivate() bool { 67 return channel.private 68 } 69 70 // Send a new message on this Channel, to all event handlers. 71 func (channel *Channel) Send(message *model.Message) { 72 channel.channelLock.Lock() 73 defer channel.channelLock.Unlock() 74 if eventHandlers := channel.eventHandlers; len(eventHandlers) > 0 { 75 76 // if a handler is run once only, then the slice will be mutated mid cycle. 77 // copy slice to ensure that removed handler is still fired. 78 handlerDuplicate := make([]*channelEventHandler, 0, len(eventHandlers)) 79 handlerDuplicate = append(handlerDuplicate, eventHandlers...) 80 for n, eventHandler := range handlerDuplicate { 81 if eventHandler.runOnce && atomic.LoadInt64(&eventHandler.runCount) > 0 { 82 channel.removeEventHandler(n) // remove from slice. 83 continue 84 } 85 channel.wg.Add(1) 86 go channel.sendMessageToHandler(eventHandler, message) 87 } 88 } 89 } 90 91 // Check if the Channel has any registered subscribers 92 func (channel *Channel) ContainsHandlers() bool { 93 return len(channel.eventHandlers) > 0 94 } 95 96 // Send message to handler function 97 func (channel *Channel) sendMessageToHandler(handler *channelEventHandler, message *model.Message) { 98 handler.callBackFunction(message) 99 atomic.AddInt64(&handler.runCount, 1) 100 channel.wg.Done() 101 } 102 103 // Subscribe a new handler function. 104 func (channel *Channel) subscribeHandler(handler *channelEventHandler) { 105 channel.channelLock.Lock() 106 defer channel.channelLock.Unlock() 107 channel.eventHandlers = append(channel.eventHandlers, handler) 108 } 109 110 func (channel *Channel) unsubscribeHandler(uuid *uuid.UUID) bool { 111 channel.channelLock.Lock() 112 defer channel.channelLock.Unlock() 113 114 for i, handler := range channel.eventHandlers { 115 if handler.uuid.String() == uuid.String() { 116 channel.removeEventHandler(i) 117 return true 118 } 119 } 120 return false 121 } 122 123 // Remove handler function from being subscribed to the Channel. 124 func (channel *Channel) removeEventHandler(index int) { 125 numHandlers := len(channel.eventHandlers) 126 if numHandlers <= 0 { 127 return 128 } 129 if index >= numHandlers { 130 return 131 } 132 133 // delete from event handler slice. 134 copy(channel.eventHandlers[index:], channel.eventHandlers[index+1:]) 135 channel.eventHandlers[numHandlers-1] = nil 136 channel.eventHandlers = channel.eventHandlers[:numHandlers-1] 137 } 138 139 func (channel *Channel) listenToBrokerSubscription(sub bridge.Subscription) { 140 for { 141 msg, m := <-sub.GetMsgChannel() 142 if m { 143 channel.Send(msg) 144 } else { 145 break 146 } 147 } 148 } 149 150 func (channel *Channel) isBrokerSubscribed(sub bridge.Subscription) bool { 151 channel.channelLock.Lock() 152 defer channel.channelLock.Unlock() 153 154 for _, cs := range channel.brokerSubs { 155 if sub.GetId().String() == cs.s.GetId().String() { 156 return true 157 } 158 } 159 return false 160 } 161 162 func (channel *Channel) isBrokerSubscribedToDestination(c bridge.Connection, dest string) bool { 163 channel.channelLock.Lock() 164 defer channel.channelLock.Unlock() 165 166 for _, cs := range channel.brokerSubs { 167 if cs.s != nil && cs.s.GetDestination() == dest && cs.c != nil && cs.c.GetId() == c.GetId() { 168 return true 169 } 170 } 171 return false 172 } 173 174 func (channel *Channel) addBrokerConnection(c bridge.Connection) { 175 channel.channelLock.Lock() 176 defer channel.channelLock.Unlock() 177 178 for _, brCon := range channel.brokerConns { 179 if brCon.GetId() == c.GetId() { 180 return 181 } 182 } 183 184 channel.brokerConns = append(channel.brokerConns, c) 185 } 186 187 func (channel *Channel) removeBrokerConnections() { 188 channel.channelLock.Lock() 189 defer channel.channelLock.Unlock() 190 191 channel.brokerConns = []bridge.Connection{} 192 } 193 194 func (channel *Channel) addBrokerSubscription(conn bridge.Connection, sub bridge.Subscription) { 195 cs := &connectionSub{c: conn, s: sub} 196 197 channel.channelLock.Lock() 198 channel.brokerSubs = append(channel.brokerSubs, cs) 199 channel.channelLock.Unlock() 200 201 go channel.listenToBrokerSubscription(sub) 202 } 203 204 func (channel *Channel) removeBrokerSubscription(sub bridge.Subscription) { 205 channel.channelLock.Lock() 206 defer channel.channelLock.Unlock() 207 208 for i, cs := range channel.brokerSubs { 209 if sub.GetId().String() == cs.s.GetId().String() { 210 channel.brokerSubs = removeSub(channel.brokerSubs, i) 211 } 212 } 213 } 214 215 func removeSub(s []*connectionSub, i int) []*connectionSub { 216 s[len(s)-1], s[i] = s[i], s[len(s)-1] 217 return s[:len(s)-1] 218 } 219 220 type connectionSub struct { 221 c bridge.Connection 222 s bridge.Subscription 223 }