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
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

conn.go 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. type Conn struct {
  10. essentials.Conn
  11. p *connPayload
  12. }
  13. type connPayload struct {
  14. ctx context.Context
  15. ctxCancel context.CancelCauseFunc
  16. clock Clock
  17. wg sync.WaitGroup
  18. writeStream bytes.Buffer
  19. writtenCond sync.Cond
  20. done bool
  21. }
  22. func (c Conn) Write(p []byte) (int, error) {
  23. if len(p) == 0 {
  24. return 0, context.Cause(c.p.ctx)
  25. }
  26. c.p.writtenCond.L.Lock()
  27. c.p.writeStream.Write(p)
  28. c.p.writtenCond.L.Unlock()
  29. c.p.writtenCond.Signal()
  30. return len(p), context.Cause(c.p.ctx)
  31. }
  32. func (c Conn) Start() {
  33. c.p.wg.Go(func() {
  34. c.start()
  35. })
  36. }
  37. func (c Conn) start() {
  38. buf := [tls.MaxRecordSize]byte{}
  39. for {
  40. select {
  41. case <-c.p.ctx.Done():
  42. return
  43. case <-c.p.clock.tick:
  44. }
  45. size := c.p.clock.stats.Size()
  46. c.p.writtenCond.L.Lock()
  47. for c.p.writeStream.Len() == 0 && !c.p.done {
  48. c.p.writtenCond.Wait()
  49. }
  50. n, _ := c.p.writeStream.Read(buf[tls.SizeHeader : tls.SizeHeader+size])
  51. c.p.writtenCond.L.Unlock()
  52. if n == 0 {
  53. continue
  54. }
  55. if err := tls.WriteRecordInPlace(c.Conn, buf[:], n); err != nil {
  56. c.p.ctxCancel(err)
  57. return
  58. }
  59. }
  60. }
  61. func (c Conn) Stop() {
  62. c.p.ctxCancel(nil)
  63. c.p.writtenCond.L.Lock()
  64. c.p.done = true
  65. c.p.writtenCond.L.Unlock()
  66. c.p.writtenCond.Broadcast()
  67. c.p.wg.Wait()
  68. }
  69. func NewConn(ctx context.Context, conn essentials.Conn, stats *Stats) Conn {
  70. ctx, cancel := context.WithCancelCause(ctx)
  71. rv := Conn{
  72. Conn: conn,
  73. p: &connPayload{
  74. ctx: ctx,
  75. ctxCancel: cancel,
  76. writtenCond: sync.Cond{
  77. L: &sync.Mutex{},
  78. },
  79. clock: Clock{
  80. stats: stats,
  81. tick: make(chan struct{}),
  82. },
  83. },
  84. }
  85. rv.p.writeStream.Grow(tls.DefaultBufferSize)
  86. rv.p.wg.Go(func() {
  87. rv.p.clock.Start(ctx)
  88. })
  89. rv.p.wg.Go(func() {
  90. rv.start()
  91. })
  92. return rv
  93. }