github.com/enbility/spine-go@v0.7.0/spine/events.go (about)

     1  package spine
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/enbility/spine-go/api"
     7  )
     8  
     9  var Events events
    10  
    11  type eventHandlerItem struct {
    12  	Level   api.EventHandlerLevel
    13  	Handler api.EventHandlerInterface
    14  }
    15  
    16  type events struct {
    17  	mu       sync.Mutex
    18  	muHandle sync.Mutex
    19  
    20  	handlers []eventHandlerItem // event handling outside of the core stack
    21  }
    22  
    23  // will be used in EEBUS core directly to access the level EventHandlerLevelCore
    24  func (r *events) subscribe(level api.EventHandlerLevel, handler api.EventHandlerInterface) error {
    25  	r.mu.Lock()
    26  	defer r.mu.Unlock()
    27  
    28  	for _, item := range r.handlers {
    29  		if item.Level == level && item.Handler == handler {
    30  			return nil
    31  		}
    32  	}
    33  
    34  	newHandlerItem := eventHandlerItem{
    35  		Level:   level,
    36  		Handler: handler,
    37  	}
    38  	r.handlers = append(r.handlers, newHandlerItem)
    39  
    40  	return nil
    41  }
    42  
    43  // Subscribe to message events and handle them in
    44  // the Eventhandler interface implementation
    45  //
    46  // returns an error if EventHandlerLevelCore is used as
    47  // that is only allowed for internal use
    48  func (r *events) Subscribe(handler api.EventHandlerInterface) error {
    49  	return r.subscribe(api.EventHandlerLevelApplication, handler)
    50  }
    51  
    52  // will be used in EEBUS core directly to access the level EventHandlerLevelCore
    53  func (r *events) unsubscribe(level api.EventHandlerLevel, handler api.EventHandlerInterface) error {
    54  	r.mu.Lock()
    55  	defer r.mu.Unlock()
    56  
    57  	var newHandlers []eventHandlerItem
    58  	for _, item := range r.handlers {
    59  		if item.Level != level || item.Handler != handler {
    60  			newHandlers = append(newHandlers, item)
    61  		}
    62  	}
    63  
    64  	r.handlers = newHandlers
    65  
    66  	return nil
    67  }
    68  
    69  // Unsubscribe from getting events
    70  func (r *events) Unsubscribe(handler api.EventHandlerInterface) error {
    71  	return r.unsubscribe(api.EventHandlerLevelApplication, handler)
    72  }
    73  
    74  // Publish an event to all subscribers
    75  func (r *events) Publish(payload api.EventPayload) {
    76  	r.mu.Lock()
    77  	var handler []eventHandlerItem
    78  	copy(r.handlers, handler)
    79  	r.mu.Unlock()
    80  
    81  	// Use different locks, so unpublish is possible in the event handlers
    82  	r.muHandle.Lock()
    83  	// process subscribers by level
    84  	handlerLevels := []api.EventHandlerLevel{
    85  		api.EventHandlerLevelCore,
    86  		api.EventHandlerLevelApplication,
    87  	}
    88  
    89  	for _, level := range handlerLevels {
    90  		for _, item := range r.handlers {
    91  			if item.Level != level {
    92  				continue
    93  			}
    94  
    95  			if level == api.EventHandlerLevelCore {
    96  				// do not run this asynchronously, to make sure all required
    97  				// and expected actions are taken
    98  				item.Handler.HandleEvent(payload)
    99  			} else {
   100  				go item.Handler.HandleEvent(payload)
   101  			}
   102  		}
   103  	}
   104  	r.muHandle.Unlock()
   105  }