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  }