github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cdp/events/loop.go (about)

     1  package events
     2  
     3  import (
     4  	"context"
     5  	"math/rand"
     6  	"sync"
     7  )
     8  
     9  type Loop struct {
    10  	mu        sync.RWMutex
    11  	sources   []SourceFactory
    12  	listeners map[ID]map[ListenerID]Listener
    13  }
    14  
    15  func NewLoop(sources ...SourceFactory) *Loop {
    16  	loop := new(Loop)
    17  	loop.listeners = make(map[ID]map[ListenerID]Listener)
    18  	loop.sources = sources
    19  
    20  	return loop
    21  }
    22  
    23  func (loop *Loop) Run(ctx context.Context) error {
    24  	var err error
    25  	sources := make([]Source, 0, len(loop.sources))
    26  
    27  	// create new sources
    28  	for _, factory := range loop.sources {
    29  		src, e := factory(ctx)
    30  
    31  		if e != nil {
    32  			err = e
    33  
    34  			break
    35  		}
    36  
    37  		sources = append(sources, src)
    38  	}
    39  
    40  	// if error occurred
    41  	if err != nil {
    42  		// clean up the open ones
    43  		for _, src := range sources {
    44  			src.Close()
    45  		}
    46  
    47  		return err
    48  	}
    49  
    50  	for _, src := range sources {
    51  		loop.consume(ctx, src)
    52  	}
    53  
    54  	return nil
    55  }
    56  
    57  func (loop *Loop) Listeners(eventID ID) int {
    58  	loop.mu.RLock()
    59  	defer loop.mu.RUnlock()
    60  
    61  	bucket, exists := loop.listeners[eventID]
    62  
    63  	if !exists {
    64  		return 0
    65  	}
    66  
    67  	return len(bucket)
    68  }
    69  
    70  func (loop *Loop) AddListener(eventID ID, handler Handler) ListenerID {
    71  	loop.mu.RLock()
    72  	defer loop.mu.RUnlock()
    73  
    74  	listener := Listener{
    75  		ID:      ListenerID(rand.Int()),
    76  		EventID: eventID,
    77  		Handler: handler,
    78  	}
    79  
    80  	bucket, exists := loop.listeners[listener.EventID]
    81  
    82  	if !exists {
    83  		bucket = make(map[ListenerID]Listener)
    84  		loop.listeners[listener.EventID] = bucket
    85  	}
    86  
    87  	bucket[listener.ID] = listener
    88  
    89  	return listener.ID
    90  }
    91  
    92  func (loop *Loop) RemoveListener(eventID ID, listenerID ListenerID) {
    93  	loop.mu.RLock()
    94  	defer loop.mu.RUnlock()
    95  
    96  	bucket, exists := loop.listeners[eventID]
    97  
    98  	if !exists {
    99  		return
   100  	}
   101  
   102  	delete(bucket, listenerID)
   103  }
   104  
   105  func (loop *Loop) consume(ctx context.Context, src Source) {
   106  	go func() {
   107  		defer func() {
   108  			if err := src.Close(); err != nil {
   109  				loop.emit(ctx, Error, err)
   110  			}
   111  		}()
   112  
   113  		for {
   114  			select {
   115  			case <-ctx.Done():
   116  				return
   117  			case <-src.Ready():
   118  				if ctx.Err() != nil {
   119  					return
   120  				}
   121  
   122  				event, err := src.Recv()
   123  
   124  				if err != nil {
   125  					loop.emit(ctx, Error, err)
   126  
   127  					return
   128  				}
   129  
   130  				loop.emit(ctx, event.ID, event.Data)
   131  			}
   132  		}
   133  	}()
   134  }
   135  
   136  func (loop *Loop) emit(ctx context.Context, eventID ID, message interface{}) {
   137  	loop.mu.Lock()
   138  
   139  	var snapshot []Listener
   140  	listeners, exist := loop.listeners[eventID]
   141  
   142  	if exist {
   143  		snapshot = make([]Listener, 0, len(listeners))
   144  
   145  		for _, listener := range listeners {
   146  			snapshot = append(snapshot, listener)
   147  		}
   148  	}
   149  
   150  	loop.mu.Unlock()
   151  
   152  	for _, listener := range snapshot {
   153  		if ctx.Err() != nil {
   154  			return
   155  		}
   156  
   157  		// if returned false,
   158  		// the handler must be removed after the call
   159  		if !listener.Handler(ctx, message) {
   160  			loop.mu.Lock()
   161  			delete(loop.listeners[eventID], listener.ID)
   162  			loop.mu.Unlock()
   163  		}
   164  	}
   165  }