瀏覽代碼

Add telegram api

tags/1.0^2
9seconds 6 年之前
父節點
當前提交
3816dbf5b1
共有 9 個文件被更改,包括 203 次插入26 次删除
  1. 24
    0
      conntypes/id.go
  2. 1
    0
      go.mod
  3. 2
    0
      go.sum
  4. 2
    1
      protocol/request.go
  5. 2
    1
      proxy/proxy.go
  6. 106
    0
      telegram/api/addresses.go
  7. 38
    0
      telegram/api/api.go
  8. 23
    0
      telegram/api/secret.go
  9. 5
    24
      wrappers/wrapper_conn.go

+ 24
- 0
conntypes/id.go 查看文件

@@ -0,0 +1,24 @@
1
+package conntypes
2
+
3
+import (
4
+	"crypto/rand"
5
+	"encoding/hex"
6
+)
7
+
8
+const ConnIDLength = 8
9
+
10
+type ConnID [ConnIDLength]byte
11
+
12
+func (c ConnID) String() string {
13
+	return hex.EncodeToString(c[:])
14
+}
15
+
16
+func NewConnID() ConnID {
17
+	var id ConnID
18
+
19
+	if _, err := rand.Read(id[:]); err != nil {
20
+		panic(err)
21
+	}
22
+
23
+	return id
24
+}

+ 1
- 0
go.mod 查看文件

@@ -9,6 +9,7 @@ require (
9 9
 	github.com/allegro/bigcache v1.2.1
10 10
 	github.com/beevik/ntp v0.2.0
11 11
 	github.com/cespare/xxhash v1.1.0
12
+	github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d
12 13
 	github.com/kr/pretty v0.1.0 // indirect
13 14
 	github.com/pkg/errors v0.8.1 // indirect
14 15
 	github.com/prometheus/client_golang v1.1.0

+ 2
- 0
go.sum 查看文件

@@ -40,6 +40,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
40 40
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
41 41
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
42 42
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
43
+github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d h1:hJXjZMxj0SWlMoQkzeZDLi2cmeiWKa7y1B8Rg+qaoEc=
44
+github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
43 45
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
44 46
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
45 47
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=

+ 2
- 1
protocol/request.go 查看文件

@@ -5,13 +5,14 @@ import (
5 5
 
6 6
 	"go.uber.org/zap"
7 7
 
8
+	"github.com/9seconds/mtg/conntypes"
8 9
 	"github.com/9seconds/mtg/wrappers"
9 10
 )
10 11
 
11 12
 type TelegramRequest struct {
12 13
 	Logger         *zap.SugaredLogger
13 14
 	ClientConn     wrappers.StreamReadWriteCloser
14
-	ConnID         wrappers.ConnID
15
+	ConnID         conntypes.ConnID
15 16
 	Ctx            context.Context
16 17
 	Cancel         context.CancelFunc
17 18
 	ClientProtocol ClientProtocol

+ 2
- 1
proxy/proxy.go 查看文件

@@ -9,6 +9,7 @@ import (
9 9
 	"go.uber.org/zap"
10 10
 
11 11
 	"github.com/9seconds/mtg/config"
12
+	"github.com/9seconds/mtg/conntypes"
12 13
 	"github.com/9seconds/mtg/protocol"
13 14
 	"github.com/9seconds/mtg/stats"
14 15
 	"github.com/9seconds/mtg/telegram"
@@ -53,7 +54,7 @@ func (p *Proxy) accept(conn net.Conn) {
53 54
 		}
54 55
 	}()
55 56
 
56
-	connID := wrappers.NewConnID()
57
+	connID := conntypes.NewConnID()
57 58
 	logger := p.Logger.With("connection_id", connID)
58 59
 
59 60
 	if err := utils.InitTCP(conn); err != nil {

+ 106
- 0
telegram/api/addresses.go 查看文件

@@ -0,0 +1,106 @@
1
+package api
2
+
3
+import (
4
+	"bufio"
5
+	"fmt"
6
+	"net"
7
+	"regexp"
8
+	"strconv"
9
+	"strings"
10
+
11
+	"github.com/9seconds/mtg/conntypes"
12
+)
13
+
14
+const (
15
+	addressesURLV4 = "https://core.telegram.org/getProxyConfig"   // nolint: gas
16
+	addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
17
+)
18
+
19
+var addressesProxyForSplitter = regexp.MustCompile(`\s+`)
20
+
21
+func AddressesV4() (map[conntypes.DC][]string, conntypes.DC, error) {
22
+	return getAddresses(addressesURLV4)
23
+}
24
+
25
+func AddressesV6() (map[conntypes.DC][]string, conntypes.DC, error) {
26
+	return getAddresses(addressesURLV6)
27
+}
28
+
29
+func getAddresses(url string) (map[conntypes.DC][]string, conntypes.DC, error) {
30
+	resp, err := request(url)
31
+	if err != nil {
32
+		return nil, 0, fmt.Errorf("cannot get http response: %w", err)
33
+	}
34
+	defer resp.Close()
35
+
36
+	scanner := bufio.NewScanner(resp)
37
+	data := map[conntypes.DC][]string{}
38
+
39
+	var defaultDC = conntypes.DCDefaultIdx
40
+	for scanner.Scan() {
41
+		text := strings.TrimSpace(scanner.Text())
42
+		switch {
43
+		case strings.HasPrefix(text, "#"):
44
+			continue
45
+
46
+		case strings.HasPrefix(text, "proxy_for"):
47
+			addr, idx, err := addressesParseProxyFor(text)
48
+			if err != nil {
49
+				return nil, 0, fmt.Errorf("cannot parse 'proxy_for' section: %w", err)
50
+			}
51
+			if addresses, ok := data[idx]; ok {
52
+				data[idx] = append(addresses, addr)
53
+			} else {
54
+				data[idx] = []string{addr}
55
+			}
56
+
57
+		case strings.HasPrefix(text, "default"):
58
+			idx, err := addressesParseDefault(text)
59
+			if err != nil {
60
+				return nil, 0, fmt.Errorf("cannot parse 'default' section: %w", err)
61
+			}
62
+			defaultDC = idx
63
+		}
64
+	}
65
+
66
+	err = scanner.Err()
67
+	if err != nil {
68
+		return nil, 0, fmt.Errorf("cannot parse http response: %w", err)
69
+	}
70
+
71
+	return data, defaultDC, nil
72
+}
73
+
74
+func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
75
+	chunks := addressesProxyForSplitter.Split(text, 3)
76
+	if len(chunks) != 3 || chunks[0] != "proxy_for" {
77
+		return "", 0, fmt.Errorf("incorrect config %s", text)
78
+	}
79
+
80
+	dc, err := strconv.ParseInt(chunks[1], 10, 16)
81
+	if err != nil {
82
+		return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
83
+	}
84
+
85
+	addr := strings.TrimRight(chunks[2], ";")
86
+	if _, _, err = net.SplitHostPort(addr); err != nil {
87
+		return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
88
+	}
89
+
90
+	return addr, conntypes.DC(dc), nil
91
+}
92
+
93
+func addressesParseDefault(text string) (conntypes.DC, error) {
94
+	chunks := addressesProxyForSplitter.Split(text, 2)
95
+	if len(chunks) != 2 || chunks[0] != "default" {
96
+		return 0, fmt.Errorf("incorrect config '%s'", text)
97
+	}
98
+
99
+	dcString := strings.TrimRight(chunks[1], ";")
100
+	dc, err := strconv.ParseInt(dcString, 10, 16)
101
+	if err != nil {
102
+		return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
103
+	}
104
+
105
+	return conntypes.DC(dc), nil
106
+}

+ 38
- 0
telegram/api/api.go 查看文件

@@ -0,0 +1,38 @@
1
+package api
2
+
3
+import (
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"net/http"
8
+	"time"
9
+)
10
+
11
+const (
12
+	apiUserAgent   = "mtg"
13
+	apiHTTPTimeout = 30 * time.Second
14
+)
15
+
16
+var httpClient = http.Client{
17
+	Timeout: apiHTTPTimeout,
18
+}
19
+
20
+func request(url string) (io.ReadCloser, error) {
21
+	req, err := http.NewRequest("GET", url, nil)
22
+	if err != nil {
23
+		panic(err)
24
+	}
25
+	req.Header.Set("Accept", "text/plan")
26
+	req.Header.Set("User-Agent", apiUserAgent)
27
+
28
+	resp, err := httpClient.Do(req)
29
+	if err != nil {
30
+		if resp != nil {
31
+			io.Copy(ioutil.Discard, resp.Body)
32
+			resp.Body.Close()
33
+		}
34
+		return nil, fmt.Errorf("cannot perform a request: %w", err)
35
+	}
36
+
37
+	return resp.Body, err
38
+}

+ 23
- 0
telegram/api/secret.go 查看文件

@@ -0,0 +1,23 @@
1
+package api
2
+
3
+import (
4
+	"fmt"
5
+	"io/ioutil"
6
+)
7
+
8
+const secretURL = "https://core.telegram.org/getProxySecret" // nolint: gas
9
+
10
+func Secret() ([]byte, error) {
11
+	resp, err := request(secretURL)
12
+	if err != nil {
13
+		return nil, fmt.Errorf("cannot access telegram server: %w", err)
14
+	}
15
+	defer resp.Close()
16
+
17
+	secret, err := ioutil.ReadAll(resp)
18
+	if err != nil {
19
+		return nil, fmt.Errorf("cannot read response: %w", err)
20
+	}
21
+
22
+	return secret, nil
23
+}

+ 5
- 24
wrappers/wrapper_conn.go 查看文件

@@ -2,8 +2,6 @@ package wrappers
2 2
 
3 3
 import (
4 4
 	"context"
5
-	"crypto/rand"
6
-	"encoding/hex"
7 5
 	"fmt"
8 6
 	"net"
9 7
 	"time"
@@ -11,16 +9,9 @@ import (
11 9
 	"go.uber.org/zap"
12 10
 
13 11
 	"github.com/9seconds/mtg/config"
12
+	"github.com/9seconds/mtg/conntypes"
14 13
 )
15 14
 
16
-const ConnIDLength = 8
17
-
18
-type ConnID [ConnIDLength]byte
19
-
20
-func (c ConnID) String() string {
21
-	return hex.EncodeToString(c[:])
22
-}
23
-
24 15
 type connPurpose uint8
25 16
 
26 17
 const (
@@ -37,7 +28,7 @@ type wrapperConn struct {
37 28
 	parent     net.Conn
38 29
 	ctx        context.Context
39 30
 	cancel     context.CancelFunc
40
-	connID     ConnID
31
+	connID     conntypes.ConnID
41 32
 	logger     *zap.SugaredLogger
42 33
 	localAddr  *net.TCPAddr
43 34
 	remoteAddr *net.TCPAddr
@@ -121,7 +112,7 @@ func (w *wrapperConn) RemoteAddr() *net.TCPAddr {
121 112
 func newConn(ctx context.Context,
122 113
 	cancel context.CancelFunc,
123 114
 	parent net.Conn,
124
-	connID ConnID,
115
+	connID conntypes.ConnID,
125 116
 	purpose connPurpose) StreamReadWriteCloser {
126 117
 	localAddr := *parent.LocalAddr().(*net.TCPAddr)
127 118
 
@@ -156,22 +147,12 @@ func newConn(ctx context.Context,
156 147
 func NewClientConn(ctx context.Context,
157 148
 	cancel context.CancelFunc,
158 149
 	parent net.Conn,
159
-	connID ConnID) StreamReadWriteCloser {
150
+	connID conntypes.ConnID) StreamReadWriteCloser {
160 151
 	return newConn(ctx, cancel, parent, connID, connPurposeClient)
161 152
 }
162 153
 
163 154
 func NewTelegramConn(ctx context.Context,
164 155
 	cancel context.CancelFunc,
165 156
 	parent net.Conn) StreamReadWriteCloser {
166
-	return newConn(ctx, cancel, parent, ConnID{}, connPurposeTelegram)
167
-}
168
-
169
-func NewConnID() ConnID {
170
-	var id ConnID
171
-
172
-	if _, err := rand.Read(id[:]); err != nil {
173
-		panic(err)
174
-	}
175
-
176
-	return id
157
+	return newConn(ctx, cancel, parent, conntypes.ConnID{}, connPurposeTelegram)
177 158
 }

Loading…
取消
儲存