mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-02 00:11:56 +03:00
Add telegram api
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
package conntypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ConnIDLength = 8
|
||||||
|
|
||||||
|
type ConnID [ConnIDLength]byte
|
||||||
|
|
||||||
|
func (c ConnID) String() string {
|
||||||
|
return hex.EncodeToString(c[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnID() ConnID {
|
||||||
|
var id ConnID
|
||||||
|
|
||||||
|
if _, err := rand.Read(id[:]); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ require (
|
|||||||
github.com/allegro/bigcache v1.2.1
|
github.com/allegro/bigcache v1.2.1
|
||||||
github.com/beevik/ntp v0.2.0
|
github.com/beevik/ntp v0.2.0
|
||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
|
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.1.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1 // indirect
|
github.com/pkg/errors v0.8.1 // indirect
|
||||||
github.com/prometheus/client_golang v1.1.0
|
github.com/prometheus/client_golang v1.1.0
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d h1:hJXjZMxj0SWlMoQkzeZDLi2cmeiWKa7y1B8Rg+qaoEc=
|
||||||
|
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
|||||||
+2
-1
@@ -5,13 +5,14 @@ import (
|
|||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
"github.com/9seconds/mtg/wrappers"
|
"github.com/9seconds/mtg/wrappers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TelegramRequest struct {
|
type TelegramRequest struct {
|
||||||
Logger *zap.SugaredLogger
|
Logger *zap.SugaredLogger
|
||||||
ClientConn wrappers.StreamReadWriteCloser
|
ClientConn wrappers.StreamReadWriteCloser
|
||||||
ConnID wrappers.ConnID
|
ConnID conntypes.ConnID
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
Cancel context.CancelFunc
|
Cancel context.CancelFunc
|
||||||
ClientProtocol ClientProtocol
|
ClientProtocol ClientProtocol
|
||||||
|
|||||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/config"
|
"github.com/9seconds/mtg/config"
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
"github.com/9seconds/mtg/protocol"
|
"github.com/9seconds/mtg/protocol"
|
||||||
"github.com/9seconds/mtg/stats"
|
"github.com/9seconds/mtg/stats"
|
||||||
"github.com/9seconds/mtg/telegram"
|
"github.com/9seconds/mtg/telegram"
|
||||||
@@ -53,7 +54,7 @@ func (p *Proxy) accept(conn net.Conn) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
connID := wrappers.NewConnID()
|
connID := conntypes.NewConnID()
|
||||||
logger := p.Logger.With("connection_id", connID)
|
logger := p.Logger.With("connection_id", connID)
|
||||||
|
|
||||||
if err := utils.InitTCP(conn); err != nil {
|
if err := utils.InitTCP(conn); err != nil {
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
addressesURLV4 = "https://core.telegram.org/getProxyConfig" // nolint: gas
|
||||||
|
addressesURLV6 = "https://core.telegram.org/getProxyConfigV6" // nolint: gas
|
||||||
|
)
|
||||||
|
|
||||||
|
var addressesProxyForSplitter = regexp.MustCompile(`\s+`)
|
||||||
|
|
||||||
|
func AddressesV4() (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||||
|
return getAddresses(addressesURLV4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddressesV6() (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||||
|
return getAddresses(addressesURLV6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAddresses(url string) (map[conntypes.DC][]string, conntypes.DC, error) {
|
||||||
|
resp, err := request(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("cannot get http response: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(resp)
|
||||||
|
data := map[conntypes.DC][]string{}
|
||||||
|
|
||||||
|
var defaultDC = conntypes.DCDefaultIdx
|
||||||
|
for scanner.Scan() {
|
||||||
|
text := strings.TrimSpace(scanner.Text())
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(text, "#"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
case strings.HasPrefix(text, "proxy_for"):
|
||||||
|
addr, idx, err := addressesParseProxyFor(text)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("cannot parse 'proxy_for' section: %w", err)
|
||||||
|
}
|
||||||
|
if addresses, ok := data[idx]; ok {
|
||||||
|
data[idx] = append(addresses, addr)
|
||||||
|
} else {
|
||||||
|
data[idx] = []string{addr}
|
||||||
|
}
|
||||||
|
|
||||||
|
case strings.HasPrefix(text, "default"):
|
||||||
|
idx, err := addressesParseDefault(text)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("cannot parse 'default' section: %w", err)
|
||||||
|
}
|
||||||
|
defaultDC = idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = scanner.Err()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("cannot parse http response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, defaultDC, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addressesParseProxyFor(text string) (string, conntypes.DC, error) {
|
||||||
|
chunks := addressesProxyForSplitter.Split(text, 3)
|
||||||
|
if len(chunks) != 3 || chunks[0] != "proxy_for" {
|
||||||
|
return "", 0, fmt.Errorf("incorrect config %s", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
dc, err := strconv.ParseInt(chunks[1], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := strings.TrimRight(chunks[2], ";")
|
||||||
|
if _, _, err = net.SplitHostPort(addr); err != nil {
|
||||||
|
return "", 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr, conntypes.DC(dc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addressesParseDefault(text string) (conntypes.DC, error) {
|
||||||
|
chunks := addressesProxyForSplitter.Split(text, 2)
|
||||||
|
if len(chunks) != 2 || chunks[0] != "default" {
|
||||||
|
return 0, fmt.Errorf("incorrect config '%s'", text)
|
||||||
|
}
|
||||||
|
|
||||||
|
dcString := strings.TrimRight(chunks[1], ";")
|
||||||
|
dc, err := strconv.ParseInt(dcString, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("incorrect config '%s': %w", text, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conntypes.DC(dc), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiUserAgent = "mtg"
|
||||||
|
apiHTTPTimeout = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
var httpClient = http.Client{
|
||||||
|
Timeout: apiHTTPTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
func request(url string) (io.ReadCloser, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Accept", "text/plan")
|
||||||
|
req.Header.Set("User-Agent", apiUserAgent)
|
||||||
|
|
||||||
|
resp, err := httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
if resp != nil {
|
||||||
|
io.Copy(ioutil.Discard, resp.Body)
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot perform a request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Body, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const secretURL = "https://core.telegram.org/getProxySecret" // nolint: gas
|
||||||
|
|
||||||
|
func Secret() ([]byte, error) {
|
||||||
|
resp, err := request(secretURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot access telegram server: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Close()
|
||||||
|
|
||||||
|
secret, err := ioutil.ReadAll(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot read response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return secret, nil
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ package wrappers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
@@ -11,16 +9,9 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/9seconds/mtg/config"
|
"github.com/9seconds/mtg/config"
|
||||||
|
"github.com/9seconds/mtg/conntypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ConnIDLength = 8
|
|
||||||
|
|
||||||
type ConnID [ConnIDLength]byte
|
|
||||||
|
|
||||||
func (c ConnID) String() string {
|
|
||||||
return hex.EncodeToString(c[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
type connPurpose uint8
|
type connPurpose uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -37,7 +28,7 @@ type wrapperConn struct {
|
|||||||
parent net.Conn
|
parent net.Conn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
connID ConnID
|
connID conntypes.ConnID
|
||||||
logger *zap.SugaredLogger
|
logger *zap.SugaredLogger
|
||||||
localAddr *net.TCPAddr
|
localAddr *net.TCPAddr
|
||||||
remoteAddr *net.TCPAddr
|
remoteAddr *net.TCPAddr
|
||||||
@@ -121,7 +112,7 @@ func (w *wrapperConn) RemoteAddr() *net.TCPAddr {
|
|||||||
func newConn(ctx context.Context,
|
func newConn(ctx context.Context,
|
||||||
cancel context.CancelFunc,
|
cancel context.CancelFunc,
|
||||||
parent net.Conn,
|
parent net.Conn,
|
||||||
connID ConnID,
|
connID conntypes.ConnID,
|
||||||
purpose connPurpose) StreamReadWriteCloser {
|
purpose connPurpose) StreamReadWriteCloser {
|
||||||
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
localAddr := *parent.LocalAddr().(*net.TCPAddr)
|
||||||
|
|
||||||
@@ -156,22 +147,12 @@ func newConn(ctx context.Context,
|
|||||||
func NewClientConn(ctx context.Context,
|
func NewClientConn(ctx context.Context,
|
||||||
cancel context.CancelFunc,
|
cancel context.CancelFunc,
|
||||||
parent net.Conn,
|
parent net.Conn,
|
||||||
connID ConnID) StreamReadWriteCloser {
|
connID conntypes.ConnID) StreamReadWriteCloser {
|
||||||
return newConn(ctx, cancel, parent, connID, connPurposeClient)
|
return newConn(ctx, cancel, parent, connID, connPurposeClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTelegramConn(ctx context.Context,
|
func NewTelegramConn(ctx context.Context,
|
||||||
cancel context.CancelFunc,
|
cancel context.CancelFunc,
|
||||||
parent net.Conn) StreamReadWriteCloser {
|
parent net.Conn) StreamReadWriteCloser {
|
||||||
return newConn(ctx, cancel, parent, ConnID{}, connPurposeTelegram)
|
return newConn(ctx, cancel, parent, conntypes.ConnID{}, connPurposeTelegram)
|
||||||
}
|
|
||||||
|
|
||||||
func NewConnID() ConnID {
|
|
||||||
var id ConnID
|
|
||||||
|
|
||||||
if _, err := rand.Read(id[:]); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return id
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user