gobot.io/x/gobot@v1.16.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  			select {
    67  			case evt := <-evtr.in:
    68  				evtr.eventsMutex.Lock()
    69  				for _, out := range evtr.outs {
    70  					out <- evt
    71  				}
    72  				evtr.eventsMutex.Unlock()
    73  			}
    74  		}
    75  	}()
    76  
    77  	return evtr
    78  }
    79  
    80  // Events returns the map of valid Event names.
    81  func (e *eventer) Events() map[string]string {
    82  	return e.eventnames
    83  }
    84  
    85  // Event returns an Event string from map of valid Event names.
    86  // Mostly used to validate that an Event name is valid.
    87  func (e *eventer) Event(name string) string {
    88  	return e.eventnames[name]
    89  }
    90  
    91  // AddEvent registers a new Event name.
    92  func (e *eventer) AddEvent(name string) {
    93  	e.eventnames[name] = name
    94  }
    95  
    96  // DeleteEvent removes a previously registered Event name.
    97  func (e *eventer) DeleteEvent(name string) {
    98  	delete(e.eventnames, name)
    99  }
   100  
   101  // Publish new events to anyone that is subscribed
   102  func (e *eventer) Publish(name string, data interface{}) {
   103  	evt := NewEvent(name, data)
   104  	e.in <- evt
   105  }
   106  
   107  // Subscribe to any events from this eventer
   108  func (e *eventer) Subscribe() eventChannel {
   109  	e.eventsMutex.Lock()
   110  	defer e.eventsMutex.Unlock()
   111  	out := make(eventChannel, eventChanBufferSize)
   112  	e.outs[out] = out
   113  	return out
   114  }
   115  
   116  // Unsubscribe from the event channel
   117  func (e *eventer) Unsubscribe(events eventChannel) {
   118  	e.eventsMutex.Lock()
   119  	defer e.eventsMutex.Unlock()
   120  	delete(e.outs, events)
   121  }
   122  
   123  // On executes the event handler f when e is Published to.
   124  func (e *eventer) On(n string, f func(s interface{})) (err error) {
   125  	out := e.Subscribe()
   126  	go func() {
   127  		for {
   128  			select {
   129  			case evt := <-out:
   130  				if evt.Name == n {
   131  					f(evt.Data)
   132  				}
   133  			}
   134  		}
   135  	}()
   136  
   137  	return
   138  }
   139  
   140  // Once is similar to On except that it only executes f one time.
   141  func (e *eventer) Once(n string, f func(s interface{})) (err error) {
   142  	out := e.Subscribe()
   143  	go func() {
   144  	ProcessEvents:
   145  		for evt := range out {
   146  			if evt.Name == n {
   147  				f(evt.Data)
   148  				e.Unsubscribe(out)
   149  				break ProcessEvents
   150  			}
   151  		}
   152  	}()
   153  
   154  	return
   155  }