github.com/vmware/transport-go@v1.3.4/bus/channel_manager.go (about) 1 // Copyright 2019-2020 VMware, Inc. 2 // SPDX-License-Identifier: BSD-2-Clause 3 4 package bus 5 6 import ( 7 "errors" 8 "fmt" 9 "github.com/google/uuid" 10 "github.com/vmware/transport-go/bridge" 11 "github.com/vmware/transport-go/model" 12 "sync" 13 ) 14 15 // ChannelManager interfaces controls all access to channels vis the bus. 16 type ChannelManager interface { 17 CreateChannel(channelName string) *Channel 18 DestroyChannel(channelName string) 19 CheckChannelExists(channelName string) bool 20 GetChannel(channelName string) (*Channel, error) 21 GetAllChannels() map[string]*Channel 22 SubscribeChannelHandler(channelName string, fn MessageHandlerFunction, runOnce bool) (*uuid.UUID, error) 23 UnsubscribeChannelHandler(channelName string, id *uuid.UUID) error 24 WaitForChannel(channelName string) error 25 MarkChannelAsGalactic(channelName string, brokerDestination string, connection bridge.Connection) (err error) 26 MarkChannelAsLocal(channelName string) (err error) 27 } 28 29 func NewBusChannelManager(bus EventBus) ChannelManager { 30 manager := new(busChannelManager) 31 manager.Channels = make(map[string]*Channel) 32 manager.bus = bus.(*transportEventBus) 33 return manager 34 } 35 36 type busChannelManager struct { 37 Channels map[string]*Channel 38 bus *transportEventBus 39 lock sync.RWMutex 40 } 41 42 // Create a new Channel with the supplied Channel name. Returns pointer to new Channel object 43 func (manager *busChannelManager) CreateChannel(channelName string) *Channel { 44 manager.lock.Lock() 45 defer manager.lock.Unlock() 46 47 channel, ok := manager.Channels[channelName] 48 if ok { 49 return channel 50 } 51 52 manager.Channels[channelName] = NewChannel(channelName) 53 go manager.bus.SendMonitorEvent(ChannelCreatedEvt, channelName, nil) 54 return manager.Channels[channelName] 55 } 56 57 // Destroy a Channel and all the handlers listening on it. 58 func (manager *busChannelManager) DestroyChannel(channelName string) { 59 manager.lock.Lock() 60 defer manager.lock.Unlock() 61 62 delete(manager.Channels, channelName) 63 go manager.bus.SendMonitorEvent(ChannelDestroyedEvt, channelName, nil) 64 } 65 66 // Get a pointer to a Channel by name. Returns points, or error if no Channel is found. 67 func (manager *busChannelManager) GetChannel(channelName string) (*Channel, error) { 68 manager.lock.RLock() 69 defer manager.lock.RUnlock() 70 71 if channel, ok := manager.Channels[channelName]; ok { 72 return channel, nil 73 } else { 74 return nil, errors.New("Channel does not exist: " + channelName) 75 } 76 } 77 78 // Get all channels currently open. Returns a map of Channel names and pointers to those Channel objects. 79 func (manager *busChannelManager) GetAllChannels() map[string]*Channel { 80 return manager.Channels 81 } 82 83 // Check Channel exists, returns true if so. 84 func (manager *busChannelManager) CheckChannelExists(channelName string) bool { 85 manager.lock.RLock() 86 defer manager.lock.RUnlock() 87 88 return manager.Channels[channelName] != nil 89 } 90 91 // Subscribe new handler lambda for Channel, bool flag runOnce determines if this is a single Fire handler. 92 // Returns UUID pointer, or error if there is no Channel by that name. 93 func (manager *busChannelManager) SubscribeChannelHandler(channelName string, fn MessageHandlerFunction, runOnce bool) (*uuid.UUID, error) { 94 channel, err := manager.GetChannel(channelName) 95 if err != nil { 96 return nil, err 97 } 98 id := uuid.New() 99 channel.subscribeHandler(&channelEventHandler{callBackFunction: fn, runOnce: runOnce, uuid: &id}) 100 manager.bus.SendMonitorEvent(ChannelSubscriberJoinedEvt, channelName, nil) 101 return &id, nil 102 } 103 104 // Unsubscribe a handler for a Channel event handler. 105 func (manager *busChannelManager) UnsubscribeChannelHandler(channelName string, uuid *uuid.UUID) error { 106 channel, err := manager.GetChannel(channelName) 107 if err != nil { 108 return err 109 } 110 found := channel.unsubscribeHandler(uuid) 111 if !found { 112 return fmt.Errorf("no handler in Channel '%s' for uuid [%s]", channelName, uuid) 113 } 114 manager.bus.SendMonitorEvent(ChannelSubscriberLeftEvt, channelName, nil) 115 return nil 116 } 117 118 func (manager *busChannelManager) WaitForChannel(channelName string) error { 119 channel, _ := manager.GetChannel(channelName) 120 if channel == nil { 121 return fmt.Errorf("no such Channel as '%s'", channelName) 122 } 123 channel.wg.Wait() 124 return nil 125 } 126 127 // Mark a channel as Galactic. This will map this channel to the supplied broker destination, if the broker connector 128 // is active and connected, this will result in a subscription to the broker destination being created. Returns 129 // an error if the channel does not exist. 130 func (manager *busChannelManager) MarkChannelAsGalactic(channelName string, dest string, conn bridge.Connection) (err error) { 131 channel, err := manager.GetChannel(channelName) 132 if err != nil { 133 return 134 } 135 136 // mark as galactic/ 137 channel.SetGalactic(dest) 138 139 // create a galactic event 140 pl := &galacticEvent{conn: conn, dest: dest} 141 142 manager.handleGalacticChannelEvent(channelName, pl) 143 return nil 144 } 145 146 // Mark a channel as Local. This will unmap the channel from the broker destination, and perform an unsubscribe 147 // operation if the broker connector is active and connected. Returns an error if the channel does not exist. 148 func (manager *busChannelManager) MarkChannelAsLocal(channelName string) (err error) { 149 channel, err := manager.GetChannel(channelName) 150 if err != nil { 151 return 152 } 153 channel.SetLocal() 154 155 // get rid of all broker connections. 156 channel.removeBrokerConnections() 157 158 manager.handleLocalChannelEvent(channelName) 159 160 return nil 161 } 162 163 func (manager *busChannelManager) handleGalacticChannelEvent(channelName string, ge *galacticEvent) { 164 ch, _ := manager.GetChannel(channelName) 165 166 if ge.conn == nil { 167 return 168 } 169 170 // check if channel is already subscribed on this connection 171 if !ch.isBrokerSubscribedToDestination(ge.conn, ge.dest) { 172 if sub, e := ge.conn.Subscribe(ge.dest); e == nil { 173 174 // add broker connection to channel. 175 ch.addBrokerConnection(ge.conn) 176 177 m := model.GenerateResponse(&model.MessageConfig{Payload: ge.dest}) // set the mapped destination as the payload 178 ch.addBrokerSubscription(ge.conn, sub) 179 manager.bus.SendMonitorEvent(BrokerSubscribedEvt, channelName, m) 180 select { 181 case ch.brokerMappedEvent <- true: // let channel watcher know, the channel is mapped 182 default: // if no-one is listening, drop. 183 } 184 } 185 } 186 } 187 188 func (manager *busChannelManager) handleLocalChannelEvent(channelName string) { 189 ch, _ := manager.GetChannel(channelName) 190 // loop through all the connections we have mapped, and subscribe! 191 for _, s := range ch.brokerSubs { 192 if e := s.s.Unsubscribe(); e == nil { 193 ch.removeBrokerSubscription(s.s) 194 m := model.GenerateResponse(&model.MessageConfig{Payload: s.s.GetDestination()}) // set the unmapped destination as the payload 195 manager.bus.SendMonitorEvent(BrokerUnsubscribedEvt, channelName, m) 196 select { 197 case ch.brokerMappedEvent <- false: // let channel watcher know, the channel is un-mapped 198 default: // if no-one is listening, drop. 199 } 200 } 201 } 202 // get rid of all broker subscriptions on this channel. 203 ch.removeBrokerConnections() 204 } 205 206 type galacticEvent struct { 207 conn bridge.Connection 208 dest string 209 }