Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

event_stream.go 1.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package events
  2. import (
  3. "context"
  4. "math/rand"
  5. "runtime"
  6. "github.com/9seconds/mtg/v2/mtglib"
  7. "github.com/OneOfOne/xxhash"
  8. )
  9. type eventStream struct {
  10. ctx context.Context
  11. ctxCancel context.CancelFunc
  12. chans []chan mtglib.Event
  13. }
  14. func (e eventStream) Send(ctx context.Context, evt mtglib.Event) {
  15. var chanNo uint32
  16. streamID := evt.StreamID()
  17. if streamID == "" {
  18. chanNo = rand.Uint32()
  19. } else {
  20. chanNo = xxhash.ChecksumString32(streamID)
  21. }
  22. select {
  23. case <-ctx.Done():
  24. case <-e.ctx.Done():
  25. case e.chans[int(chanNo)%len(e.chans)] <- evt:
  26. }
  27. }
  28. func (e eventStream) Shutdown() {
  29. e.ctxCancel()
  30. }
  31. func NewEventStream(observerFactories []ObserverFactory) mtglib.EventStream {
  32. if len(observerFactories) == 0 {
  33. observerFactories = append(observerFactories, NewNoopObserver)
  34. }
  35. ctx, cancel := context.WithCancel(context.Background())
  36. rv := eventStream{
  37. ctx: ctx,
  38. ctxCancel: cancel,
  39. chans: make([]chan mtglib.Event, runtime.NumCPU()),
  40. }
  41. for i := 0; i < runtime.NumCPU(); i++ {
  42. rv.chans[i] = make(chan mtglib.Event, 1)
  43. if len(observerFactories) == 1 {
  44. go eventStreamProcessor(ctx, rv.chans[i], observerFactories[0]())
  45. } else {
  46. go eventStreamProcessor(ctx, rv.chans[i], newMultiObserver(observerFactories))
  47. }
  48. }
  49. return rv
  50. }
  51. func eventStreamProcessor(ctx context.Context, eventChan <-chan mtglib.Event, observer Observer) {
  52. defer observer.Shutdown()
  53. for {
  54. select {
  55. case <-ctx.Done():
  56. return
  57. case evt := <-eventChan:
  58. switch typedEvt := evt.(type) {
  59. case mtglib.EventStart:
  60. observer.EventStart(typedEvt)
  61. case mtglib.EventFinish:
  62. observer.EventFinish(typedEvt)
  63. case mtglib.EventConcurrencyLimited:
  64. observer.EventConcurrencyLimited(typedEvt)
  65. }
  66. }
  67. }
  68. }