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 }