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
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

telegram.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package dc
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "strconv"
  7. "strings"
  8. "sync"
  9. "time"
  10. "github.com/gotd/td/telegram"
  11. )
  12. type Telegram struct {
  13. logger Logger
  14. lock sync.RWMutex
  15. view dcView
  16. preferIP preferIP
  17. client *telegram.Client
  18. }
  19. func (t *Telegram) GetAddresses(dc int) []Addr {
  20. t.lock.RLock()
  21. defer t.lock.RUnlock()
  22. switch t.preferIP {
  23. case preferIPOnlyIPv4:
  24. return t.view.getV4(dc)
  25. case preferIPOnlyIPv6:
  26. return t.view.getV4(dc)
  27. case preferIPPreferIPv4:
  28. return append(t.view.getV4(dc), t.view.getV6(dc)...)
  29. }
  30. return append(t.view.getV6(dc), t.view.getV4(dc)...)
  31. }
  32. func (t *Telegram) Run(ctx context.Context, updateEach time.Duration) {
  33. if updateEach == 0 {
  34. updateEach = DefaultUpdateDCAddressesEach
  35. }
  36. t.update(ctx)
  37. ticker := time.NewTicker(updateEach)
  38. defer func() {
  39. ticker.Stop()
  40. select {
  41. case <-ctx.Done():
  42. case <-ticker.C:
  43. default:
  44. }
  45. }()
  46. for {
  47. select {
  48. case <-ctx.Done():
  49. return
  50. case <-ticker.C:
  51. t.update(ctx)
  52. }
  53. }
  54. }
  55. func (t *Telegram) update(ctx context.Context) {
  56. collected := dcAddrSet{
  57. v4: map[int][]Addr{},
  58. v6: map[int][]Addr{},
  59. }
  60. err := t.client.Run(ctx, func(tgctx context.Context) error {
  61. conf, err := t.client.API().HelpGetConfig(tgctx)
  62. if err != nil {
  63. return err
  64. }
  65. for _, opt := range conf.DCOptions {
  66. addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port))
  67. if opt.Ipv6 {
  68. collected.v6[opt.ID] = append(collected.v6[opt.ID], Addr{
  69. Network: "tcp6",
  70. Address: addr,
  71. })
  72. } else {
  73. collected.v4[opt.ID] = append(collected.v4[opt.ID], Addr{
  74. Network: "tcp4",
  75. Address: addr,
  76. })
  77. }
  78. }
  79. return nil
  80. })
  81. if err != nil {
  82. t.logger.WarningError("update has failed", err)
  83. return
  84. }
  85. t.lock.Lock()
  86. t.view.collected = collected
  87. t.lock.Unlock()
  88. t.logger.Info(fmt.Sprintf("updated DC list: %v", collected))
  89. }
  90. func New(logger Logger, ipPreference string, userOverrides map[int][]string) (*Telegram, error) {
  91. var pref preferIP
  92. switch strings.ToLower(ipPreference) {
  93. case "prefer-ipv4":
  94. pref = preferIPPreferIPv4
  95. case "prefer-ipv6":
  96. pref = preferIPPreferIPv6
  97. case "only-ipv4":
  98. pref = preferIPOnlyIPv4
  99. case "only-ipv6":
  100. pref = preferIPOnlyIPv6
  101. default:
  102. return nil, fmt.Errorf("unknown ip preference %s", ipPreference)
  103. }
  104. overrides := dcAddrSet{}
  105. for dc, addrs := range userOverrides {
  106. for _, addr := range addrs {
  107. host, _, err := net.SplitHostPort(addr)
  108. if err != nil {
  109. return nil, fmt.Errorf("incorrect host %s: %w", addr, err)
  110. }
  111. parsed := net.ParseIP(host)
  112. if parsed == nil {
  113. return nil, fmt.Errorf("incorrect host %s", addr)
  114. }
  115. if parsed.To4() != nil {
  116. overrides.v4[dc] = append(overrides.v4[dc], Addr{
  117. Network: "tcp4",
  118. Address: addr,
  119. })
  120. } else {
  121. overrides.v6[dc] = append(overrides.v6[dc], Addr{
  122. Network: "tcp6",
  123. Address: addr,
  124. })
  125. }
  126. }
  127. }
  128. return &Telegram{
  129. view: dcView{
  130. overrides: overrides,
  131. },
  132. logger: logger,
  133. client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}),
  134. preferIP: pref,
  135. }, nil
  136. }