Pārlūkot izejas kodu

Add telegram caller struct

tags/0.9
9seconds 7 gadus atpakaļ
vecāks
revīzija
67c1194d5b
3 mainītis faili ar 195 papildinājumiem un 0 dzēšanām
  1. 1
    0
      main.go
  2. 37
    0
      telegram/middle.go
  3. 157
    0
      telegram/middle_caller.go

+ 1
- 0
main.go Parādīt failu

@@ -16,6 +16,7 @@ import (
16 16
 
17 17
 	"github.com/9seconds/mtg/config"
18 18
 	"github.com/9seconds/mtg/proxy"
19
+	"github.com/9seconds/mtg/telegram"
19 20
 	"github.com/juju/errors"
20 21
 )
21 22
 

+ 37
- 0
telegram/middle.go Parādīt failu

@@ -0,0 +1,37 @@
1
+package telegram
2
+
3
+import (
4
+	"net"
5
+	"net/http"
6
+	"sync"
7
+
8
+	"go.uber.org/zap"
9
+
10
+	"github.com/9seconds/mtg/config"
11
+)
12
+
13
+type middleTelegram struct {
14
+	middleTelegramCaller
15
+}
16
+
17
+func NewMiddleTelegram(conf *config.Config, logger *zap.SugaredLogger) Telegram {
18
+	tg := &middleTelegram{
19
+		middleTelegramCaller: middleTelegramCaller{
20
+			baseTelegram: baseTelegram{
21
+				dialer: tgDialer{net.Dialer{Timeout: telegramDialTimeout}},
22
+			},
23
+			logger: logger,
24
+			httpClient: &http.Client{
25
+				Timeout: middleTelegramHTTPClientTimeout,
26
+			},
27
+			dialerMutex: &sync.RWMutex{},
28
+		},
29
+	}
30
+
31
+	if err := tg.update(); err != nil {
32
+		panic(err)
33
+	}
34
+	go tg.autoUpdate()
35
+
36
+	return tg
37
+}

+ 157
- 0
telegram/middle_caller.go Parādīt failu

@@ -0,0 +1,157 @@
1
+package telegram
2
+
3
+import (
4
+	"bufio"
5
+	"io"
6
+	"io/ioutil"
7
+	"net"
8
+	"net/http"
9
+	"regexp"
10
+	"strconv"
11
+	"strings"
12
+	"sync"
13
+	"time"
14
+
15
+	"github.com/juju/errors"
16
+	"go.uber.org/zap"
17
+
18
+	"github.com/9seconds/mtg/mtproto"
19
+)
20
+
21
+const (
22
+	middleTelegramAutoUpdateInterval = 6 * time.Hour
23
+	middleTelegramHTTPClientTimeout  = 30 * time.Second
24
+
25
+	tgAddrProxySecret = "https://core.telegram.org/getProxySecret"   // nolint: gas
26
+	tgAddrProxyV4     = "https://core.telegram.org/getProxyConfig"   // nolint: gas
27
+	tgAddrProxyV6     = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
28
+	tgUserAgent       = "mtg"
29
+)
30
+
31
+var middleTelegramProxyConfigSplitter *regexp.Regexp
32
+
33
+type middleTelegramCaller struct {
34
+	baseTelegram
35
+
36
+	proxySecret []byte
37
+	dialerMutex *sync.RWMutex
38
+	logger      *zap.SugaredLogger
39
+	httpClient  *http.Client
40
+}
41
+
42
+func (t *middleTelegramCaller) Dial(connOpts *mtproto.ConnectionOpts) (io.ReadWriteCloser, error) {
43
+	dc := connOpts.DC
44
+	if dc == 0 {
45
+		dc = 1
46
+	}
47
+	t.dialerMutex.RLock()
48
+	defer t.dialerMutex.RUnlock()
49
+
50
+	return t.baseTelegram.dial(dc)
51
+}
52
+
53
+func (t *middleTelegramCaller) autoUpdate() {
54
+	for range time.Tick(middleTelegramAutoUpdateInterval) {
55
+		if err := t.update(); err != nil {
56
+			t.logger.Warnw("Cannot update from Telegram", "error", err)
57
+		}
58
+	}
59
+}
60
+
61
+func (t *middleTelegramCaller) update() error {
62
+	secret, err := t.getTelegramProxySecret()
63
+	if err != nil {
64
+		return errors.Annotate(err, "Cannot get proxy secret")
65
+	}
66
+
67
+	v4Addresses, err := t.getTelegramAddresses(tgAddrProxyV4)
68
+	if err != nil {
69
+		return errors.Annotate(err, "Cannot get ipv4 addresses")
70
+	}
71
+
72
+	v6Addresses, err := t.getTelegramAddresses(tgAddrProxyV6)
73
+	if err != nil {
74
+		return errors.Annotate(err, "Cannot get ipv6 addresses")
75
+	}
76
+
77
+	t.dialerMutex.Lock()
78
+	t.proxySecret = secret
79
+	t.v4Addresses = v4Addresses
80
+	t.v6Addresses = v6Addresses
81
+	t.dialerMutex.Unlock()
82
+
83
+	t.logger.Infow("Telegram middle proxy data has been updated")
84
+
85
+	return nil
86
+}
87
+
88
+func (t *middleTelegramCaller) getTelegramProxySecret() ([]byte, error) {
89
+	resp, err := t.call(tgAddrProxySecret)
90
+	if err != nil {
91
+		return nil, errors.Annotate(err, "Cannot access telegram server")
92
+	}
93
+	defer resp.Body.Close() // nolint: errcheck
94
+
95
+	secret, err := ioutil.ReadAll(resp.Body)
96
+	if err != nil {
97
+		return nil, errors.Annotate(err, "Cannot read response")
98
+	}
99
+
100
+	return secret, nil
101
+}
102
+
103
+func (t *middleTelegramCaller) getTelegramAddresses(url string) (map[int16][]string, error) {
104
+	resp, err := t.call(url)
105
+	if err != nil {
106
+		return nil, errors.Annotate(err, "Cannot access telegram server")
107
+	}
108
+	defer resp.Body.Close()
109
+
110
+	scanner := bufio.NewScanner(resp.Body)
111
+	data := map[int16][]string{}
112
+	for scanner.Scan() {
113
+		text := strings.TrimSpace(scanner.Text())
114
+		if strings.HasPrefix(text, "#") {
115
+			continue
116
+		}
117
+
118
+		chunks := middleTelegramProxyConfigSplitter.Split(text, 3)
119
+		if len(chunks) != 3 || chunks[0] != "proxy_for" {
120
+			return nil, errors.Errorf("Incorrect config '%s'", text)
121
+		}
122
+		dcIdx64, err2 := strconv.ParseInt(chunks[1], 10, 16)
123
+		if err2 != nil {
124
+			return nil, errors.Errorf("Incorrect config '%s'", text)
125
+		}
126
+		dcIdx := int16(dcIdx64)
127
+
128
+		addr := strings.TrimRight(chunks[2], ";")
129
+		if _, _, err2 = net.SplitHostPort(addr); err != nil {
130
+			return nil, errors.Annotatef(err2, "Incorrect config '%s'", text)
131
+		}
132
+
133
+		if addresses, ok := data[dcIdx]; ok {
134
+			data[dcIdx] = append(addresses, addr)
135
+		} else {
136
+			data[dcIdx] = []string{addr}
137
+		}
138
+	}
139
+	err = scanner.Err()
140
+	if err != nil {
141
+		return nil, errors.Annotate(err, "Cannot read response from the telegram")
142
+	}
143
+
144
+	return data, nil
145
+}
146
+
147
+func (t *middleTelegramCaller) call(url string) (*http.Response, error) {
148
+	req, _ := http.NewRequest("GET", url, nil)
149
+	req.Header.Set("Accept", "text/plain")
150
+	req.Header.Set("User-Agent", tgUserAgent)
151
+
152
+	return t.httpClient.Do(req)
153
+}
154
+
155
+func init() {
156
+	middleTelegramProxyConfigSplitter = regexp.MustCompile(`\s+`)
157
+}

Notiek ielāde…
Atcelt
Saglabāt