github.com/quantosnetwork/Quantos@v0.0.0-20220306172517-e20b28c5a29a/events/listener.go (about)

     1  package events
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/fsnotify/fsnotify"
     6  	"github.com/quantosnetwork/Quantos/events/set"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  // Listener is the function type to run on events.
    12  type Listener func(interface{})
    13  
    14  type Subscribers map[string]Listener
    15  
    16  type Observer struct {
    17  	quit           chan bool
    18  	events         chan *Event
    19  	watcher        *fsnotify.Watcher
    20  	watchPatterns  set.Set
    21  	watchDirs      set.Set
    22  	listeners      []Listener
    23  	mutex          *sync.Mutex
    24  	bufferEvents   []*Event
    25  	bufferDuration time.Duration
    26  	Verbose        bool
    27  }
    28  
    29  // Open the observer channles and run the event loop,
    30  // it will return an error if event loop already running.
    31  func (o *Observer) Open() error {
    32  	// Check for mutex
    33  	if o.mutex == nil {
    34  		o.mutex = &sync.Mutex{}
    35  	}
    36  
    37  	if o.events != nil {
    38  		return fmt.Errorf("Observer already inititated.")
    39  	}
    40  
    41  	// Create the observer channels.
    42  	o.quit = make(chan bool)
    43  	o.events = make(chan *Event)
    44  
    45  	// Run the observer.
    46  	return o.eventLoop()
    47  }
    48  
    49  // Close the observer channles,
    50  // it will return an error if close fails.
    51  func (o *Observer) Close() error {
    52  	// Close event loop
    53  	if o.events != nil {
    54  		// Send a quit signal.
    55  		o.quit <- true
    56  
    57  		// Close channels.
    58  		close(o.quit)
    59  		close(o.events)
    60  	}
    61  
    62  	// Close file watcher.
    63  	if o.watcher != nil {
    64  		o.watcher.Close()
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // AddListener adds a listener function to run on event,
    71  // the listener function will recive the event object as argument.
    72  func (o *Observer) AddListener(l Listener) {
    73  	// Check for mutex
    74  	if o.mutex == nil {
    75  		o.mutex = &sync.Mutex{}
    76  	}
    77  
    78  	// Lock:
    79  	// 1. operations on array listeners
    80  	o.mutex.Lock()
    81  	defer o.mutex.Unlock()
    82  
    83  	o.listeners = append(o.listeners, l)
    84  }
    85  
    86  // Emit an event, and event can be of any type, when event is triggered all
    87  // listeners will be called using the event object.
    88  func (o *Observer) Emit(event *Event) {
    89  	o.events <- event
    90  }
    91  
    92  // eventLoop runs the event loop.
    93  func (o *Observer) eventLoop() error {
    94  	// Run observer.
    95  	go func() {
    96  		for {
    97  			select {
    98  			case event := <-o.events:
    99  				o.handleEvent(event)
   100  			case <-o.quit:
   101  				return
   102  			}
   103  		}
   104  	}()
   105  
   106  	return nil
   107  }
   108  
   109  func (o *Observer) handleEvent(event *Event) {
   110  	o.mutex.Lock()
   111  	defer o.mutex.Unlock()
   112  	// If we do not buffer events, just send this event now.
   113  	if o.bufferDuration == 0 {
   114  		o.sendEvent(event)
   115  		return
   116  	}
   117  	o.bufferEvents = append(o.bufferEvents, event)
   118  	// If this is the first event, set a timeout function.
   119  	if len(o.bufferEvents) == 1 {
   120  		time.AfterFunc(o.bufferDuration, func() {
   121  			// Lock:
   122  			// 1. operations on listeners array (sendEvent).
   123  			// 2. operations on bufferEvents array.
   124  			o.mutex.Lock()
   125  			defer o.mutex.Unlock()
   126  
   127  			// Send all events in event buffer.
   128  			for i := range o.bufferEvents {
   129  				o.sendEvent(o.bufferEvents[i])
   130  			}
   131  
   132  			// Reset events buffer.
   133  			o.bufferEvents = make([]*Event, 0)
   134  		})
   135  	}
   136  }
   137  
   138  var listeners Subscribers
   139  
   140  func (o *Observer) sendEvent(event *Event) {
   141  	if event.Subscribable() {
   142  		subscribers := event.subscribers
   143  		for s := range subscribers {
   144  			go listeners[s](event)
   145  		}
   146  	}
   147  }