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 1.9KB

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