mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 14:54:01 +03:00
Add event stream module
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user