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
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

conn.go 2.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. package doppel
  2. import (
  3. "bytes"
  4. "context"
  5. "sync"
  6. "github.com/9seconds/mtg/v2/essentials"
  7. "github.com/9seconds/mtg/v2/mtglib/internal/tls"
  8. )
  9. var doppelBufPool = sync.Pool{
  10. New: func() any {
  11. b := make([]byte, tls.MaxRecordSize)
  12. return &b
  13. },
  14. }
  15. type Conn struct {
  16. essentials.Conn
  17. p *connPayload
  18. }
  19. type connPayload struct {
  20. ctx context.Context
  21. ctxCancel context.CancelCauseFunc
  22. clock Clock
  23. wg sync.WaitGroup
  24. writeStream bytes.Buffer
  25. writtenCond sync.Cond
  26. done bool
  27. }
  28. func (c Conn) Write(p []byte) (int, error) {
  29. if len(p) == 0 {
  30. return 0, context.Cause(c.p.ctx)
  31. }
  32. c.p.writtenCond.L.Lock()
  33. c.p.writeStream.Write(p)
  34. c.p.writtenCond.L.Unlock()
  35. c.p.writtenCond.Signal()
  36. return len(p), context.Cause(c.p.ctx)
  37. }
  38. func (c Conn) Start() {
  39. c.p.wg.Go(func() {
  40. c.start()
  41. })
  42. }
  43. func (c Conn) start() {
  44. bp := doppelBufPool.Get().(*[]byte)
  45. buf := *bp
  46. defer doppelBufPool.Put(bp)
  47. for {
  48. select {
  49. case <-c.p.ctx.Done():
  50. return
  51. case <-c.p.clock.tick:
  52. }
  53. size := c.p.clock.stats.Size()
  54. c.p.writtenCond.L.Lock()
  55. for c.p.writeStream.Len() == 0 && !c.p.done {
  56. c.p.writtenCond.Wait()
  57. }
  58. n, _ := c.p.writeStream.Read(buf[tls.SizeHeader : tls.SizeHeader+size])
  59. c.p.writtenCond.L.Unlock()
  60. if n == 0 {
  61. continue
  62. }
  63. if err := tls.WriteRecordInPlace(c.Conn, buf, n); err != nil {
  64. c.p.ctxCancel(err)
  65. return
  66. }
  67. }
  68. }
  69. func (c Conn) Stop() {
  70. c.p.ctxCancel(nil)
  71. c.p.writtenCond.L.Lock()
  72. c.p.done = true
  73. c.p.writtenCond.L.Unlock()
  74. c.p.writtenCond.Broadcast()
  75. c.p.wg.Wait()
  76. }
  77. func NewConn(ctx context.Context, conn essentials.Conn, stats *Stats) Conn {
  78. ctx, cancel := context.WithCancelCause(ctx)
  79. rv := Conn{
  80. Conn: conn,
  81. p: &connPayload{
  82. ctx: ctx,
  83. ctxCancel: cancel,
  84. writtenCond: sync.Cond{
  85. L: &sync.Mutex{},
  86. },
  87. clock: Clock{
  88. stats: stats,
  89. tick: make(chan struct{}),
  90. },
  91. },
  92. }
  93. rv.p.writeStream.Grow(tls.DefaultBufferSize)
  94. rv.p.wg.Go(func() {
  95. rv.p.clock.Start(ctx)
  96. })
  97. rv.p.wg.Go(func() {
  98. rv.start()
  99. })
  100. return rv
  101. }