pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/events/events.go (about)

     1  // Package events provides methods and structs for creating event-driven systems
     2  package events
     3  
     4  // ////////////////////////////////////////////////////////////////////////////////// //
     5  //                                                                                    //
     6  //                         Copyright (c) 2022 ESSENTIAL KAOS                          //
     7  //      Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>     //
     8  //                                                                                    //
     9  // ////////////////////////////////////////////////////////////////////////////////// //
    10  
    11  import (
    12  	"fmt"
    13  	"reflect"
    14  	"sync"
    15  )
    16  
    17  // ////////////////////////////////////////////////////////////////////////////////// //
    18  
    19  // Dispatcher is event dispatcher
    20  type Dispatcher struct {
    21  	handlers map[string]Handlers
    22  	mx       *sync.RWMutex
    23  }
    24  
    25  // Handlers is a slice with handlers
    26  type Handlers []Handler
    27  
    28  // Handler is a function that handles an event
    29  type Handler func(payload interface{})
    30  
    31  // ////////////////////////////////////////////////////////////////////////////////// //
    32  
    33  var (
    34  	ErrNilDispatcher = fmt.Errorf("Dispatcher wasn't created properly")
    35  	ErrEmptyType     = fmt.Errorf("Event type is empty")
    36  	ErrNilHandler    = fmt.Errorf("Handler must not be nil")
    37  )
    38  
    39  // ////////////////////////////////////////////////////////////////////////////////// //
    40  
    41  // NewDispatcher creates new event dispatcher instance
    42  func NewDispatcher() *Dispatcher {
    43  	return &Dispatcher{
    44  		handlers: make(map[string]Handlers),
    45  		mx:       &sync.RWMutex{},
    46  	}
    47  }
    48  
    49  // ////////////////////////////////////////////////////////////////////////////////// //
    50  
    51  // AddHandler registers handler for events with given event type
    52  func (d *Dispatcher) AddHandler(typ string, handler Handler) error {
    53  	err := validateArguments(d, typ, handler, true)
    54  
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	d.mx.Lock()
    60  
    61  	if d.getHandlerIndex(typ, handler) != -1 {
    62  		d.mx.Unlock()
    63  		return fmt.Errorf("Handler already registered for given event type (%s)", typ)
    64  	}
    65  
    66  	d.handlers[typ] = append(d.handlers[typ], handler)
    67  
    68  	d.mx.Unlock()
    69  	return nil
    70  }
    71  
    72  // RemoveHandler removes handler for given event type
    73  func (d *Dispatcher) RemoveHandler(typ string, handler Handler) error {
    74  	err := validateArguments(d, typ, handler, true)
    75  
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	d.mx.Lock()
    81  
    82  	i := d.getHandlerIndex(typ, handler)
    83  
    84  	if i == -1 {
    85  		d.mx.Unlock()
    86  		return fmt.Errorf("Handler is not registered for given event type (%s)", typ)
    87  	}
    88  
    89  	copy(d.handlers[typ][i:], d.handlers[typ][i+1:])
    90  	d.handlers[typ][len(d.handlers[typ])-1] = nil
    91  	d.handlers[typ] = d.handlers[typ][:len(d.handlers[typ])-1]
    92  
    93  	d.mx.Unlock()
    94  	return nil
    95  }
    96  
    97  // HasHandler returns true if given handler is registered for given event type
    98  func (d *Dispatcher) HasHandler(typ string, handler Handler) bool {
    99  	err := validateArguments(d, typ, handler, true)
   100  
   101  	if err != nil {
   102  		return false
   103  	}
   104  
   105  	d.mx.RLock()
   106  	defer d.mx.RUnlock()
   107  
   108  	return d.getHandlerIndex(typ, handler) != -1
   109  }
   110  
   111  // Dispatch dispatches event with given type and payload
   112  func (d *Dispatcher) Dispatch(typ string, payload interface{}) error {
   113  	err := validateArguments(d, typ, nil, false)
   114  
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	d.mx.RLock()
   120  
   121  	if d.handlers[typ] == nil {
   122  		d.mx.RUnlock()
   123  		return fmt.Errorf("No handlers for event \"%s\"", typ)
   124  	}
   125  
   126  	d.mx.RUnlock()
   127  	d.mx.RLock()
   128  
   129  	for _, h := range d.handlers[typ] {
   130  		go h(payload)
   131  	}
   132  
   133  	d.mx.RUnlock()
   134  	return nil
   135  }
   136  
   137  // DispatchAndWait dispatches event with given type and payload and waits
   138  // until all handlers will be executed
   139  func (d *Dispatcher) DispatchAndWait(typ string, payload interface{}) error {
   140  	err := validateArguments(d, typ, nil, false)
   141  
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	d.mx.RLock()
   147  
   148  	if d.handlers[typ] == nil {
   149  		d.mx.RUnlock()
   150  		return fmt.Errorf("No handlers for event \"%s\"", typ)
   151  	}
   152  
   153  	d.mx.RUnlock()
   154  	d.mx.RLock()
   155  
   156  	cur, tot := 0, len(d.handlers[typ])
   157  	ch := make(chan bool, tot)
   158  
   159  	for _, h := range d.handlers[typ] {
   160  		go execWrapper(ch, h, payload)
   161  	}
   162  
   163  	d.mx.RUnlock()
   164  
   165  MAIN:
   166  	for {
   167  		select {
   168  		case <-ch:
   169  			cur++
   170  			if cur == tot {
   171  				break MAIN
   172  			}
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  // ////////////////////////////////////////////////////////////////////////////////// //
   180  
   181  // getHandlerIndex returns index of handler in the slice
   182  func (d *Dispatcher) getHandlerIndex(typ string, handler Handler) int {
   183  	hp := reflect.ValueOf(handler).Pointer()
   184  
   185  	for i, h := range d.handlers[typ] {
   186  		if reflect.ValueOf(h).Pointer() == hp {
   187  			return i
   188  		}
   189  	}
   190  
   191  	return -1
   192  }
   193  
   194  // ////////////////////////////////////////////////////////////////////////////////// //
   195  
   196  // validateArguments validates arguments
   197  func validateArguments(d *Dispatcher, typ string, handler Handler, isHandlerRequired bool) error {
   198  	if d == nil || d.handlers == nil {
   199  		return ErrNilDispatcher
   200  	}
   201  
   202  	if typ == "" {
   203  		return ErrEmptyType
   204  	}
   205  
   206  	if isHandlerRequired && handler == nil {
   207  		return ErrNilHandler
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // execWrapper exec wrapper runs given handler function and sends true to the channel
   214  // when function is successfully executed
   215  func execWrapper(ch chan bool, handler Handler, payload interface{}) {
   216  	handler(payload)
   217  	ch <- true
   218  }