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文字以内のものにしてください。

sync_pair.go 1.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package relay
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "net"
  8. "os"
  9. "sync"
  10. "time"
  11. )
  12. type syncPair struct {
  13. writer *bufio.Writer
  14. copyBuf []byte
  15. mutex sync.Mutex
  16. reader net.Conn
  17. }
  18. func (s *syncPair) Sync() (int64, error) {
  19. return io.CopyBuffer(s, s, s.copyBuf) // nolint: wrapcheck
  20. }
  21. func (s *syncPair) Read(p []byte) (int, error) {
  22. n, err := s.readBlocking(p, false)
  23. // nothing has been delivered for readTimeout time. Let's flush.
  24. if errors.Is(err, os.ErrDeadlineExceeded) {
  25. if err := s.Flush(); err != nil {
  26. return 0, fmt.Errorf("cannot flush writer hand-side: %w", err)
  27. }
  28. return s.readBlocking(p, true)
  29. }
  30. return n, err
  31. }
  32. func (s *syncPair) Write(p []byte) (int, error) {
  33. s.mutex.Lock()
  34. defer s.mutex.Unlock()
  35. n, err := s.writer.Write(p)
  36. // optimization for a case when we have a small package and want to avoid a
  37. // delay in readTimeout. In that case, we assume that peer has finished to
  38. // sent a data it wants to send so we can flush without waiting for anything
  39. // else.
  40. if err == nil && n < copyBufferSize {
  41. err = s.writer.Flush()
  42. }
  43. return n, err // nolint: wrapcheck
  44. }
  45. func (s *syncPair) Flush() error {
  46. s.mutex.Lock()
  47. defer s.mutex.Unlock()
  48. return s.writer.Flush() // nolint: wrapcheck
  49. }
  50. func (s *syncPair) readBlocking(p []byte, blocking bool) (int, error) {
  51. var deadline time.Time
  52. if !blocking {
  53. deadline = time.Now().Add(readTimeout)
  54. }
  55. if err := s.reader.SetReadDeadline(deadline); err != nil {
  56. return 0, fmt.Errorf("cannot set read deadline: %w", err)
  57. }
  58. return s.reader.Read(p) // nolint: wrapcheck
  59. }