Add event stream module

This commit is contained in:
9seconds
2021-03-15 21:34:53 +03:00
parent abff0cf211
commit b08d945d7c
13 changed files with 225 additions and 15 deletions
+64
View File
@@ -0,0 +1,64 @@
package events
import (
"context"
"runtime"
"github.com/9seconds/mtg/v2/mtglib"
"github.com/OneOfOne/xxhash"
)
type eventStream struct {
ctx context.Context
ctxCancel context.CancelFunc
chans []chan mtglib.Event
}
func (e eventStream) Send(ctx context.Context, evt mtglib.Event) {
chanNo := int(xxhash.ChecksumString32(evt.ConnectionID())) % len(e.chans)
select {
case <-ctx.Done():
case <-e.ctx.Done():
case e.chans[chanNo] <- evt:
}
}
func (e eventStream) Shutdown() {
e.ctxCancel()
}
func NewEventStream(observerFactories []ObserverFactory) mtglib.EventStream {
ctx, cancel := context.WithCancel(context.Background())
rv := eventStream{
ctx: ctx,
ctxCancel: cancel,
chans: make([]chan mtglib.Event, runtime.NumCPU()),
}
for i := 0; i < runtime.NumCPU(); i++ {
rv.chans[i] = make(chan mtglib.Event, 1)
go eventStreamProcessor(ctx, rv.chans[i], newMultiObserver(observerFactories))
}
return rv
}
func eventStreamProcessor(ctx context.Context, eventChan <-chan mtglib.Event, observer Observer) {
defer observer.Shutdown()
for {
select {
case <-ctx.Done():
return
case evt := <-eventChan:
switch typedEvt := evt.(type) {
case mtglib.EventStart:
observer.EventStart(typedEvt)
case mtglib.EventFinish:
observer.EventFinish(typedEvt)
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
package events
import "github.com/9seconds/mtg/v2/mtglib"
type Observer interface {
EventStart(mtglib.EventStart)
EventFinish(mtglib.EventFinish)
Shutdown()
}
type ObserverFactory func() Observer
+59
View File
@@ -0,0 +1,59 @@
package events
import (
"sync"
"github.com/9seconds/mtg/v2/mtglib"
)
type multiObserver struct {
observers []Observer
}
func (m multiObserver) EventStart(evt mtglib.EventStart) {
wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers {
go func(obs Observer) {
defer wg.Done()
obs.EventStart(evt)
}(v)
}
wg.Wait()
}
func (m multiObserver) EventFinish(evt mtglib.EventFinish) {
wg := &sync.WaitGroup{}
wg.Add(len(m.observers))
for _, v := range m.observers {
go func(obs Observer) {
defer wg.Done()
obs.EventFinish(evt)
}(v)
}
wg.Wait()
}
func (m multiObserver) Shutdown() {
for _, v := range m.observers {
v.Shutdown()
}
}
func newMultiObserver(factories []ObserverFactory) Observer {
observers := make([]Observer, len(factories))
for i, v := range factories {
observers[i] = v()
}
return multiObserver{
observers: observers,
}
}