mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 22:34:02 +03:00
Change network to accept DialFunc
This commit is contained in:
+7
-17
@@ -38,8 +38,8 @@ type Access struct {
|
||||
Hex bool `help:"Print secret in hex encoding."`
|
||||
}
|
||||
|
||||
func (c *Access) Run(cli *CLI) error {
|
||||
if err := c.ReadConfig(cli.Access.ConfigPath); err != nil {
|
||||
func (c *Access) Run(cli *CLI, version string) error {
|
||||
if err := c.ReadConfig(cli.Access.ConfigPath, version); err != nil {
|
||||
return fmt.Errorf("cannot init config: %w", err)
|
||||
}
|
||||
|
||||
@@ -74,21 +74,11 @@ func (c *Access) Run(cli *CLI) error {
|
||||
}
|
||||
|
||||
func (c *Access) getIP(protocol string) net.IP {
|
||||
client := c.network.MakeHTTPClient(0)
|
||||
client.Transport = &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return c.network.DialContext(ctx, protocol, address)
|
||||
},
|
||||
}
|
||||
client := c.network.MakeHTTPClient(func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return c.network.DialContext(ctx, protocol, address)
|
||||
})
|
||||
|
||||
c.network.PrepareHTTPClient(client)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "https://ifconfig.co", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
resp, err := client.Get("https://ifconfig.co") // nolint: noctx
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
@@ -98,7 +88,7 @@ func (c *Access) getIP(protocol string) net.IP {
|
||||
}
|
||||
|
||||
defer func() {
|
||||
io.Copy(ioutil.Discard, resp.Body)
|
||||
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
|
||||
resp.Body.Close()
|
||||
}()
|
||||
|
||||
|
||||
+7
-6
@@ -15,7 +15,7 @@ type base struct {
|
||||
conf *config.Config
|
||||
}
|
||||
|
||||
func (b *base) ReadConfig(path string) error {
|
||||
func (b *base) ReadConfig(path, version string) error {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read config file: %w", err)
|
||||
@@ -26,7 +26,7 @@ func (b *base) ReadConfig(path string) error {
|
||||
return fmt.Errorf("cannot parse config: %w", err)
|
||||
}
|
||||
|
||||
ntw, err := b.makeNetwork(conf)
|
||||
ntw, err := b.makeNetwork(conf, version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot build a network: %w", err)
|
||||
}
|
||||
@@ -37,11 +37,12 @@ func (b *base) ReadConfig(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *base) makeNetwork(conf *config.Config) (network.Network, error) {
|
||||
func (b *base) makeNetwork(conf *config.Config, version string) (network.Network, error) {
|
||||
tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout)
|
||||
idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout)
|
||||
dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String()
|
||||
bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize)
|
||||
userAgent := "mtg/" + version
|
||||
|
||||
baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize))
|
||||
if err != nil {
|
||||
@@ -58,14 +59,14 @@ func (b *base) makeNetwork(conf *config.Config) (network.Network, error) {
|
||||
|
||||
switch len(proxyURLs) {
|
||||
case 0:
|
||||
return network.NewNetwork(baseDialer, dohIP, idleTimeout)
|
||||
return network.NewNetwork(baseDialer, userAgent, dohIP, idleTimeout)
|
||||
case 1:
|
||||
socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
|
||||
}
|
||||
|
||||
return network.NewNetwork(socksDialer, dohIP, idleTimeout)
|
||||
return network.NewNetwork(socksDialer, userAgent, dohIP, idleTimeout)
|
||||
}
|
||||
|
||||
socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs)
|
||||
@@ -73,5 +74,5 @@ func (b *base) makeNetwork(conf *config.Config) (network.Network, error) {
|
||||
return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
|
||||
}
|
||||
|
||||
return network.NewNetwork(socksDialer, dohIP, idleTimeout)
|
||||
return network.NewNetwork(socksDialer, userAgent, dohIP, idleTimeout)
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/alecthomas/kong"
|
||||
)
|
||||
import "github.com/alecthomas/kong"
|
||||
|
||||
type CLI struct {
|
||||
GenerateSecret GenerateSecret `cmd help:"Generate new proxy secret"` // nolint: govet
|
||||
|
||||
@@ -13,7 +13,7 @@ type GenerateSecret struct {
|
||||
Hex bool `help:"Print secret in hex encoding."`
|
||||
}
|
||||
|
||||
func (c *GenerateSecret) Run(cli *CLI) error { // nolint: unparam
|
||||
func (c *GenerateSecret) Run(cli *CLI, _ string) error {
|
||||
secret := mtglib.GenerateSecret(cli.GenerateSecret.HostName)
|
||||
|
||||
if cli.GenerateSecret.Hex {
|
||||
|
||||
@@ -30,7 +30,7 @@ func (c *TypeBytes) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypeBytes) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypeBytes) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func (c *TypeDuration) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypeDuration) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypeDuration) MarshalText() ([]byte, error) {
|
||||
return []byte(c.value.String()), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ func (c *TypeFloat) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TypeFloat) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c *TypeFloat) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func (c *TypeHostPort) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypeHostPort) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypeHostPort) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ func (c TypeHostPort) String() string {
|
||||
}
|
||||
|
||||
func (c TypeHostPort) HostValue(defaultValue net.IP) net.IP {
|
||||
return c.host.Value(defaultValue)
|
||||
return c.host.Value(defaultValue)
|
||||
}
|
||||
|
||||
func (c TypeHostPort) PortValue(defaultValue uint) uint {
|
||||
return c.port.Value(defaultValue)
|
||||
return c.port.Value(defaultValue)
|
||||
}
|
||||
|
||||
func (c TypeHostPort) Value(defaultHostValue net.IP, defaultPortValue uint) string {
|
||||
|
||||
@@ -6,7 +6,7 @@ type TypeHTTPPath struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (c *TypeHTTPPath) UnmarshalText(data []byte) error { // nolint: unparam
|
||||
func (c *TypeHTTPPath) UnmarshalText(data []byte) error {
|
||||
if len(data) > 0 {
|
||||
c.value = "/" + strings.Trim(string(data), "/")
|
||||
}
|
||||
@@ -14,7 +14,7 @@ func (c *TypeHTTPPath) UnmarshalText(data []byte) error { // nolint: unparam
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypeHTTPPath) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypeHTTPPath) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ func (c *TypeIP) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TypeIP) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c *TypeIP) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ func (c *TypeMetricPrefix) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypeMetricPrefix) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypeMetricPrefix) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ func (c *TypePort) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TypePort) MarshalJSON() ([]byte, error) { // nolint: unparam
|
||||
return []byte(c.String()), nil
|
||||
func (c *TypePort) MarshalJSON() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
func (c TypePort) String() string {
|
||||
|
||||
@@ -26,7 +26,7 @@ func (c *TypePreferIP) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c TypePreferIP) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c TypePreferIP) MarshalText() ([]byte, error) {
|
||||
return []byte(c.value), nil
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ func (c *TypeURL) UnmarshalText(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TypeURL) MarshalText() ([]byte, error) { // nolint: unparam
|
||||
func (c *TypeURL) MarshalText() ([]byte, error) {
|
||||
return []byte(c.String()), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,5 +19,5 @@ func main() {
|
||||
"version": version,
|
||||
})
|
||||
|
||||
ctx.FatalIfErrorf(ctx.Run(cli))
|
||||
ctx.FatalIfErrorf(ctx.Run(cli, version))
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
const (
|
||||
DefaultTimeout = 10 * time.Second
|
||||
DefaultIdleTimeout = time.Minute
|
||||
DefaultHTTPTimeout = 5 * time.Second
|
||||
DefaultBufferSize = 4096
|
||||
|
||||
ProxyDialerOpenThreshold = 5
|
||||
@@ -20,7 +19,8 @@ const (
|
||||
|
||||
DefaultDOHHostname = "9.9.9.9"
|
||||
|
||||
DNSTimeout = 5 * time.Second
|
||||
DNSTimeout = 5 * time.Second
|
||||
HTTPTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -28,6 +28,8 @@ var (
|
||||
ErrCannotDialWithAllProxies = errors.New("cannot dial with all proxies")
|
||||
)
|
||||
|
||||
type DialFunc func(ctx context.Context, protocol, address string) (net.Conn, error)
|
||||
|
||||
type Dialer interface {
|
||||
Dial(network, address string) (net.Conn, error)
|
||||
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||||
@@ -37,7 +39,6 @@ type Network interface {
|
||||
Dialer
|
||||
|
||||
DNSResolve(network, hostname string) (ips []string, err error)
|
||||
MakeHTTPClient(timeout time.Duration) *http.Client
|
||||
MakeHTTPClient(DialFunc) *http.Client
|
||||
IdleTimeout() time.Duration
|
||||
PrepareHTTPClient(*http.Client)
|
||||
}
|
||||
|
||||
+31
-14
@@ -12,10 +12,22 @@ import (
|
||||
doh "github.com/babolivier/go-doh-client"
|
||||
)
|
||||
|
||||
type networkHTTPTransport struct {
|
||||
userAgent string
|
||||
next http.RoundTripper
|
||||
}
|
||||
|
||||
func (n networkHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req.Header.Set("User-Agent", n.userAgent)
|
||||
|
||||
return n.next.RoundTrip(req)
|
||||
}
|
||||
|
||||
type network struct {
|
||||
idleTimeout time.Duration
|
||||
dialer Dialer
|
||||
dns doh.Resolver
|
||||
idleTimeout time.Duration
|
||||
userAgent string
|
||||
}
|
||||
|
||||
func (n *network) Dial(protocol, address string) (net.Conn, error) {
|
||||
@@ -107,23 +119,15 @@ func (n *network) IdleTimeout() time.Duration {
|
||||
return n.idleTimeout
|
||||
}
|
||||
|
||||
func (n *network) MakeHTTPClient(timeout time.Duration) *http.Client {
|
||||
if timeout <= 0 {
|
||||
timeout = DefaultHTTPTimeout
|
||||
func (n *network) MakeHTTPClient(dialFunc DialFunc) *http.Client {
|
||||
if dialFunc == nil {
|
||||
dialFunc = n.DialContext
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
Timeout: timeout,
|
||||
Transport: &http.Transport{
|
||||
DialContext: n.DialContext,
|
||||
},
|
||||
}
|
||||
return makeHTTPClient(n.userAgent, dialFunc)
|
||||
}
|
||||
|
||||
func (n *network) PatchHTTPClient(_ *http.Client) {
|
||||
}
|
||||
|
||||
func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (Network, error) {
|
||||
func NewNetwork(dialer Dialer, userAgent, dohHostname string, idleTimeout time.Duration) (Network, error) {
|
||||
switch {
|
||||
case idleTimeout < 0:
|
||||
return nil, fmt.Errorf("timeout should be positive number %s", idleTimeout)
|
||||
@@ -138,6 +142,7 @@ func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (N
|
||||
return &network{
|
||||
dialer: dialer,
|
||||
idleTimeout: idleTimeout,
|
||||
userAgent: userAgent,
|
||||
dns: doh.Resolver{
|
||||
Host: dohHostname,
|
||||
Class: doh.IN,
|
||||
@@ -150,3 +155,15 @@ func NewNetwork(dialer Dialer, dohHostname string, idleTimeout time.Duration) (N
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeHTTPClient(userAgent string, dialFunc DialFunc) *http.Client {
|
||||
return &http.Client{
|
||||
Timeout: HTTPTimeout,
|
||||
Transport: networkHTTPTransport{
|
||||
userAgent: userAgent,
|
||||
next: &http.Transport{
|
||||
DialContext: dialFunc,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/9seconds/mtg/v2/config"
|
||||
"github.com/9seconds/mtg/v2/mtglib/network"
|
||||
)
|
||||
|
||||
func makeNetwork(conf *config.Config) (network.Network, error) {
|
||||
tcpTimeout := conf.Network.Timeout.TCP.Value(network.DefaultTimeout)
|
||||
idleTimeout := conf.Network.Timeout.Idle.Value(network.DefaultIdleTimeout)
|
||||
dohIP := conf.Network.DOHIP.Value(net.ParseIP(network.DefaultDOHHostname)).String()
|
||||
bufferSize := conf.TCPBuffer.Value(network.DefaultBufferSize)
|
||||
|
||||
baseDialer, err := network.NewDefaultDialer(tcpTimeout, int(bufferSize))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot build a default dialer: %w", err)
|
||||
}
|
||||
|
||||
proxyURLs := make([]*url.URL, 0, len(conf.Network.Proxies))
|
||||
|
||||
for _, v := range conf.Network.Proxies {
|
||||
if value := v.Value(nil); value != nil {
|
||||
proxyURLs = append(proxyURLs, v.Value(nil))
|
||||
}
|
||||
}
|
||||
|
||||
switch len(proxyURLs) {
|
||||
case 0:
|
||||
return network.NewNetwork(baseDialer, dohIP, idleTimeout)
|
||||
case 1:
|
||||
socksDialer, err := network.NewSocks5Dialer(baseDialer, proxyURLs[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
|
||||
}
|
||||
|
||||
return network.NewNetwork(socksDialer, dohIP, idleTimeout)
|
||||
}
|
||||
|
||||
socksDialer, err := network.NewLoadBalancedSocks5Dialer(baseDialer, proxyURLs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot build socks5 dialer: %w", err)
|
||||
}
|
||||
|
||||
return network.NewNetwork(socksDialer, dohIP, idleTimeout)
|
||||
}
|
||||
|
||||
func exhaustResponse(response *http.Response) {
|
||||
io.Copy(ioutil.Discard, response.Body) // nolint: errcheck
|
||||
response.Body.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user