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
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ganger.go 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package doppel
  2. import (
  3. "context"
  4. "sync"
  5. "time"
  6. "github.com/9seconds/mtg/v2/essentials"
  7. )
  8. const (
  9. DoppelGangerMaxDurations = 4096
  10. DoppelGangerScoutRaidEach = 6 * time.Hour
  11. DoppelGangerScoutRepeats = 10
  12. )
  13. type gangerConnRequest struct {
  14. ret chan<- Conn
  15. payload essentials.Conn
  16. }
  17. type Ganger struct {
  18. ctx context.Context
  19. ctxCancel context.CancelFunc
  20. logger Logger
  21. wg sync.WaitGroup
  22. scout Scout
  23. scoutRaidEach time.Duration
  24. scoutRaidRepeats int
  25. drs bool
  26. stats *Stats
  27. durations []time.Duration
  28. connRequests chan gangerConnRequest
  29. }
  30. func (g *Ganger) Shutdown() {
  31. g.ctxCancel()
  32. g.wg.Wait()
  33. }
  34. func (g *Ganger) Run() {
  35. g.wg.Go(func() {
  36. g.run()
  37. })
  38. }
  39. func (g *Ganger) NewConn(conn essentials.Conn) (Conn, error) {
  40. rvChan := make(chan Conn)
  41. req := gangerConnRequest{
  42. ret: rvChan,
  43. payload: conn,
  44. }
  45. defer close(req.ret)
  46. select {
  47. case <-g.ctx.Done():
  48. return Conn{}, context.Cause(g.ctx)
  49. case g.connRequests <- req:
  50. }
  51. select {
  52. case <-g.ctx.Done():
  53. return Conn{}, context.Cause(g.ctx)
  54. case conn := <-rvChan:
  55. return conn, nil
  56. }
  57. }
  58. func (g *Ganger) run() {
  59. scoutTicker := time.NewTicker(g.scoutRaidEach)
  60. defer func() {
  61. scoutTicker.Stop()
  62. select {
  63. case <-scoutTicker.C:
  64. default:
  65. }
  66. }()
  67. scoutCollectedChan := make(chan []time.Duration)
  68. currentScoutCollectedChan := scoutCollectedChan
  69. updatedStatsChan := make(chan *Stats)
  70. g.wg.Go(func() {
  71. g.runScoutRaid(scoutCollectedChan)
  72. })
  73. for {
  74. select {
  75. case <-g.ctx.Done():
  76. return
  77. case durations := <-currentScoutCollectedChan:
  78. g.durations = append(g.durations, durations...)
  79. if len(g.durations) > DoppelGangerMaxDurations {
  80. copy(g.durations, g.durations[len(g.durations)-DoppelGangerMaxDurations:])
  81. g.durations = g.durations[:DoppelGangerMaxDurations]
  82. }
  83. if len(g.durations) < MinDurationsToCalculate {
  84. continue
  85. }
  86. currentScoutCollectedChan = nil
  87. g.wg.Go(func() {
  88. select {
  89. case <-g.ctx.Done():
  90. case updatedStatsChan <- NewStats(durations, g.drs):
  91. }
  92. })
  93. case stats := <-updatedStatsChan:
  94. g.stats = stats
  95. currentScoutCollectedChan = scoutCollectedChan
  96. case <-scoutTicker.C:
  97. g.wg.Go(func() {
  98. g.runScoutRaid(scoutCollectedChan)
  99. })
  100. case req := <-g.connRequests:
  101. select {
  102. case <-g.ctx.Done():
  103. case req.ret <- NewConn(g.ctx, req.payload, g.stats):
  104. }
  105. }
  106. }
  107. }
  108. func (g *Ganger) runScoutRaid(rvChan chan<- []time.Duration) {
  109. durations := []time.Duration{}
  110. for range g.scoutRaidRepeats {
  111. learned, err := g.scout.Learn(g.ctx)
  112. if err != nil {
  113. g.logger.WarningError("cannot learn", err)
  114. continue
  115. }
  116. durations = append(durations, learned...)
  117. }
  118. select {
  119. case <-g.ctx.Done():
  120. return
  121. case rvChan <- durations:
  122. }
  123. }
  124. func NewGanger(
  125. ctx context.Context,
  126. network Network,
  127. logger Logger,
  128. scoutEach time.Duration,
  129. scoutRepeats int,
  130. urls []string,
  131. drs bool,
  132. ) *Ganger {
  133. ctx, cancel := context.WithCancel(ctx)
  134. if scoutEach == 0 {
  135. scoutEach = DoppelGangerScoutRaidEach
  136. }
  137. if scoutRepeats == 0 {
  138. scoutRepeats = DoppelGangerScoutRepeats
  139. }
  140. return &Ganger{
  141. ctx: ctx,
  142. ctxCancel: cancel,
  143. logger: logger,
  144. scoutRaidEach: scoutEach,
  145. scoutRaidRepeats: scoutRepeats,
  146. drs: drs,
  147. stats: &Stats{
  148. k: StatsDefaultK,
  149. lambda: StatsDefaultLambda,
  150. drs: drs,
  151. },
  152. scout: NewScout(network, urls),
  153. connRequests: make(chan gangerConnRequest),
  154. }
  155. }