mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 22:24:02 +03:00
Fetch DC ips from Telegram
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
package telegram
|
||||
|
||||
import "math/rand"
|
||||
|
||||
type addressPool struct {
|
||||
v4 [][]tgAddr
|
||||
v6 [][]tgAddr
|
||||
}
|
||||
|
||||
func (a addressPool) isValidDC(dc int) bool {
|
||||
return dc > 0 && dc <= len(a.v4) && dc <= len(a.v6)
|
||||
}
|
||||
|
||||
func (a addressPool) getRandomDC() int {
|
||||
return 1 + rand.Intn(len(a.v4))
|
||||
}
|
||||
|
||||
func (a addressPool) getV4(dc int) []tgAddr {
|
||||
return a.get(a.v4, dc-1)
|
||||
}
|
||||
|
||||
func (a addressPool) getV6(dc int) []tgAddr {
|
||||
return a.get(a.v6, dc-1)
|
||||
}
|
||||
|
||||
func (a addressPool) get(addresses [][]tgAddr, dc int) []tgAddr {
|
||||
if dc < 0 || dc >= len(addresses) {
|
||||
return nil
|
||||
}
|
||||
|
||||
rv := make([]tgAddr, len(addresses[dc]))
|
||||
copy(rv, addresses[dc])
|
||||
|
||||
if len(rv) > 1 {
|
||||
rand.Shuffle(len(rv), func(i, j int) {
|
||||
rv[i], rv[j] = rv[j], rv[i]
|
||||
})
|
||||
}
|
||||
|
||||
return rv
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package telegram
|
||||
|
||||
type dcAddresses struct {
|
||||
v4 map[int][]tgAddr
|
||||
v6 map[int][]tgAddr
|
||||
}
|
||||
|
||||
func (a dcAddresses) getV4(dc int) []tgAddr {
|
||||
return a.v4[dc]
|
||||
}
|
||||
|
||||
func (a dcAddresses) getV6(dc int) []tgAddr {
|
||||
return a.v6[dc]
|
||||
}
|
||||
|
||||
func (a dcAddresses) isValidDC(dc int) bool {
|
||||
_, ok := a.v4[dc]
|
||||
return ok
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package telegram
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/v2/essentials"
|
||||
)
|
||||
@@ -18,6 +19,18 @@ const (
|
||||
preferIPPreferIPv6
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDC = 2
|
||||
defaultUpdateDCAddressesEach = time.Hour
|
||||
defaultAppID = 123456
|
||||
defaultAppHash = ""
|
||||
)
|
||||
|
||||
type loggerInterface interface {
|
||||
Info(msg string)
|
||||
WarningError(msg string, err error)
|
||||
}
|
||||
|
||||
type tgAddr struct {
|
||||
network string
|
||||
address string
|
||||
@@ -25,64 +38,41 @@ type tgAddr struct {
|
||||
|
||||
// https://github.com/telegramdesktop/tdesktop/blob/master/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp#L30
|
||||
var (
|
||||
productionV4Addresses = [][]tgAddr{
|
||||
{ // dc1
|
||||
defaultV4Addresses = map[int][]tgAddr{
|
||||
1: {
|
||||
{network: "tcp4", address: "149.154.175.50:443"},
|
||||
},
|
||||
{ // dc2
|
||||
2: {
|
||||
{network: "tcp4", address: "149.154.167.51:443"},
|
||||
{network: "tcp4", address: "95.161.76.100:443"},
|
||||
},
|
||||
{ // dc3
|
||||
3: {
|
||||
{network: "tcp4", address: "149.154.175.100:443"},
|
||||
},
|
||||
{ // dc4
|
||||
4: {
|
||||
{network: "tcp4", address: "149.154.167.91:443"},
|
||||
},
|
||||
{ // dc5
|
||||
5: {
|
||||
{network: "tcp4", address: "149.154.171.5:443"},
|
||||
},
|
||||
}
|
||||
productionV6Addresses = [][]tgAddr{
|
||||
{ // dc1
|
||||
defaultV6Addresses = map[int][]tgAddr{
|
||||
1: {
|
||||
{network: "tcp6", address: "[2001:b28:f23d:f001::a]:443"},
|
||||
},
|
||||
{ // dc2
|
||||
2: {
|
||||
{network: "tcp6", address: "[2001:67c:04e8:f002::a]:443"},
|
||||
},
|
||||
{ // dc3
|
||||
3: {
|
||||
{network: "tcp6", address: "[2001:b28:f23d:f003::a]:443"},
|
||||
},
|
||||
{ // dc4
|
||||
4: {
|
||||
{network: "tcp6", address: "[2001:67c:04e8:f004::a]:443"},
|
||||
},
|
||||
{ // dc5
|
||||
5: {
|
||||
{network: "tcp6", address: "[2001:b28:f23f:f005::a]:443"},
|
||||
},
|
||||
}
|
||||
|
||||
testV4Addresses = [][]tgAddr{
|
||||
{ // dc1
|
||||
{network: "tcp4", address: "149.154.175.10:443"},
|
||||
},
|
||||
{ // dc2
|
||||
{network: "tcp4", address: "149.154.167.40:443"},
|
||||
},
|
||||
{ // dc3
|
||||
{network: "tcp4", address: "149.154.175.117:443"},
|
||||
},
|
||||
}
|
||||
testV6Addresses = [][]tgAddr{
|
||||
{ // dc1
|
||||
{network: "tcp6", address: "[2001:b28:f23d:f001::e]:443"},
|
||||
},
|
||||
{ // dc2
|
||||
{network: "tcp6", address: "[2001:67c:04e8:f002::e]:443"},
|
||||
},
|
||||
{ // dc3
|
||||
{network: "tcp6", address: "[2001:b28:f23d:f003::e]:443"},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type Dialer interface {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/gotd/td/telegram"
|
||||
)
|
||||
|
||||
type rpcClient struct {
|
||||
*telegram.Client
|
||||
}
|
||||
|
||||
func (r rpcClient) getDCAddresses(logger loggerInterface, ctx context.Context) (dcAddresses, error) {
|
||||
addrs := dcAddresses{
|
||||
v4: map[int][]tgAddr{},
|
||||
v6: map[int][]tgAddr{},
|
||||
}
|
||||
|
||||
err := r.Client.Run(ctx, func(_ context.Context) error {
|
||||
for _, opt := range r.Client.Config().DCOptions {
|
||||
addr := net.JoinHostPort(opt.IPAddress, strconv.Itoa(opt.Port))
|
||||
|
||||
if opt.Ipv6 {
|
||||
addrs.v6[opt.ID] = append(addrs.v6[opt.ID], tgAddr{
|
||||
network: "tcp6",
|
||||
address: addr,
|
||||
})
|
||||
} else {
|
||||
addrs.v4[opt.ID] = append(addrs.v4[opt.ID], tgAddr{
|
||||
network: "tcp4",
|
||||
address: addr,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return addrs, err
|
||||
}
|
||||
@@ -4,29 +4,39 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/9seconds/mtg/v2/essentials"
|
||||
"github.com/gotd/td/telegram"
|
||||
)
|
||||
|
||||
type Telegram struct {
|
||||
dialer Dialer
|
||||
preferIP preferIP
|
||||
pool addressPool
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
lock sync.RWMutex
|
||||
|
||||
dialer Dialer
|
||||
preferIP preferIP
|
||||
addresses dcAddresses
|
||||
rpc rpcClient
|
||||
}
|
||||
|
||||
func (t Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) {
|
||||
func (t *Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) {
|
||||
var addresses []tgAddr
|
||||
|
||||
t.lock.RLock()
|
||||
switch t.preferIP {
|
||||
case preferIPOnlyIPv4:
|
||||
addresses = t.pool.getV4(dc)
|
||||
addresses = t.addresses.getV4(dc)
|
||||
case preferIPOnlyIPv6:
|
||||
addresses = t.pool.getV6(dc)
|
||||
addresses = t.addresses.getV6(dc)
|
||||
case preferIPPreferIPv4:
|
||||
addresses = append(t.pool.getV4(dc), t.pool.getV6(dc)...)
|
||||
addresses = append(t.addresses.getV4(dc), t.addresses.getV6(dc)...)
|
||||
case preferIPPreferIPv6:
|
||||
addresses = append(t.pool.getV6(dc), t.pool.getV4(dc)...)
|
||||
addresses = append(t.addresses.getV6(dc), t.addresses.getV4(dc)...)
|
||||
}
|
||||
t.lock.RUnlock()
|
||||
|
||||
var conn essentials.Conn
|
||||
|
||||
@@ -42,15 +52,60 @@ func (t Telegram) Dial(ctx context.Context, dc int) (essentials.Conn, error) {
|
||||
return nil, fmt.Errorf("cannot dial to %d dc: %w", dc, err)
|
||||
}
|
||||
|
||||
func (t Telegram) IsKnownDC(dc int) bool {
|
||||
return t.pool.isValidDC(dc)
|
||||
func (t *Telegram) IsKnownDC(dc int) bool {
|
||||
return t.addresses.isValidDC(dc)
|
||||
}
|
||||
|
||||
func (t Telegram) GetFallbackDC() int {
|
||||
return t.pool.getRandomDC()
|
||||
func (t *Telegram) GetFallbackDC() int {
|
||||
return defaultDC
|
||||
}
|
||||
|
||||
func New(dialer Dialer, ipPreference string, useTestDCs bool) (*Telegram, error) {
|
||||
func (t *Telegram) Shutdown() {
|
||||
t.ctxCancel()
|
||||
}
|
||||
|
||||
func (t *Telegram) Run(logger loggerInterface, updateEach time.Duration) {
|
||||
if updateEach == 0 {
|
||||
updateEach = defaultUpdateDCAddressesEach
|
||||
}
|
||||
|
||||
t.update(logger)
|
||||
|
||||
ticker := time.NewTicker(updateEach)
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
|
||||
select {
|
||||
case <-ticker.C:
|
||||
default:
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
t.update(logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Telegram) update(logger loggerInterface) {
|
||||
otherAddresses, err := t.rpc.getDCAddresses(logger, t.ctx)
|
||||
if err != nil {
|
||||
logger.WarningError("Cannot update DC list", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.lock.Lock()
|
||||
t.addresses = otherAddresses
|
||||
t.lock.Unlock()
|
||||
|
||||
logger.Info(fmt.Sprintf("DC are updated: %v", t.addresses))
|
||||
}
|
||||
|
||||
func New(dialer Dialer, ipPreference string) (*Telegram, error) {
|
||||
var pref preferIP
|
||||
|
||||
switch strings.ToLower(ipPreference) {
|
||||
@@ -66,18 +121,19 @@ func New(dialer Dialer, ipPreference string, useTestDCs bool) (*Telegram, error)
|
||||
return nil, fmt.Errorf("unknown ip preference %s", ipPreference)
|
||||
}
|
||||
|
||||
pool := addressPool{
|
||||
v4: productionV4Addresses,
|
||||
v6: productionV6Addresses,
|
||||
}
|
||||
if useTestDCs {
|
||||
pool.v4 = testV4Addresses
|
||||
pool.v6 = testV6Addresses
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
return &Telegram{
|
||||
dialer: dialer,
|
||||
preferIP: pref,
|
||||
pool: pool,
|
||||
ctx: ctx,
|
||||
ctxCancel: cancel,
|
||||
dialer: dialer,
|
||||
preferIP: pref,
|
||||
addresses: dcAddresses{
|
||||
v4: defaultV4Addresses,
|
||||
v6: defaultV6Addresses,
|
||||
},
|
||||
rpc: rpcClient{
|
||||
Client: telegram.NewClient(defaultAppID, defaultAppHash, telegram.Options{}),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user