mirror of https://github.com/go-gost/gost.git
add config hot reload
parent
3c7a984aa3
commit
581dd74bbb
|
|
@ -1,6 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-gost/core/auth"
|
"github.com/go-gost/core/auth"
|
||||||
|
|
@ -9,6 +11,7 @@ import (
|
||||||
"github.com/go-gost/x/api"
|
"github.com/go-gost/x/api"
|
||||||
xauth "github.com/go-gost/x/auth"
|
xauth "github.com/go-gost/x/auth"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
|
"github.com/go-gost/x/config/cmd"
|
||||||
admission_parser "github.com/go-gost/x/config/parsing/admission"
|
admission_parser "github.com/go-gost/x/config/parsing/admission"
|
||||||
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
auth_parser "github.com/go-gost/x/config/parsing/auth"
|
||||||
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
|
||||||
|
|
@ -24,134 +27,352 @@ import (
|
||||||
router_parser "github.com/go-gost/x/config/parsing/router"
|
router_parser "github.com/go-gost/x/config/parsing/router"
|
||||||
sd_parser "github.com/go-gost/x/config/parsing/sd"
|
sd_parser "github.com/go-gost/x/config/parsing/sd"
|
||||||
service_parser "github.com/go-gost/x/config/parsing/service"
|
service_parser "github.com/go-gost/x/config/parsing/service"
|
||||||
|
xmd "github.com/go-gost/x/metadata"
|
||||||
|
mdutil "github.com/go-gost/x/metadata/util"
|
||||||
metrics "github.com/go-gost/x/metrics/service"
|
metrics "github.com/go-gost/x/metrics/service"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildService(cfg *config.Config) (services []service.Service) {
|
func parseConfig() (*config.Config, error) {
|
||||||
if cfg == nil {
|
cfg := &config.Config{}
|
||||||
return
|
if cfgFile != "" {
|
||||||
|
cfgFile = strings.TrimSpace(cfgFile)
|
||||||
|
if strings.HasPrefix(cfgFile, "{") && strings.HasSuffix(cfgFile, "}") {
|
||||||
|
if err := json.Unmarshal([]byte(cfgFile), cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cfg.ReadFile(cfgFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log := logger.Default()
|
cmdCfg, err := cmd.BuildConfigFromCmd(services, nodes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg = mergeConfig(cfg, cmdCfg)
|
||||||
|
|
||||||
|
if len(cfg.Services) == 0 && apiAddr == "" && cfg.API == nil {
|
||||||
|
if err := cfg.Load(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := os.Getenv("GOST_LOGGER_LEVEL"); v != "" {
|
||||||
|
cfg.Log = &config.LogConfig{
|
||||||
|
Level: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v := os.Getenv("GOST_API"); v != "" {
|
||||||
|
cfg.API = &config.APIConfig{
|
||||||
|
Addr: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v := os.Getenv("GOST_METRICS"); v != "" {
|
||||||
|
cfg.Metrics = &config.MetricsConfig{
|
||||||
|
Addr: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v := os.Getenv("GOST_PROFILING"); v != "" {
|
||||||
|
cfg.Profiling = &config.ProfilingConfig{
|
||||||
|
Addr: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if debug || trace {
|
||||||
|
if cfg.Log == nil {
|
||||||
|
cfg.Log = &config.LogConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Log.Level = string(logger.DebugLevel)
|
||||||
|
if trace {
|
||||||
|
cfg.Log.Level = string(logger.TraceLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiAddr != "" {
|
||||||
|
cfg.API = &config.APIConfig{
|
||||||
|
Addr: apiAddr,
|
||||||
|
}
|
||||||
|
if url, _ := cmd.Norm(apiAddr); url != nil {
|
||||||
|
cfg.API.Addr = url.Host
|
||||||
|
if url.User != nil {
|
||||||
|
username := url.User.Username()
|
||||||
|
password, _ := url.User.Password()
|
||||||
|
cfg.API.Auth = &config.AuthConfig{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m := map[string]any{}
|
||||||
|
for k, v := range url.Query() {
|
||||||
|
if len(v) > 0 {
|
||||||
|
m[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md := xmd.NewMetadata(m)
|
||||||
|
cfg.API.PathPrefix = mdutil.GetString(md, "pathPrefix")
|
||||||
|
cfg.API.AccessLog = mdutil.GetBool(md, "accesslog")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if metricsAddr != "" {
|
||||||
|
cfg.Metrics = &config.MetricsConfig{
|
||||||
|
Addr: metricsAddr,
|
||||||
|
}
|
||||||
|
if url, _ := cmd.Norm(metricsAddr); url != nil {
|
||||||
|
cfg.Metrics.Addr = url.Host
|
||||||
|
if url.User != nil {
|
||||||
|
username := url.User.Username()
|
||||||
|
password, _ := url.User.Password()
|
||||||
|
cfg.Metrics.Auth = &config.AuthConfig{
|
||||||
|
Username: username,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m := map[string]any{}
|
||||||
|
for k, v := range url.Query() {
|
||||||
|
if len(v) > 0 {
|
||||||
|
m[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
md := xmd.NewMetadata(m)
|
||||||
|
cfg.Metrics.Path = mdutil.GetString(md, "path")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeConfig(cfg1, cfg2 *config.Config) *config.Config {
|
||||||
|
if cfg1 == nil {
|
||||||
|
return cfg2
|
||||||
|
}
|
||||||
|
if cfg2 == nil {
|
||||||
|
return cfg1
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.Config{
|
||||||
|
Services: append(cfg1.Services, cfg2.Services...),
|
||||||
|
Chains: append(cfg1.Chains, cfg2.Chains...),
|
||||||
|
Hops: append(cfg1.Hops, cfg2.Hops...),
|
||||||
|
Authers: append(cfg1.Authers, cfg2.Authers...),
|
||||||
|
Admissions: append(cfg1.Admissions, cfg2.Admissions...),
|
||||||
|
Bypasses: append(cfg1.Bypasses, cfg2.Bypasses...),
|
||||||
|
Resolvers: append(cfg1.Resolvers, cfg2.Resolvers...),
|
||||||
|
Hosts: append(cfg1.Hosts, cfg2.Hosts...),
|
||||||
|
Ingresses: append(cfg1.Ingresses, cfg2.Ingresses...),
|
||||||
|
SDs: append(cfg1.SDs, cfg2.SDs...),
|
||||||
|
Recorders: append(cfg1.Recorders, cfg2.Recorders...),
|
||||||
|
Limiters: append(cfg1.Limiters, cfg2.Limiters...),
|
||||||
|
CLimiters: append(cfg1.CLimiters, cfg2.CLimiters...),
|
||||||
|
RLimiters: append(cfg1.RLimiters, cfg2.RLimiters...),
|
||||||
|
Loggers: append(cfg1.Loggers, cfg2.Loggers...),
|
||||||
|
Routers: append(cfg1.Routers, cfg2.Routers...),
|
||||||
|
Observers: append(cfg1.Observers, cfg2.Observers...),
|
||||||
|
TLS: cfg1.TLS,
|
||||||
|
Log: cfg1.Log,
|
||||||
|
API: cfg1.API,
|
||||||
|
Metrics: cfg1.Metrics,
|
||||||
|
Profiling: cfg1.Profiling,
|
||||||
|
}
|
||||||
|
if cfg2.TLS != nil {
|
||||||
|
cfg.TLS = cfg2.TLS
|
||||||
|
}
|
||||||
|
if cfg2.Log != nil {
|
||||||
|
cfg.Log = cfg2.Log
|
||||||
|
}
|
||||||
|
if cfg2.API != nil {
|
||||||
|
cfg.API = cfg2.API
|
||||||
|
}
|
||||||
|
if cfg2.Metrics != nil {
|
||||||
|
cfg.Metrics = cfg2.Metrics
|
||||||
|
}
|
||||||
|
if cfg2.Profiling != nil {
|
||||||
|
cfg.Profiling = cfg2.Profiling
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func register(cfg *config.Config) error {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for name := range registry.LoggerRegistry().GetAll() {
|
||||||
|
registry.LoggerRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, loggerCfg := range cfg.Loggers {
|
for _, loggerCfg := range cfg.Loggers {
|
||||||
if err := registry.LoggerRegistry().Register(loggerCfg.Name, logger_parser.ParseLogger(loggerCfg)); err != nil {
|
if err := registry.LoggerRegistry().Register(loggerCfg.Name, logger_parser.ParseLogger(loggerCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.AutherRegistry().GetAll() {
|
||||||
|
registry.AutherRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, autherCfg := range cfg.Authers {
|
for _, autherCfg := range cfg.Authers {
|
||||||
if err := registry.AutherRegistry().Register(autherCfg.Name, auth_parser.ParseAuther(autherCfg)); err != nil {
|
if err := registry.AutherRegistry().Register(autherCfg.Name, auth_parser.ParseAuther(autherCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.AdmissionRegistry().GetAll() {
|
||||||
|
registry.AdmissionRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, admissionCfg := range cfg.Admissions {
|
for _, admissionCfg := range cfg.Admissions {
|
||||||
if err := registry.AdmissionRegistry().Register(admissionCfg.Name, admission_parser.ParseAdmission(admissionCfg)); err != nil {
|
if err := registry.AdmissionRegistry().Register(admissionCfg.Name, admission_parser.ParseAdmission(admissionCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.BypassRegistry().GetAll() {
|
||||||
|
registry.BypassRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, bypassCfg := range cfg.Bypasses {
|
for _, bypassCfg := range cfg.Bypasses {
|
||||||
if err := registry.BypassRegistry().Register(bypassCfg.Name, bypass_parser.ParseBypass(bypassCfg)); err != nil {
|
if err := registry.BypassRegistry().Register(bypassCfg.Name, bypass_parser.ParseBypass(bypassCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.ResolverRegistry().GetAll() {
|
||||||
|
registry.ResolverRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, resolverCfg := range cfg.Resolvers {
|
for _, resolverCfg := range cfg.Resolvers {
|
||||||
r, err := resolver_parser.ParseResolver(resolverCfg)
|
r, err := resolver_parser.ParseResolver(resolverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
if err := registry.ResolverRegistry().Register(resolverCfg.Name, r); err != nil {
|
if err := registry.ResolverRegistry().Register(resolverCfg.Name, r); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.HostsRegistry().GetAll() {
|
||||||
|
registry.HostsRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, hostsCfg := range cfg.Hosts {
|
for _, hostsCfg := range cfg.Hosts {
|
||||||
if err := registry.HostsRegistry().Register(hostsCfg.Name, hosts_parser.ParseHostMapper(hostsCfg)); err != nil {
|
if err := registry.HostsRegistry().Register(hostsCfg.Name, hosts_parser.ParseHostMapper(hostsCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.IngressRegistry().GetAll() {
|
||||||
|
registry.IngressRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, ingressCfg := range cfg.Ingresses {
|
for _, ingressCfg := range cfg.Ingresses {
|
||||||
if err := registry.IngressRegistry().Register(ingressCfg.Name, ingress_parser.ParseIngress(ingressCfg)); err != nil {
|
if err := registry.IngressRegistry().Register(ingressCfg.Name, ingress_parser.ParseIngress(ingressCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.RouterRegistry().GetAll() {
|
||||||
|
registry.RouterRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, routerCfg := range cfg.Routers {
|
for _, routerCfg := range cfg.Routers {
|
||||||
if err := registry.RouterRegistry().Register(routerCfg.Name, router_parser.ParseRouter(routerCfg)); err != nil {
|
if err := registry.RouterRegistry().Register(routerCfg.Name, router_parser.ParseRouter(routerCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.SDRegistry().GetAll() {
|
||||||
|
registry.SDRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, sdCfg := range cfg.SDs {
|
for _, sdCfg := range cfg.SDs {
|
||||||
if err := registry.SDRegistry().Register(sdCfg.Name, sd_parser.ParseSD(sdCfg)); err != nil {
|
if err := registry.SDRegistry().Register(sdCfg.Name, sd_parser.ParseSD(sdCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.ObserverRegistry().GetAll() {
|
||||||
|
registry.ObserverRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, observerCfg := range cfg.Observers {
|
for _, observerCfg := range cfg.Observers {
|
||||||
if err := registry.ObserverRegistry().Register(observerCfg.Name, observer_parser.ParseObserver(observerCfg)); err != nil {
|
if err := registry.ObserverRegistry().Register(observerCfg.Name, observer_parser.ParseObserver(observerCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.RecorderRegistry().GetAll() {
|
||||||
|
registry.RecorderRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, recorderCfg := range cfg.Recorders {
|
for _, recorderCfg := range cfg.Recorders {
|
||||||
if err := registry.RecorderRegistry().Register(recorderCfg.Name, recorder_parser.ParseRecorder(recorderCfg)); err != nil {
|
if err := registry.RecorderRegistry().Register(recorderCfg.Name, recorder_parser.ParseRecorder(recorderCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.TrafficLimiterRegistry().GetAll() {
|
||||||
|
registry.TrafficLimiterRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, limiterCfg := range cfg.Limiters {
|
for _, limiterCfg := range cfg.Limiters {
|
||||||
if err := registry.TrafficLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseTrafficLimiter(limiterCfg)); err != nil {
|
if err := registry.TrafficLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseTrafficLimiter(limiterCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.ConnLimiterRegistry().GetAll() {
|
||||||
|
registry.ConnLimiterRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, limiterCfg := range cfg.CLimiters {
|
for _, limiterCfg := range cfg.CLimiters {
|
||||||
if err := registry.ConnLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseConnLimiter(limiterCfg)); err != nil {
|
if err := registry.ConnLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseConnLimiter(limiterCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.RateLimiterRegistry().GetAll() {
|
||||||
|
registry.RateLimiterRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, limiterCfg := range cfg.RLimiters {
|
for _, limiterCfg := range cfg.RLimiters {
|
||||||
if err := registry.RateLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseRateLimiter(limiterCfg)); err != nil {
|
if err := registry.RateLimiterRegistry().Register(limiterCfg.Name, limiter_parser.ParseRateLimiter(limiterCfg)); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, hopCfg := range cfg.Hops {
|
|
||||||
hop, err := hop_parser.ParseHop(hopCfg, log)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := registry.HopRegistry().Register(hopCfg.Name, hop); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, chainCfg := range cfg.Chains {
|
|
||||||
c, err := chain_parser.ParseChain(chainCfg, log)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := registry.ChainRegistry().Register(chainCfg.Name, c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name := range registry.HopRegistry().GetAll() {
|
||||||
|
registry.HopRegistry().Unregister(name)
|
||||||
|
}
|
||||||
|
for _, hopCfg := range cfg.Hops {
|
||||||
|
hop, err := hop_parser.ParseHop(hopCfg, logger.Default())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := registry.HopRegistry().Register(hopCfg.Name, hop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for name := range registry.ChainRegistry().GetAll() {
|
||||||
|
registry.ChainRegistry().Unregister(name)
|
||||||
|
}
|
||||||
|
for _, chainCfg := range cfg.Chains {
|
||||||
|
c, err := chain_parser.ParseChain(chainCfg, logger.Default())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := registry.ChainRegistry().Register(chainCfg.Name, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for name := range registry.ServiceRegistry().GetAll() {
|
||||||
|
registry.ServiceRegistry().Unregister(name)
|
||||||
|
}
|
||||||
for _, svcCfg := range cfg.Services {
|
for _, svcCfg := range cfg.Services {
|
||||||
svc, err := service_parser.ParseService(svcCfg)
|
svc, err := service_parser.ParseService(svcCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
if svc != nil {
|
if svc != nil {
|
||||||
if err := registry.ServiceRegistry().Register(svcCfg.Name, svc); err != nil {
|
if err := registry.ServiceRegistry().Register(svcCfg.Name, svc); err != nil {
|
||||||
log.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
services = append(services, svc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildAPIService(cfg *config.APIConfig) (service.Service, error) {
|
func buildAPIService(cfg *config.APIConfig) (service.Service, error) {
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ var (
|
||||||
services stringList
|
services stringList
|
||||||
nodes stringList
|
nodes stringList
|
||||||
debug bool
|
debug bool
|
||||||
|
trace bool
|
||||||
apiAddr string
|
apiAddr string
|
||||||
metricsAddr string
|
metricsAddr string
|
||||||
)
|
)
|
||||||
|
|
@ -90,6 +91,7 @@ func init() {
|
||||||
flag.BoolVar(&printVersion, "V", false, "print version")
|
flag.BoolVar(&printVersion, "V", false, "print version")
|
||||||
flag.StringVar(&outputFormat, "O", "", "output format, one of yaml|json format")
|
flag.StringVar(&outputFormat, "O", "", "output format, one of yaml|json format")
|
||||||
flag.BoolVar(&debug, "D", false, "debug mode")
|
flag.BoolVar(&debug, "D", false, "debug mode")
|
||||||
|
flag.BoolVar(&trace, "DD", false, "trace mode")
|
||||||
flag.StringVar(&apiAddr, "api", "", "api service address")
|
flag.StringVar(&apiAddr, "api", "", "api service address")
|
||||||
flag.StringVar(&metricsAddr, "metrics", "", "metrics service address")
|
flag.StringVar(&metricsAddr, "metrics", "", "metrics service address")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
@ -99,13 +101,15 @@ func init() {
|
||||||
version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.SetDefault(xlogger.NewLogger())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
log := xlogger.NewLogger()
|
||||||
|
logger.SetDefault(log)
|
||||||
|
|
||||||
p := &program{}
|
p := &program{}
|
||||||
|
|
||||||
if err := svc.Run(p); err != nil {
|
if err := svc.Run(p); err != nil {
|
||||||
log.Fatal(err)
|
logger.Default().Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,139 +1,44 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"context"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/go-gost/core/logger"
|
"github.com/go-gost/core/logger"
|
||||||
"github.com/go-gost/core/service"
|
"github.com/go-gost/core/service"
|
||||||
"github.com/go-gost/x/config"
|
"github.com/go-gost/x/config"
|
||||||
"github.com/go-gost/x/config/cmd"
|
|
||||||
"github.com/go-gost/x/config/parsing"
|
"github.com/go-gost/x/config/parsing"
|
||||||
logger_parser "github.com/go-gost/x/config/parsing/logger"
|
logger_parser "github.com/go-gost/x/config/parsing/logger"
|
||||||
xmd "github.com/go-gost/x/metadata"
|
|
||||||
mdutil "github.com/go-gost/x/metadata/util"
|
|
||||||
xmetrics "github.com/go-gost/x/metrics"
|
xmetrics "github.com/go-gost/x/metrics"
|
||||||
"github.com/go-gost/x/registry"
|
"github.com/go-gost/x/registry"
|
||||||
"github.com/judwhite/go-svc"
|
"github.com/judwhite/go-svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type program struct {
|
type program struct {
|
||||||
apiSrv service.Service
|
srvApi service.Service
|
||||||
metricSrv service.Service
|
srvMetric service.Service
|
||||||
|
srvProfiling *http.Server
|
||||||
|
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) Init(env svc.Environment) error {
|
func (p *program) Init(env svc.Environment) error {
|
||||||
cfg := &config.Config{}
|
cfg, err := parseConfig()
|
||||||
if cfgFile != "" {
|
|
||||||
cfgFile = strings.TrimSpace(cfgFile)
|
|
||||||
if strings.HasPrefix(cfgFile, "{") && strings.HasSuffix(cfgFile, "}") {
|
|
||||||
if err := json.Unmarshal([]byte(cfgFile), cfg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := cfg.ReadFile(cfgFile); err != nil {
|
|
||||||
logger.Default().Error(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmdCfg, err := cmd.BuildConfigFromCmd(services, nodes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg = p.mergeConfig(cfg, cmdCfg)
|
|
||||||
|
|
||||||
if len(cfg.Services) == 0 && apiAddr == "" && cfg.API == nil {
|
config.Set(cfg)
|
||||||
if err := cfg.Load(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v := os.Getenv("GOST_API"); v != "" {
|
return nil
|
||||||
cfg.API = &config.APIConfig{
|
}
|
||||||
Addr: v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v := os.Getenv("GOST_LOGGER_LEVEL"); v != "" {
|
|
||||||
cfg.Log = &config.LogConfig{
|
|
||||||
Level: v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v := os.Getenv("GOST_PROFILING"); v != "" {
|
|
||||||
cfg.Profiling = &config.ProfilingConfig{
|
|
||||||
Addr: v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v := os.Getenv("GOST_METRICS"); v != "" {
|
|
||||||
cfg.Metrics = &config.MetricsConfig{
|
|
||||||
Addr: v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if apiAddr != "" {
|
func (p *program) Start() error {
|
||||||
cfg.API = &config.APIConfig{
|
cfg := config.Global()
|
||||||
Addr: apiAddr,
|
|
||||||
}
|
|
||||||
if url, _ := cmd.Norm(apiAddr); url != nil {
|
|
||||||
cfg.API.Addr = url.Host
|
|
||||||
if url.User != nil {
|
|
||||||
username := url.User.Username()
|
|
||||||
password, _ := url.User.Password()
|
|
||||||
cfg.API.Auth = &config.AuthConfig{
|
|
||||||
Username: username,
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m := map[string]any{}
|
|
||||||
for k, v := range url.Query() {
|
|
||||||
if len(v) > 0 {
|
|
||||||
m[k] = v[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
md := xmd.NewMetadata(m)
|
|
||||||
cfg.API.PathPrefix = mdutil.GetString(md, "pathPrefix")
|
|
||||||
cfg.API.AccessLog = mdutil.GetBool(md, "accesslog")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if debug {
|
|
||||||
if cfg.Log == nil {
|
|
||||||
cfg.Log = &config.LogConfig{}
|
|
||||||
}
|
|
||||||
cfg.Log.Level = string(logger.DebugLevel)
|
|
||||||
}
|
|
||||||
if metricsAddr != "" {
|
|
||||||
cfg.Metrics = &config.MetricsConfig{
|
|
||||||
Addr: metricsAddr,
|
|
||||||
}
|
|
||||||
if url, _ := cmd.Norm(metricsAddr); url != nil {
|
|
||||||
cfg.Metrics.Addr = url.Host
|
|
||||||
if url.User != nil {
|
|
||||||
username := url.User.Username()
|
|
||||||
password, _ := url.User.Password()
|
|
||||||
cfg.Metrics.Auth = &config.AuthConfig{
|
|
||||||
Username: username,
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m := map[string]any{}
|
|
||||||
for k, v := range url.Query() {
|
|
||||||
if len(v) > 0 {
|
|
||||||
m[k] = v[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
md := xmd.NewMetadata(m)
|
|
||||||
cfg.Metrics.Path = mdutil.GetString(md, "path")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logCfg := cfg.Log
|
|
||||||
if logCfg == nil {
|
|
||||||
logCfg = &config.LogConfig{}
|
|
||||||
}
|
|
||||||
logger.SetDefault(logger_parser.ParseLogger(&config.LoggerConfig{Log: logCfg}))
|
|
||||||
|
|
||||||
if outputFormat != "" {
|
if outputFormat != "" {
|
||||||
if err := cfg.Write(os.Stdout, outputFormat); err != nil {
|
if err := cfg.Write(os.Stdout, outputFormat); err != nil {
|
||||||
|
|
@ -142,127 +47,173 @@ func (p *program) Init(env svc.Environment) error {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
parsing.BuildDefaultTLSConfig(cfg.TLS)
|
if cfg.Metrics != nil {
|
||||||
|
xmetrics.Init(xmetrics.NewMetrics())
|
||||||
|
}
|
||||||
|
|
||||||
config.Set(cfg)
|
if err := p.build(cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
p.cancel = cancel
|
||||||
|
go p.reload(ctx)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) Start() error {
|
func (p *program) Stop() error {
|
||||||
log := logger.Default()
|
if p.cancel != nil {
|
||||||
cfg := config.Global()
|
p.cancel()
|
||||||
|
|
||||||
if cfg.API != nil {
|
|
||||||
s, err := buildAPIService(cfg.API)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
p.apiSrv = s
|
|
||||||
go func() {
|
|
||||||
defer s.Close()
|
|
||||||
log.Info("api service on ", s.Addr())
|
|
||||||
log.Error(s.Serve())
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
if cfg.Profiling != nil {
|
|
||||||
go func() {
|
|
||||||
addr := cfg.Profiling.Addr
|
|
||||||
if addr == "" {
|
|
||||||
addr = ":6060"
|
|
||||||
}
|
|
||||||
log.Info("profiling server on ", addr)
|
|
||||||
log.Fatal(http.ListenAndServe(addr, nil))
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Metrics != nil {
|
for name, srv := range registry.ServiceRegistry().GetAll() {
|
||||||
xmetrics.Init(xmetrics.NewMetrics())
|
srv.Close()
|
||||||
if cfg.Metrics.Addr != "" {
|
logger.Default().Debugf("service %s shutdown", name)
|
||||||
s, err := buildMetricsService(cfg.Metrics)
|
}
|
||||||
if err != nil {
|
if p.srvApi != nil {
|
||||||
log.Fatal(err)
|
p.srvApi.Close()
|
||||||
|
}
|
||||||
|
if p.srvMetric != nil {
|
||||||
|
p.srvMetric.Close()
|
||||||
|
}
|
||||||
|
if p.srvProfiling != nil {
|
||||||
|
p.srvProfiling.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *program) reload(ctx context.Context) {
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, syscall.SIGHUP)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-c:
|
||||||
|
if err := p.reloadConfig(); err != nil {
|
||||||
|
logger.Default().Error(err)
|
||||||
|
} else {
|
||||||
|
logger.Default().Info("config reloaded")
|
||||||
}
|
}
|
||||||
p.metricSrv = s
|
|
||||||
go func() {
|
case <-ctx.Done():
|
||||||
defer s.Close()
|
return
|
||||||
log.Info("metrics service on ", s.Addr())
|
|
||||||
log.Error(s.Serve())
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, svc := range buildService(cfg) {
|
func (p *program) reloadConfig() error {
|
||||||
|
cfg, err := parseConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Set(cfg)
|
||||||
|
|
||||||
|
if err := p.build(cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *program) build(cfg *config.Config) error {
|
||||||
|
logCfg := cfg.Log
|
||||||
|
if logCfg == nil {
|
||||||
|
logCfg = &config.LogConfig{}
|
||||||
|
}
|
||||||
|
logger.SetDefault(logger_parser.ParseLogger(&config.LoggerConfig{Log: logCfg}))
|
||||||
|
|
||||||
|
tlsCfg, err := parsing.BuildDefaultTLSConfig(cfg.TLS)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
parsing.SetDefaultTLSConfig(tlsCfg)
|
||||||
|
|
||||||
|
if err := register(cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, svc := range registry.ServiceRegistry().GetAll() {
|
||||||
svc := svc
|
svc := svc
|
||||||
go func() {
|
go func() {
|
||||||
svc.Serve()
|
svc.Serve()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.API != nil {
|
||||||
|
if p.srvApi != nil {
|
||||||
|
p.srvApi.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := buildAPIService(cfg.API)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.srvApi = s
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{"kind": "service", "service": "@api"})
|
||||||
|
|
||||||
|
log.Info("listening on ", s.Addr())
|
||||||
|
if err := s.Serve(); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Metrics != nil && cfg.Metrics.Addr != "" {
|
||||||
|
if p.srvMetric != nil {
|
||||||
|
p.srvMetric.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := buildMetricsService(cfg.Metrics)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.srvMetric = s
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{"kind": "service", "service": "@metrics"})
|
||||||
|
|
||||||
|
log.Info("listening on ", s.Addr())
|
||||||
|
if err := s.Serve(); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Profiling != nil {
|
||||||
|
if p.srvProfiling != nil {
|
||||||
|
p.srvProfiling.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := cfg.Profiling.Addr
|
||||||
|
if addr == "" {
|
||||||
|
addr = ":6060"
|
||||||
|
}
|
||||||
|
s := &http.Server{
|
||||||
|
Addr: addr,
|
||||||
|
}
|
||||||
|
p.srvProfiling = s
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
log := logger.Default().WithFields(map[string]any{"kind": "service", "service": "@profiling"})
|
||||||
|
|
||||||
|
log.Info("listening on ", addr)
|
||||||
|
if err := s.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *program) Stop() error {
|
|
||||||
for name, srv := range registry.ServiceRegistry().GetAll() {
|
|
||||||
srv.Close()
|
|
||||||
logger.Default().Debugf("service %s shutdown", name)
|
|
||||||
}
|
|
||||||
if p.apiSrv != nil {
|
|
||||||
p.apiSrv.Close()
|
|
||||||
}
|
|
||||||
if p.metricSrv != nil {
|
|
||||||
p.metricSrv.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *program) mergeConfig(cfg1, cfg2 *config.Config) *config.Config {
|
|
||||||
if cfg1 == nil {
|
|
||||||
return cfg2
|
|
||||||
}
|
|
||||||
if cfg2 == nil {
|
|
||||||
return cfg1
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := &config.Config{
|
|
||||||
Services: append(cfg1.Services, cfg2.Services...),
|
|
||||||
Chains: append(cfg1.Chains, cfg2.Chains...),
|
|
||||||
Hops: append(cfg1.Hops, cfg2.Hops...),
|
|
||||||
Authers: append(cfg1.Authers, cfg2.Authers...),
|
|
||||||
Admissions: append(cfg1.Admissions, cfg2.Admissions...),
|
|
||||||
Bypasses: append(cfg1.Bypasses, cfg2.Bypasses...),
|
|
||||||
Resolvers: append(cfg1.Resolvers, cfg2.Resolvers...),
|
|
||||||
Hosts: append(cfg1.Hosts, cfg2.Hosts...),
|
|
||||||
Ingresses: append(cfg1.Ingresses, cfg2.Ingresses...),
|
|
||||||
SDs: append(cfg1.SDs, cfg2.SDs...),
|
|
||||||
Recorders: append(cfg1.Recorders, cfg2.Recorders...),
|
|
||||||
Limiters: append(cfg1.Limiters, cfg2.Limiters...),
|
|
||||||
CLimiters: append(cfg1.CLimiters, cfg2.CLimiters...),
|
|
||||||
RLimiters: append(cfg1.RLimiters, cfg2.RLimiters...),
|
|
||||||
Loggers: append(cfg1.Loggers, cfg2.Loggers...),
|
|
||||||
Routers: append(cfg1.Routers, cfg2.Routers...),
|
|
||||||
Observers: append(cfg1.Observers, cfg2.Observers...),
|
|
||||||
TLS: cfg1.TLS,
|
|
||||||
Log: cfg1.Log,
|
|
||||||
API: cfg1.API,
|
|
||||||
Metrics: cfg1.Metrics,
|
|
||||||
Profiling: cfg1.Profiling,
|
|
||||||
}
|
|
||||||
if cfg2.TLS != nil {
|
|
||||||
cfg.TLS = cfg2.TLS
|
|
||||||
}
|
|
||||||
if cfg2.Log != nil {
|
|
||||||
cfg.Log = cfg2.Log
|
|
||||||
}
|
|
||||||
if cfg2.API != nil {
|
|
||||||
cfg.API = cfg2.API
|
|
||||||
}
|
|
||||||
if cfg2.Metrics != nil {
|
|
||||||
cfg.Metrics = cfg2.Metrics
|
|
||||||
}
|
|
||||||
if cfg2.Profiling != nil {
|
|
||||||
cfg.Profiling = cfg2.Profiling
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -5,8 +5,8 @@ go 1.23.0
|
||||||
toolchain go1.23.4
|
toolchain go1.23.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-gost/core v0.2.0
|
github.com/go-gost/core v0.2.1
|
||||||
github.com/go-gost/x v0.3.1
|
github.com/go-gost/x v0.4.0
|
||||||
github.com/judwhite/go-svc v1.2.1
|
github.com/judwhite/go-svc v1.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
8
go.sum
8
go.sum
|
|
@ -51,8 +51,8 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
github.com/go-gost/core v0.2.0 h1:hZf94DAv93iwKXXzGXBmspE5bExYcBJeLl6inL9mG6Y=
|
github.com/go-gost/core v0.2.1 h1:oNTeKRcuTYowzWIBEgd/YtDocxzyvsqgWpnn/Q3vuaw=
|
||||||
github.com/go-gost/core v0.2.0/go.mod h1:WGI43jOka7FAsSAwi/fSMaqxdR+E339ycb4NBGlFr6A=
|
github.com/go-gost/core v0.2.1/go.mod h1:WGI43jOka7FAsSAwi/fSMaqxdR+E339ycb4NBGlFr6A=
|
||||||
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
|
||||||
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
|
||||||
github.com/go-gost/gosocks5 v0.4.2 h1:IianxHTkACPqCwiOAT3MHoMdSUl+SEPSRu1ikawC1Pc=
|
github.com/go-gost/gosocks5 v0.4.2 h1:IianxHTkACPqCwiOAT3MHoMdSUl+SEPSRu1ikawC1Pc=
|
||||||
|
|
@ -63,8 +63,8 @@ github.com/go-gost/relay v0.5.0 h1:JG1tgy/KWiVXS0ukuVXvbM0kbYuJTWxYpJ5JwzsCf/c=
|
||||||
github.com/go-gost/relay v0.5.0/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
github.com/go-gost/relay v0.5.0/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
|
||||||
github.com/go-gost/tls-dissector v0.1.1 h1:2zUOTPzCQAUQ54Rpy0UEi3JPMQSYsIFSeFeKrzmkCoU=
|
github.com/go-gost/tls-dissector v0.1.1 h1:2zUOTPzCQAUQ54Rpy0UEi3JPMQSYsIFSeFeKrzmkCoU=
|
||||||
github.com/go-gost/tls-dissector v0.1.1/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
github.com/go-gost/tls-dissector v0.1.1/go.mod h1:/9QfdewqmHdaE362Hv5nDaSWLx3pCmtD870d6GaquXs=
|
||||||
github.com/go-gost/x v0.3.1 h1:sL4O0OwaEncMhV3XiUkB0H6sHnt6MsQn4eBWnqxJHpI=
|
github.com/go-gost/x v0.4.0 h1:Hj3bdgyfVEKR/zPLPJ4CJmfVbV8qWPqqfVWxqdS7tJ8=
|
||||||
github.com/go-gost/x v0.3.1/go.mod h1:t/wKYrBSJIKg3Z8j84jautQiP/+qROuqOx3aHbiLV7g=
|
github.com/go-gost/x v0.4.0/go.mod h1:O3FX/RzTvDLqSkU6/FmpImUSpnRRY1TlnaQKnRA3Abo=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue