gobot.io/x/gobot/v2@v2.1.0/eventer.go (about)

     1  package gobot
     2  
     3  import "sync"
     4  
     5  type eventChannel chan *Event
     6  
     7  type eventer struct {
     8  	// map of valid Event names
     9  	eventnames map[string]string
    10  
    11  	// new events get put in to the event channel
    12  	in eventChannel
    13  
    14  	// map of out channels used by subscribers
    15  	outs map[eventChannel]eventChannel
    16  
    17  	// mutex to protect the eventChannel map
    18  	eventsMutex sync.Mutex
    19  }
    20  
    21  const eventChanBufferSize = 10
    22  
    23  // Eventer is the interface which describes how a Driver or Adaptor
    24  // handles events.
    25  type Eventer interface {
    26  	// Events returns the map of valid Event names.
    27  	Events() (eventnames map[string]string)
    28  
    29  	// Event returns an Event string from map of valid Event names.
    30  	// Mostly used to validate that an Event name is valid.
    31  	Event(name string) string
    32  
    33  	// AddEvent registers a new Event name.
    34  	AddEvent(name string)
    35  
    36  	// DeleteEvent removes a previously registered Event name.
    37  	DeleteEvent(name string)
    38  
    39  	// Publish new events to any subscriber
    40  	Publish(name string, data interface{})
    41  
    42  	// Subscribe to events
    43  	Subscribe() (events eventChannel)
    44  
    45  	// Unsubscribe from an event channel
    46  	Unsubscribe(events eventChannel)
    47  
    48  	// Event handler
    49  	On(name string, f func(s interface{})) (err error)
    50  
    51  	// Event handler, only executes one time
    52  	Once(name string, f func(s interface{})) (err error)
    53  }
    54  
    55  // NewEventer returns a new Eventer.
    56  func NewEventer() Eventer {
    57  	evtr := &eventer{
    58  		eventnames: make(map[string]string),
    59  		in:         make(eventChannel, eventChanBufferSize),
    60  		outs:       make(map[eventChannel]eventChannel),
    61  	}
    62  
    63  	// goroutine to cascade "in" events to all "out" event channels
    64  	go func() {
    65  		for {
    66  			evt := <-evtr.in
    67  			evtr.eventsMutex.Lock()
    68  			for _, out := range evtr.outs {
    69  				out <- evt
    70  			}
    71  			evtr.eventsMutex.Unlock()
    72  		}
    73  	}()
    74  
    75  	return evtr
    76  }
    77  
    78  // Events returns the map of valid Event names.
    79  func (e *eventer) Events() map[string]string {
    80  	return e.eventnames
    81  }
    82  
    83  // Event returns an Event string from map of valid Event names.
    84  // Mostly used to validate that an Event name is valid.
    85  func (e *eventer) Event(name string) string {
    86  	return e.eventnames[name]
    87  }
    88  
    89  // AddEvent registers a new Event name.
    90  func (e *eventer) AddEvent(name string) {
    91  	e.eventnames[name] = name
    92  }
    93  
    94  // DeleteEvent removes a previously registered Event name.
    95  func (e *eventer) DeleteEvent(name string) {
    96  	delete(e.eventnames, name)
    97  }
    98  
    99  // Publish new events to anyone that is subscribed
   100  func (e *eventer) Publish(name string, data interface{}) {
   101  	evt := NewEvent(name, data)
   102  	e.in <- evt
   103  }
   104  
   105  // Subscribe to any events from this eventer
   106  func (e *eventer) Subscribe() eventChannel {
   107  	e.eventsMutex.Lock()
   108  	defer e.eventsMutex.Unlock()
   109  	out := make(eventChannel, eventChanBufferSize)
   110  	e.outs[out] = out
   111  	return out
   112  }
   113  
   114  // Unsubscribe from the event channel
   115  func (e *eventer) Unsubscribe(events eventChannel) {
   116  	e.eventsMutex.Lock()
   117  	defer e.eventsMutex.Unlock()
   118  	delete(e.outs, events)
   119  }
   120  
   121  // On executes the event handler f when e is Published to.
   122  func (e *eventer) On(n string, f func(s interface{})) (err error) {
   123  	out := e.Subscribe()
   124  	go func() {
   125  		for {
   126  			evt := <-out
   127  			if evt.Name == n {
   128  				f(evt.Data)
   129  			}
   130  		}
   131  	}()
   132  
   133  	return
   134  }
   135  
   136  // Once is similar to On except that it only executes f one time.
   137  func (e *eventer) Once(n string, f func(s interface{})) (err error) {
   138  	out := e.Subscribe()
   139  	go func() {
   140  	ProcessEvents:
   141  		for evt := range out {
   142  			if evt.Name == n {
   143  				f(evt.Data)
   144  				e.Unsubscribe(out)
   145  				break ProcessEvents
   146  			}
   147  		}
   148  	}()
   149  
   150  	return
   151  }