github.com/CyCoreSystems/ari@v4.8.4+incompatible/ext/bridgemon/bridgemon.go (about)

     1  package bridgemon
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/CyCoreSystems/ari"
     7  )
     8  
     9  // Monitor is a bridge monitor, which maintains bridge data.  It monitors an ARI bridge for events and keeps an internal cache of the bridge's data.
    10  type Monitor struct {
    11  	h *ari.BridgeHandle
    12  
    13  	br *ari.BridgeData
    14  
    15  	sub    ari.Subscription
    16  	closed bool
    17  
    18  	watchers  []chan *ari.BridgeData
    19  	watcherMu sync.Mutex
    20  
    21  	mu sync.Mutex
    22  }
    23  
    24  // New returns a new bridge monitor
    25  func New(h *ari.BridgeHandle) *Monitor {
    26  
    27  	sub := h.Subscribe(ari.Events.BridgeDestroyed, ari.Events.ChannelEnteredBridge, ari.Events.ChannelLeftBridge)
    28  
    29  	m := &Monitor{
    30  		h:   h,
    31  		sub: sub,
    32  	}
    33  
    34  	// Monitor bridge events to keep data in sync
    35  	go m.monitor()
    36  
    37  	// Attempt to load initial bridge data; this may fail if the bridge has only
    38  	// been staged, so ignore errors here
    39  	data, _ := h.Data() // nolint
    40  	m.updateData(data)
    41  
    42  	return m
    43  }
    44  
    45  func (m *Monitor) monitor() {
    46  
    47  	defer m.Close()
    48  
    49  	for v := range m.sub.Events() {
    50  		if v == nil {
    51  			continue
    52  		}
    53  
    54  		switch v.GetType() {
    55  		case ari.Events.BridgeDestroyed:
    56  			e, ok := v.(*ari.BridgeDestroyed)
    57  			if !ok {
    58  				continue
    59  			}
    60  			m.updateData(&e.Bridge)
    61  			return // bridge is destroyed; there will be no more events
    62  		case ari.Events.ChannelEnteredBridge:
    63  			e, ok := v.(*ari.ChannelEnteredBridge)
    64  			if !ok {
    65  				continue
    66  			}
    67  			m.updateData(&e.Bridge)
    68  		case ari.Events.ChannelLeftBridge:
    69  			e, ok := v.(*ari.ChannelLeftBridge)
    70  			if !ok {
    71  				continue
    72  			}
    73  			m.updateData(&e.Bridge)
    74  		}
    75  	}
    76  
    77  }
    78  
    79  func (m *Monitor) updateData(data *ari.BridgeData) {
    80  
    81  	// Populate the bridge key in the bridge data, since Asterisk does not populate this field.
    82  	if data.Key == nil {
    83  		data.Key = m.h.Key()
    84  	}
    85  
    86  	// Update the stored data
    87  	m.mu.Lock()
    88  	m.br = data
    89  	m.mu.Unlock()
    90  
    91  	// Distribute new data to any watchers
    92  	m.watcherMu.Lock()
    93  	for _, w := range m.watchers {
    94  		select {
    95  		case w <- data:
    96  		default:
    97  		}
    98  	}
    99  	m.watcherMu.Unlock()
   100  
   101  }
   102  
   103  // Data returns the current bridge data
   104  func (m *Monitor) Data() *ari.BridgeData {
   105  	if m == nil {
   106  		return nil
   107  	}
   108  
   109  	return m.br
   110  }
   111  
   112  // Handle returns the BridgeHandle which was used to create the bridge Monitor.
   113  func (m *Monitor) Handle() *ari.BridgeHandle {
   114  	if m == nil {
   115  		return nil
   116  	}
   117  	return m.h
   118  }
   119  
   120  // Key returns the key of the monitored bridge
   121  func (m *Monitor) Key() *ari.Key {
   122  	if m == nil || m.h == nil {
   123  		return nil
   124  	}
   125  	return m.h.Key()
   126  }
   127  
   128  // Watch returns a channel on which bridge data will be returned when events
   129  // occur.  This channel will be closed when the bridge or the monitor is
   130  // destoyed.
   131  //
   132  // NOTE:  the user should NEVER close this channel directly.
   133  //
   134  func (m *Monitor) Watch() <-chan *ari.BridgeData {
   135  	ch := make(chan *ari.BridgeData)
   136  
   137  	m.mu.Lock()
   138  	defer m.mu.Unlock()
   139  	if m.closed {
   140  		close(ch)
   141  		return ch
   142  	}
   143  
   144  	m.watcherMu.Lock()
   145  	m.watchers = append(m.watchers, ch)
   146  	m.watcherMu.Unlock()
   147  
   148  	return ch
   149  }
   150  
   151  // Close shuts down a bridge monitor
   152  func (m *Monitor) Close() {
   153  	if m == nil {
   154  		return
   155  	}
   156  
   157  	m.mu.Lock()
   158  	if !m.closed {
   159  		m.closed = true
   160  		if m.sub != nil {
   161  			m.sub.Cancel()
   162  		}
   163  	}
   164  	m.mu.Unlock()
   165  
   166  	m.watcherMu.Lock()
   167  	for _, w := range m.watchers {
   168  		close(w)
   169  	}
   170  	m.watchers = nil
   171  	m.watcherMu.Unlock()
   172  }