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
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

relay.go 2.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package relay
  2. import (
  3. "context"
  4. "io"
  5. "sync"
  6. "time"
  7. )
  8. type Relay struct {
  9. ctx context.Context
  10. ctxCancel context.CancelFunc
  11. logger Logger
  12. processMutex sync.Mutex
  13. eastBuffer []byte
  14. westBuffer []byte
  15. tickChannel chan struct{}
  16. errorChannel chan error
  17. tickTimeout time.Duration
  18. }
  19. func (r *Relay) Reset() {
  20. r.processMutex.Lock()
  21. defer r.processMutex.Unlock()
  22. if r.ctxCancel != nil {
  23. r.ctxCancel()
  24. }
  25. r.ctx = nil
  26. r.ctxCancel = nil
  27. r.logger = nil
  28. }
  29. func (r *Relay) Process(eastConn, westConn io.ReadWriteCloser) error {
  30. r.processMutex.Lock()
  31. defer r.processMutex.Unlock()
  32. eastConn = conn{
  33. ReadWriteCloser: eastConn,
  34. ctx: r.ctx,
  35. tickChannel: r.tickChannel,
  36. }
  37. westConn = conn{
  38. ReadWriteCloser: westConn,
  39. ctx: r.ctx,
  40. tickChannel: r.tickChannel,
  41. }
  42. wg := &sync.WaitGroup{}
  43. wg.Add(3) // nolint: gomnd
  44. go r.runObserver(eastConn, westConn, wg)
  45. go r.transmit(eastConn, westConn, r.westBuffer, "west", wg)
  46. r.transmit(westConn, eastConn, r.eastBuffer, "east", wg)
  47. wg.Wait()
  48. select {
  49. case err := <-r.errorChannel:
  50. return err
  51. default:
  52. return nil
  53. }
  54. }
  55. func (r *Relay) transmit(src io.ReadCloser, dst io.WriteCloser,
  56. buffer []byte, direction string, wg *sync.WaitGroup) {
  57. defer func() {
  58. src.Close()
  59. dst.Close()
  60. wg.Done()
  61. r.ctxCancel()
  62. }()
  63. if _, err := io.CopyBuffer(dst, src, buffer); err != nil {
  64. r.logger.Printf("error '%v' happened on direction %s", err, direction)
  65. select {
  66. case <-r.ctx.Done():
  67. err = r.ctx.Err()
  68. default:
  69. }
  70. select {
  71. case r.errorChannel <- err:
  72. default:
  73. }
  74. }
  75. }
  76. func (r *Relay) runObserver(one, another io.Closer, wg *sync.WaitGroup) {
  77. ticker := time.NewTicker(time.Second)
  78. defer func() {
  79. one.Close()
  80. another.Close()
  81. ticker.Stop()
  82. select {
  83. case <-ticker.C:
  84. default:
  85. }
  86. wg.Done()
  87. }()
  88. lastTickAt := time.Now()
  89. for {
  90. select {
  91. case <-r.ctx.Done():
  92. return
  93. case <-r.tickChannel:
  94. lastTickAt = time.Now()
  95. case <-ticker.C:
  96. if time.Since(lastTickAt) > r.tickTimeout {
  97. r.logger.Printf("exit due to a timeout")
  98. r.ctxCancel()
  99. return
  100. }
  101. }
  102. }
  103. }