mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 22:04:02 +03:00
More reasonable shutdowns
This commit is contained in:
+11
-3
@@ -15,9 +15,12 @@ import (
|
|||||||
"github.com/9seconds/mtg/proxy"
|
"github.com/9seconds/mtg/proxy"
|
||||||
"github.com/9seconds/mtg/stats"
|
"github.com/9seconds/mtg/stats"
|
||||||
"github.com/9seconds/mtg/telegram"
|
"github.com/9seconds/mtg/telegram"
|
||||||
|
"github.com/9seconds/mtg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Proxy() error {
|
func Proxy() error {
|
||||||
|
ctx := utils.GetSignalContext()
|
||||||
|
|
||||||
atom := zap.NewAtomicLevel()
|
atom := zap.NewAtomicLevel()
|
||||||
switch {
|
switch {
|
||||||
case config.C.Debug:
|
case config.C.Debug:
|
||||||
@@ -37,7 +40,7 @@ func Proxy() error {
|
|||||||
zap.ReplaceGlobals(logger)
|
zap.ReplaceGlobals(logger)
|
||||||
defer logger.Sync() // nolint: errcheck
|
defer logger.Sync() // nolint: errcheck
|
||||||
|
|
||||||
if err := config.InitPublicAddress(); err != nil {
|
if err := config.InitPublicAddress(ctx); err != nil {
|
||||||
Fatal(err.Error())
|
Fatal(err.Error())
|
||||||
}
|
}
|
||||||
zap.S().Debugw("Configuration", "config", config.C)
|
zap.S().Debugw("Configuration", "config", config.C)
|
||||||
@@ -61,16 +64,21 @@ func Proxy() error {
|
|||||||
if err := antireplay.Init(); err != nil {
|
if err := antireplay.Init(); err != nil {
|
||||||
Fatal(err.Error())
|
Fatal(err.Error())
|
||||||
}
|
}
|
||||||
if err := stats.Init(); err != nil {
|
if err := stats.Init(ctx); err != nil {
|
||||||
Fatal(err.Error())
|
Fatal(err.Error())
|
||||||
}
|
}
|
||||||
proxyListener, err := net.Listen("tcp", config.C.ListenAddr.String())
|
proxyListener, err := net.Listen("tcp", config.C.ListenAddr.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatal(err.Error())
|
Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
proxyListener.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
app := &proxy.Proxy{
|
app := &proxy.Proxy{
|
||||||
Logger: zap.S().Named("proxy"),
|
Logger: zap.S().Named("proxy"),
|
||||||
|
Context: ctx,
|
||||||
}
|
}
|
||||||
if len(config.C.AdTag) == 0 {
|
if len(config.C.AdTag) == 0 {
|
||||||
app.TelegramProtocolMaker = obfuscated2.MakeTelegramProtocol
|
app.TelegramProtocolMaker = obfuscated2.MakeTelegramProtocol
|
||||||
|
|||||||
+6
-5
@@ -2,6 +2,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -140,14 +141,14 @@ func (c Config) String() string {
|
|||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigOpt struct {
|
type Opt struct {
|
||||||
Option OptionType
|
Option OptionType
|
||||||
Value interface{}
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var C = Config{}
|
var C = Config{}
|
||||||
|
|
||||||
func Init(options ...ConfigOpt) error { // nolint: gocyclo
|
func Init(options ...Opt) error { // nolint: gocyclo
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
switch opt.Option {
|
switch opt.Option {
|
||||||
case OptionTypeDebug:
|
case OptionTypeDebug:
|
||||||
@@ -222,7 +223,7 @@ func Init(options ...ConfigOpt) error { // nolint: gocyclo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitPublicAddress() error {
|
func InitPublicAddress(ctx context.Context) error {
|
||||||
if C.PublicIPv4Addr.Port == 0 {
|
if C.PublicIPv4Addr.Port == 0 {
|
||||||
C.PublicIPv4Addr.Port = C.ListenAddr.Port
|
C.PublicIPv4Addr.Port = C.ListenAddr.Port
|
||||||
}
|
}
|
||||||
@@ -232,7 +233,7 @@ func InitPublicAddress() error {
|
|||||||
|
|
||||||
foundAddress := C.PublicIPv4Addr.IP != nil || C.PublicIPv6Addr.IP != nil
|
foundAddress := C.PublicIPv4Addr.IP != nil || C.PublicIPv6Addr.IP != nil
|
||||||
if C.PublicIPv4Addr.IP == nil {
|
if C.PublicIPv4Addr.IP == nil {
|
||||||
ip, err := getGlobalIPv4()
|
ip, err := getGlobalIPv4(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Warnw("Cannot resolve public address", "error", err)
|
zap.S().Warnw("Cannot resolve public address", "error", err)
|
||||||
} else {
|
} else {
|
||||||
@@ -241,7 +242,7 @@ func InitPublicAddress() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if C.PublicIPv6Addr.IP == nil {
|
if C.PublicIPv6Addr.IP == nil {
|
||||||
ip, err := getGlobalIPv6()
|
ip, err := getGlobalIPv6(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Warnw("Cannot resolve public address", "error", err)
|
zap.S().Warnw("Cannot resolve public address", "error", err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+11
-6
@@ -17,23 +17,23 @@ const (
|
|||||||
ifconfigTimeout = 10 * time.Second
|
ifconfigTimeout = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
func getGlobalIPv4() (net.IP, error) {
|
func getGlobalIPv4(ctx context.Context) (net.IP, error) {
|
||||||
ip, err := fetchIP("tcp4")
|
ip, err := fetchIP(ctx, "tcp4")
|
||||||
if err != nil || ip.To4() == nil {
|
if err != nil || ip.To4() == nil {
|
||||||
return nil, errors.Annotate(err, "Cannot find public ipv4 address")
|
return nil, errors.Annotate(err, "Cannot find public ipv4 address")
|
||||||
}
|
}
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGlobalIPv6() (net.IP, error) {
|
func getGlobalIPv6(ctx context.Context) (net.IP, error) {
|
||||||
ip, err := fetchIP("tcp6")
|
ip, err := fetchIP(ctx, "tcp6")
|
||||||
if err != nil || ip.To4() != nil {
|
if err != nil || ip.To4() != nil {
|
||||||
return nil, errors.Annotate(err, "Cannot find public ipv6 address")
|
return nil, errors.Annotate(err, "Cannot find public ipv6 address")
|
||||||
}
|
}
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchIP(network string) (net.IP, error) {
|
func fetchIP(ctx context.Context, network string) (net.IP, error) {
|
||||||
dialer := &net.Dialer{FallbackDelay: -1}
|
dialer := &net.Dialer{FallbackDelay: -1}
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Jar: nil,
|
Jar: nil,
|
||||||
@@ -45,7 +45,12 @@ func fetchIP(network string) (net.IP, error) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Get(ifconfigAddress)
|
req, err := http.NewRequest("GET", ifconfigAddress, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Annotate(err, "Cannot create a request")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
|
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
|
||||||
|
|||||||
@@ -152,29 +152,29 @@ func main() {
|
|||||||
|
|
||||||
case proxyCommand.FullCommand():
|
case proxyCommand.FullCommand():
|
||||||
err := config.Init(
|
err := config.Init(
|
||||||
config.ConfigOpt{Option: config.OptionTypeDebug, Value: *proxyDebug},
|
config.Opt{Option: config.OptionTypeDebug, Value: *proxyDebug},
|
||||||
config.ConfigOpt{Option: config.OptionTypeVerbose, Value: *proxyVerbose},
|
config.Opt{Option: config.OptionTypeVerbose, Value: *proxyVerbose},
|
||||||
config.ConfigOpt{Option: config.OptionTypeBindIP, Value: *proxyBindIP},
|
config.Opt{Option: config.OptionTypeBindIP, Value: *proxyBindIP},
|
||||||
config.ConfigOpt{Option: config.OptionTypeBindPort, Value: *proxyBindPort},
|
config.Opt{Option: config.OptionTypeBindPort, Value: *proxyBindPort},
|
||||||
config.ConfigOpt{Option: config.OptionTypePublicIPv4, Value: *proxyPublicIPv4},
|
config.Opt{Option: config.OptionTypePublicIPv4, Value: *proxyPublicIPv4},
|
||||||
config.ConfigOpt{Option: config.OptionTypePublicIPv4Port, Value: *proxyPublicIPv4Port},
|
config.Opt{Option: config.OptionTypePublicIPv4Port, Value: *proxyPublicIPv4Port},
|
||||||
config.ConfigOpt{Option: config.OptionTypePublicIPv6, Value: *proxyPublicIPv6},
|
config.Opt{Option: config.OptionTypePublicIPv6, Value: *proxyPublicIPv6},
|
||||||
config.ConfigOpt{Option: config.OptionTypePublicIPv6Port, Value: *proxyPublicIPv6Port},
|
config.Opt{Option: config.OptionTypePublicIPv6Port, Value: *proxyPublicIPv6Port},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsIP, Value: *proxyStatsIP},
|
config.Opt{Option: config.OptionTypeStatsIP, Value: *proxyStatsIP},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsPort, Value: *proxyStatsPort},
|
config.Opt{Option: config.OptionTypeStatsPort, Value: *proxyStatsPort},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdIP, Value: *proxyStatsdIP},
|
config.Opt{Option: config.OptionTypeStatsdIP, Value: *proxyStatsdIP},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdPort, Value: *proxyStatsdPort},
|
config.Opt{Option: config.OptionTypeStatsdPort, Value: *proxyStatsdPort},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdNetwork, Value: *proxyStatsdNetwork},
|
config.Opt{Option: config.OptionTypeStatsdNetwork, Value: *proxyStatsdNetwork},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdPrefix, Value: *proxyStatsdPrefix},
|
config.Opt{Option: config.OptionTypeStatsdPrefix, Value: *proxyStatsdPrefix},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdTagsFormat, Value: *proxyStatsdTagsFormat},
|
config.Opt{Option: config.OptionTypeStatsdTagsFormat, Value: *proxyStatsdTagsFormat},
|
||||||
config.ConfigOpt{Option: config.OptionTypeStatsdTags, Value: *proxyStatsdTags},
|
config.Opt{Option: config.OptionTypeStatsdTags, Value: *proxyStatsdTags},
|
||||||
config.ConfigOpt{Option: config.OptionTypePrometheusPrefix, Value: *proxyPrometheusPrefix},
|
config.Opt{Option: config.OptionTypePrometheusPrefix, Value: *proxyPrometheusPrefix},
|
||||||
config.ConfigOpt{Option: config.OptionTypeWriteBufferSize, Value: *proxyWriteBufferSize},
|
config.Opt{Option: config.OptionTypeWriteBufferSize, Value: *proxyWriteBufferSize},
|
||||||
config.ConfigOpt{Option: config.OptionTypeReadBufferSize, Value: *proxyReadBufferSize},
|
config.Opt{Option: config.OptionTypeReadBufferSize, Value: *proxyReadBufferSize},
|
||||||
config.ConfigOpt{Option: config.OptionTypeAntiReplayMaxSize, Value: *proxyAntiReplayMaxSize},
|
config.Opt{Option: config.OptionTypeAntiReplayMaxSize, Value: *proxyAntiReplayMaxSize},
|
||||||
config.ConfigOpt{Option: config.OptionTypeAntiReplayEvictionTime, Value: *proxyAntiReplayEvictionTime},
|
config.Opt{Option: config.OptionTypeAntiReplayEvictionTime, Value: *proxyAntiReplayEvictionTime},
|
||||||
config.ConfigOpt{Option: config.OptionTypeSecret, Value: *proxySecret},
|
config.Opt{Option: config.OptionTypeSecret, Value: *proxySecret},
|
||||||
config.ConfigOpt{Option: config.OptionTypeAdtag, Value: *proxyAdtag},
|
config.Opt{Option: config.OptionTypeAdtag, Value: *proxyAdtag},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cli.Fatal(err.Error())
|
cli.Fatal(err.Error())
|
||||||
|
|||||||
+11
-3
@@ -20,17 +20,25 @@ const directPipeBufferSize = 1024 * 1024
|
|||||||
|
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
Logger *zap.SugaredLogger
|
Logger *zap.SugaredLogger
|
||||||
|
Context context.Context
|
||||||
ClientProtocolMaker protocol.ClientProtocolMaker
|
ClientProtocolMaker protocol.ClientProtocolMaker
|
||||||
TelegramProtocolMaker protocol.TelegramProtocolMaker
|
TelegramProtocolMaker protocol.TelegramProtocolMaker
|
||||||
TelegramDialer telegram.Telegram
|
TelegramDialer telegram.Telegram
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) Serve(listener net.Listener) {
|
func (p *Proxy) Serve(listener net.Listener) {
|
||||||
|
doneChan := p.Context.Done()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := listener.Accept()
|
conn, err := listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.Logger.Errorw("Cannot allocate incoming connection", "error", err)
|
select {
|
||||||
continue
|
case <-doneChan:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
p.Logger.Errorw("Cannot allocate incoming connection", "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
go p.accept(conn)
|
go p.accept(conn)
|
||||||
}
|
}
|
||||||
@@ -53,7 +61,7 @@ func (p *Proxy) accept(conn net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(p.Context)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
wrappedConn := wrappers.NewClientConn(ctx, cancel, conn, connID)
|
wrappedConn := wrappers.NewClientConn(ctx, cancel, conn, connID)
|
||||||
|
|||||||
+6
-1
@@ -1,6 +1,7 @@
|
|||||||
package stats
|
package stats
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ func (m multiStats) AntiReplayDetected() {
|
|||||||
|
|
||||||
var S Stats
|
var S Stats
|
||||||
|
|
||||||
func Init() error {
|
func Init(ctx context.Context) error {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
instanceJSON := newStatsJSON(mux)
|
instanceJSON := newStatsJSON(mux)
|
||||||
@@ -86,6 +87,10 @@ func Init() error {
|
|||||||
Handler: mux,
|
Handler: mux,
|
||||||
}
|
}
|
||||||
go srv.Serve(listener) // nolint: errcheck
|
go srv.Serve(listener) // nolint: errcheck
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
srv.Shutdown(context.Background()) // nolint: errcheck
|
||||||
|
}()
|
||||||
|
|
||||||
S = multiStats(stats)
|
S = multiStats(stats)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSignalContext() context.Context {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
for range sigChan {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSignalContext() context.Context {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
sigChan := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(sigChan, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
for range sigChan {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user