diff --git a/.gitignore b/.gitignore index 8b9f0b7..98bed52 100755 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ log/ go.work.sum -!src/config/ \ No newline at end of file +!src/config/ + +todo.md \ No newline at end of file diff --git a/go.work b/go.work index 493fee9..9583605 100644 --- a/go.work +++ b/go.work @@ -1,3 +1,5 @@ -go 1.22 +go 1.22.0 + +toolchain go1.22.6 use ./src diff --git a/schema/providers.schema.json b/schema/providers.schema.json index 87ff679..b31ef53 100644 --- a/schema/providers.schema.json +++ b/schema/providers.schema.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "go-proxy providers file", - "anyOf": [ + "oneOf": [ { "type": "object" }, @@ -16,7 +16,7 @@ "properties": { "scheme": { "title": "Proxy scheme (http, https, tcp, udp)", - "anyOf": [ + "oneOf": [ { "type": "string", "enum": [ @@ -101,7 +101,7 @@ "then": { "properties": { "port": { - "anyOf": [ + "oneOf": [ { "type": "string", "pattern": "^[0-9]{1,5}$", @@ -118,7 +118,7 @@ ] }, "path": { - "anyOf": [ + "oneOf": [ { "type": "string", "description": "Proxy path" diff --git a/src/api/v1/checkhealth.go b/src/api/v1/checkhealth.go index ae11d8b..cead95f 100644 --- a/src/api/v1/checkhealth.go +++ b/src/api/v1/checkhealth.go @@ -6,6 +6,7 @@ import ( U "github.com/yusing/go-proxy/api/v1/utils" "github.com/yusing/go-proxy/config" + PT "github.com/yusing/go-proxy/proxy/fields" R "github.com/yusing/go-proxy/route" ) @@ -23,20 +24,20 @@ func CheckHealth(cfg *config.Config, w http.ResponseWriter, r *http.Request) { U.HandleErr(w, r, U.ErrNotFound("target", target), http.StatusNotFound) return case *R.HTTPRoute: - path := r.FormValue("path") - if path == "" { - U.HandleErr(w, r, U.ErrMissingKey("path"), http.StatusBadRequest) + path, err := PT.NewPath(r.FormValue("path")) + if err.IsNotNil() { + U.HandleErr(w, r, err, http.StatusBadRequest) return } sr, hasSr := route.GetSubroute(path) if !hasSr { - U.HandleErr(w, r, U.ErrNotFound("path", path), http.StatusNotFound) + U.HandleErr(w, r, U.ErrNotFound("path", string(path)), http.StatusNotFound) return } ok = U.IsSiteHealthy(sr.TargetURL.String()) case *R.StreamRoute: ok = U.IsStreamHealthy( - route.Scheme.ProxyScheme.String(), + string(route.Scheme.ProxyScheme), fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort), ) } diff --git a/src/api/v1/utils/error.go b/src/api/v1/utils/error.go index 4f644fa..ae5b9b4 100644 --- a/src/api/v1/utils/error.go +++ b/src/api/v1/utils/error.go @@ -11,7 +11,7 @@ import ( func HandleErr(w http.ResponseWriter, r *http.Request, err error, code ...int) { err = E.From(err).Subjectf("%s %s", r.Method, r.URL) - logrus.WithField("?", "api").Error(err) + logrus.WithField("module", "api").Error(err) if len(code) > 0 { http.Error(w, err.Error(), code[0]) return diff --git a/src/autocert/constants.go b/src/autocert/constants.go index 96d80de..72129bc 100644 --- a/src/autocert/constants.go +++ b/src/autocert/constants.go @@ -28,4 +28,4 @@ var providersGenMap = map[string]ProviderGenerator{ ProviderDuckdns: providerGenerator(duckdns.NewDefaultConfig, duckdns.NewDNSProviderConfig), } -var Logger = logrus.WithField("?", "autocert") +var Logger = logrus.WithField("module", "autocert") diff --git a/src/autocert/provider.go b/src/autocert/provider.go index 120a24b..5212815 100644 --- a/src/autocert/provider.go +++ b/src/autocert/provider.go @@ -255,4 +255,4 @@ func providerGenerator[CT any, PT challenge.Provider]( } } -var logger = logrus.WithField("?", "autocert") +var logger = logrus.WithField("module", "autocert") diff --git a/src/config/config.go b/src/config/config.go index 3f2c432..f1b7314 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -32,14 +32,15 @@ type Config struct { func New() (*Config, E.NestedError) { cfg := &Config{ - l: logrus.WithField("?", "config"), + l: logrus.WithField("module", "config"), reader: U.NewFileReader(common.ConfigPath), watcher: W.NewFileWatcher(common.ConfigFileName), - reloadReq: make(chan struct{}), + reloadReq: make(chan struct{}, 1), } if err := cfg.load(); err.IsNotNil() { return nil, err } + cfg.startProviders() cfg.watchChanges() return cfg, E.Nil() } @@ -200,7 +201,7 @@ func (cfg *Config) load() E.NestedError { } } - warnings := E.NewBuilder("errors validating config") + warnings := E.NewBuilder("errors loading config") cfg.l.Debug("starting autocert") ap, err := autocert.NewConfig(&model.AutoCert).GetProvider() @@ -211,7 +212,7 @@ func (cfg *Config) load() E.NestedError { } cfg.autocertProvider = ap - cfg.l.Debug("starting providers") + cfg.l.Debug("loading providers") cfg.proxyProviders = F.NewMap[string, *PR.Provider]() for _, filename := range model.Providers.Files { p := PR.NewFileProvider(filename) @@ -221,12 +222,7 @@ func (cfg *Config) load() E.NestedError { p := PR.NewDockerProvider(name, dockerHost) cfg.proxyProviders.Set(p.GetName(), p) } - cfg.proxyProviders.EachKV(func(name string, p *PR.Provider) { - if err := p.StartAllRoutes(); err.IsNotNil() { - warnings.Add(E.Failure("start routes").Subject(p).With(err)) - } - }) - cfg.l.Debug("started providers") + cfg.l.Debug("loaded providers") cfg.value = model @@ -257,5 +253,5 @@ func (cfg *Config) startProviders() { } func (cfg *Config) stopProviders() { - cfg.controlProviders("stop", (*PR.Provider).StopAllRoutes) + cfg.controlProviders("stop routes", (*PR.Provider).StopAllRoutes) } diff --git a/src/docker/client.go b/src/docker/client.go index a3e1ba3..4da3473 100644 --- a/src/docker/client.go +++ b/src/docker/client.go @@ -91,4 +91,4 @@ var clientOptEnvHost = []client.Opt{ client.WithAPIVersionNegotiation(), } -var logger = logrus.WithField("?", "docker") +var logger = logrus.WithField("module", "docker") diff --git a/src/go.mod b/src/go.mod index cf78707..a5562a6 100644 --- a/src/go.mod +++ b/src/go.mod @@ -1,22 +1,24 @@ module github.com/yusing/go-proxy -go 1.22 +go 1.22.0 + +toolchain go1.22.6 require ( - github.com/docker/cli v27.1.2+incompatible - github.com/docker/docker v27.1.2+incompatible + github.com/docker/cli v27.2.1+incompatible + github.com/docker/docker v27.2.1+incompatible github.com/fsnotify/fsnotify v1.7.0 - github.com/go-acme/lego/v4 v4.17.4 + github.com/go-acme/lego/v4 v4.18.0 github.com/santhosh-tekuri/jsonschema v1.2.4 github.com/sirupsen/logrus v1.9.3 - golang.org/x/net v0.28.0 + golang.org/x/net v0.29.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/Microsoft/go-winio v0.6.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cloudflare/cloudflare-go v0.101.0 // indirect + github.com/cloudflare/cloudflare-go v0.104.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.5.0 // indirect @@ -28,25 +30,25 @@ require ( github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/miekg/dns v1.1.61 // indirect + github.com/miekg/dns v1.1.62 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/mod v0.20.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.25.0 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/src/go.sum b/src/go.sum index cd58fde..fff00c8 100644 --- a/src/go.sum +++ b/src/go.sum @@ -4,8 +4,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cloudflare/cloudflare-go v0.101.0 h1:SXWNSEDkbdY84iFIZGyTdWQwDfd98ljv0/4UubpleBQ= -github.com/cloudflare/cloudflare-go v0.101.0/go.mod h1:xXQHnoXKR48JlWbFS42i2al3nVqimVhcYvKnIdXLw9g= +github.com/cloudflare/cloudflare-go v0.104.0 h1:R/lB0dZupaZbOgibAH/BRrkFbZ6Acn/WsKg2iX2xXuY= +github.com/cloudflare/cloudflare-go v0.104.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -13,10 +13,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v27.1.2+incompatible h1:nYviRv5Y+YAKx3dFrTvS1ErkyVVunKOhoweCTE1BsnI= -github.com/docker/cli v27.1.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.1.2+incompatible h1:AhGzR1xaQIy53qCkxARaFluI00WPGtXn0AJuoQsVYTY= -github.com/docker/docker v27.1.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= +github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v27.2.1+incompatible h1:fQdiLfW7VLscyoeYEBz7/J8soYFDZV1u6VW6gJEjNMI= +github.com/docker/docker v27.2.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -25,8 +25,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q= -github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U= +github.com/go-acme/lego/v4 v4.18.0 h1:2hH8KcdRBSb+p5o9VZIm61GAOXYALgILUCSs1Q+OYsk= +github.com/go-acme/lego/v4 v4.18.0/go.mod h1:Blkg3izvXpl3zxk7WKngIuwR2I/hvYVP3vRnvgBp7m8= github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -51,8 +51,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= -github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= +github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= +github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= @@ -79,37 +79,37 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0/go.mod h1:6KW1Fm6R/s6Z3PGXwSJN2K4eT6wQB3vXX6CVnYX9NmM= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -119,20 +119,20 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/main.go b/src/main.go index 4b549b0..fb35c2b 100755 --- a/src/main.go +++ b/src/main.go @@ -20,13 +20,14 @@ import ( R "github.com/yusing/go-proxy/route" "github.com/yusing/go-proxy/server" F "github.com/yusing/go-proxy/utils/functional" + W "github.com/yusing/go-proxy/watcher" ) func main() { runtime.GOMAXPROCS(runtime.NumCPU()) args := common.GetArgs() - l := logrus.WithField("?", "init") + l := logrus.WithField("module", "main") if common.IsDebug { logrus.SetLevel(logrus.DebugLevel) @@ -69,6 +70,7 @@ func main() { onShutdown.Add(func() { docker.CloseAllClients() + W.StopAllFileWatchers() cfg.Dispose() }) diff --git a/src/proxy/entry.go b/src/proxy/entry.go index df3f484..2f11954 100644 --- a/src/proxy/entry.go +++ b/src/proxy/entry.go @@ -1,9 +1,9 @@ package proxy import ( + "fmt" "net/http" "net/url" - "strconv" E "github.com/yusing/go-proxy/error" M "github.com/yusing/go-proxy/models" @@ -39,7 +39,7 @@ func NewEntry(m *M.ProxyEntry) (any, E.NestedError) { if scheme.IsStream() { return validateStreamEntry(m) } - return validateEntry(m, *scheme) + return validateEntry(m, scheme) } func validateEntry(m *M.ProxyEntry, s T.Scheme) (*Entry, E.NestedError) { @@ -55,7 +55,7 @@ func validateEntry(m *M.ProxyEntry, s T.Scheme) (*Entry, E.NestedError) { if err.IsNotNil() { return nil, err } - url, err := E.Check(url.Parse(s.String() + "://" + host.String() + ":" + strconv.Itoa(int(port)))) + url, err := E.Check(url.Parse(fmt.Sprintf("%s://%s:%d", s, host, port))) if err.IsNotNil() { return nil, err } diff --git a/src/proxy/fields/alias.go b/src/proxy/fields/alias.go index d91beff..3b56810 100644 --- a/src/proxy/fields/alias.go +++ b/src/proxy/fields/alias.go @@ -6,11 +6,11 @@ import ( F "github.com/yusing/go-proxy/utils/functional" ) -type Alias struct{ F.Stringable } +type Alias string type Aliases struct{ *F.Slice[Alias] } func NewAlias(s string) Alias { - return Alias{F.NewStringable(s)} + return Alias(s) } func NewAliases(s string) Aliases { diff --git a/src/proxy/fields/host.go b/src/proxy/fields/host.go index 38bb325..dda158c 100644 --- a/src/proxy/fields/host.go +++ b/src/proxy/fields/host.go @@ -2,19 +2,11 @@ package fields import ( E "github.com/yusing/go-proxy/error" - F "github.com/yusing/go-proxy/utils/functional" ) -type Host struct{ F.Stringable } +type Host string type Subdomain = Alias func NewHost(s string) (Host, E.NestedError) { - return Host{F.NewStringable(s)}, E.Nil() -} - -func (h Host) Subdomain() (*Subdomain, E.NestedError) { - if i := h.IndexRune(':'); i != -1 { - return &Subdomain{h.SubStr(0, i)}, E.Nil() - } - return nil, E.Invalid("host", h) + return Host(s), E.Nil() } diff --git a/src/proxy/fields/path.go b/src/proxy/fields/path.go index 115871e..ef38444 100644 --- a/src/proxy/fields/path.go +++ b/src/proxy/fields/path.go @@ -2,14 +2,13 @@ package fields import ( E "github.com/yusing/go-proxy/error" - F "github.com/yusing/go-proxy/utils/functional" ) -type Path struct{ F.Stringable } +type Path string func NewPath(s string) (Path, E.NestedError) { if s == "" || s[0] == '/' { - return Path{F.NewStringable(s)}, E.Nil() + return Path(s), E.Nil() } - return Path{}, E.Invalid("path", s).With("must be empty or start with '/'") + return "", E.Invalid("path", s).With("must be empty or start with '/'") } diff --git a/src/proxy/fields/path_mode.go b/src/proxy/fields/path_mode.go index 7a72754..f632cf9 100644 --- a/src/proxy/fields/path_mode.go +++ b/src/proxy/fields/path_mode.go @@ -1,25 +1,24 @@ package fields import ( - F "github.com/yusing/go-proxy/utils/functional" E "github.com/yusing/go-proxy/error" ) -type PathMode struct{ F.Stringable } +type PathMode string func NewPathMode(pm string) (PathMode, E.NestedError) { switch pm { case "", "forward": - return PathMode{F.NewStringable(pm)}, E.Nil() + return PathMode(pm), E.Nil() default: - return PathMode{}, E.Invalid("path mode", pm) + return "", E.Invalid("path mode", pm) } } func (p PathMode) IsRemove() bool { - return p.String() == "" + return p == "" } func (p PathMode) IsForward() bool { - return p.String() == "forward" + return p == "forward" } diff --git a/src/proxy/fields/scheme.go b/src/proxy/fields/scheme.go index d2e667c..f0dc510 100644 --- a/src/proxy/fields/scheme.go +++ b/src/proxy/fields/scheme.go @@ -4,20 +4,19 @@ import ( "strings" E "github.com/yusing/go-proxy/error" - F "github.com/yusing/go-proxy/utils/functional" ) -type Scheme struct{ F.Stringable } +type Scheme string -func NewScheme(s string) (*Scheme, E.NestedError) { +func NewScheme(s string) (Scheme, E.NestedError) { switch s { case "http", "https", "tcp", "udp": - return &Scheme{F.NewStringable(s)}, E.Nil() + return Scheme(s), E.Nil() } - return nil, E.Invalid("scheme", s) + return "", E.Invalid("scheme", s) } -func NewSchemeFromPort(p string) (*Scheme, E.NestedError) { +func NewSchemeFromPort(p string) (Scheme, E.NestedError) { var s string switch { case strings.ContainsRune(p, ':'): @@ -27,11 +26,11 @@ func NewSchemeFromPort(p string) (*Scheme, E.NestedError) { default: s = "http" } - return &Scheme{F.NewStringable(s)}, E.Nil() + return Scheme(s), E.Nil() } -func (s Scheme) IsHTTP() bool { return s.String() == "http" } -func (s Scheme) IsHTTPS() bool { return s.String() == "https" } -func (s Scheme) IsTCP() bool { return s.String() == "tcp" } -func (s Scheme) IsUDP() bool { return s.String() == "udp" } +func (s Scheme) IsHTTP() bool { return s == "http" } +func (s Scheme) IsHTTPS() bool { return s == "https" } +func (s Scheme) IsTCP() bool { return s == "tcp" } +func (s Scheme) IsUDP() bool { return s == "udp" } func (s Scheme) IsStream() bool { return s.IsTCP() || s.IsUDP() } diff --git a/src/proxy/fields/stream_scheme.go b/src/proxy/fields/stream_scheme.go index 0ecfe2a..adc214d 100644 --- a/src/proxy/fields/stream_scheme.go +++ b/src/proxy/fields/stream_scheme.go @@ -1,14 +1,15 @@ package fields import ( + "fmt" "strings" E "github.com/yusing/go-proxy/error" ) type StreamScheme struct { - ListeningScheme *Scheme `json:"listening"` - ProxyScheme *Scheme `json:"proxy"` + ListeningScheme Scheme `json:"listening"` + ProxyScheme Scheme `json:"proxy"` } func NewStreamScheme(s string) (ss *StreamScheme, err E.NestedError) { @@ -31,12 +32,12 @@ func NewStreamScheme(s string) (ss *StreamScheme, err E.NestedError) { } func (s StreamScheme) String() string { - return s.ListeningScheme.String() + " -> " + s.ProxyScheme.String() + return fmt.Sprintf("%s -> %s", s.ListeningScheme, s.ProxyScheme) } // IsCoherent checks if the ListeningScheme and ProxyScheme of the StreamScheme are equal. // // It returns a boolean value indicating whether the ListeningScheme and ProxyScheme are equal. func (s StreamScheme) IsCoherent() bool { - return *s.ListeningScheme == *s.ProxyScheme + return s.ListeningScheme == s.ProxyScheme } diff --git a/src/proxy/provider/docker_provider.go b/src/proxy/provider/docker_provider.go index 2512bc6..6557985 100755 --- a/src/proxy/provider/docker_provider.go +++ b/src/proxy/provider/docker_provider.go @@ -100,8 +100,8 @@ func (p *DockerProvider) getEntriesFromLabels(container *types.Container, client // init entries map for all aliases aliases.ForEach(func(a PT.Alias) { - entries.Set(a.String(), &M.ProxyEntry{ - Alias: a.String(), + entries.Set(string(a), &M.ProxyEntry{ + Alias: string(a), Host: clientHost, Port: fmt.Sprint(defaultPort), }) diff --git a/src/proxy/provider/provider.go b/src/proxy/provider/provider.go index 298914a..55ed41a 100644 --- a/src/proxy/provider/provider.go +++ b/src/proxy/provider/provider.go @@ -40,13 +40,15 @@ const ( ) func newProvider(name string, t ProviderType) *Provider { - return &Provider{ + p := &Provider{ name: name, t: t, routes: R.NewRoutes(), reloadReqCh: make(chan struct{}, 1), - l: logrus.WithField("provider", name), } + p.l = logrus.WithField("provider", p) + + return p } func NewFileProvider(filename string) *Provider { name := path.Base(filename) @@ -72,7 +74,7 @@ func (p *Provider) GetType() ProviderType { } func (p *Provider) String() string { - return fmt.Sprintf("%s (%s provider)", p.name, p.t) + return fmt.Sprintf("%s: %s", p.t, p.name) } func (p *Provider) StartAllRoutes() E.NestedError { @@ -103,25 +105,22 @@ func (p *Provider) StartAllRoutes() E.NestedError { } func (p *Provider) StopAllRoutes() E.NestedError { - defer p.routes.Clear() - if p.watcherCancel != nil { p.watcherCancel() } errors := E.NewBuilder("errors stopping routes for provider %q", p.name) nStopped := 0 + nFailed := 0 p.routes.EachKVParallel(func(alias string, r R.Route) { if err := r.Stop(); err.IsNotNil() { errors.Add(err.Subject(r)) + nFailed++ } else { nStopped++ } }) - if err := errors.Build(); err.IsNotNil() { - return err - } - p.l.Infof("%d routes stopped", nStopped) - return E.Nil() + p.l.Infof("%d routes stopped, %d failed", nStopped, nFailed) + return errors.Build() } func (p *Provider) ReloadRoutes() { @@ -146,7 +145,7 @@ func (p *Provider) GetCurrentRoutes() *R.Routes { func (p *Provider) watchEvents() { events, errs := p.watcher.Events(p.watcherCtx) - l := logrus.WithField("?", "watcher") + l := p.l.WithField("module", "watcher") for { select { @@ -156,12 +155,15 @@ func (p *Provider) watchEvents() { if !ok { return } - l.Infof("watcher event: %v", event) + l.Infof("watcher event: %s", event) p.reloadReqCh <- struct{}{} case err, ok := <-errs: if !ok { return } + if err.Is(context.Canceled) { + continue + } l.Errorf("watcher error: %s", err) } } @@ -175,17 +177,15 @@ func (p *Provider) loadRoutes() E.NestedError { } p.routes = R.NewRoutes() - errors := E.NewBuilder("errors loading routes from provider %q", p.name) + errors := E.NewBuilder("errors loading routes from %s", p) entries.EachKV(func(a string, e *M.ProxyEntry) { e.Alias = a r, err := R.NewRoute(e) if err.IsNotNil() { errors.Add(err.Subject(a)) - p.l.Debugf("failed to load route: %s, %s", a, err) } else { p.routes.Set(a, r) } }) - p.l.Debugf("loaded %d routes from %d entries", p.routes.Size(), entries.Size()) return errors.Build() } diff --git a/src/proxy/reverse_proxy_mod.go b/src/proxy/reverse_proxy_mod.go index 09d72c2..e5d23c5 100644 --- a/src/proxy/reverse_proxy_mod.go +++ b/src/proxy/reverse_proxy_mod.go @@ -535,4 +535,4 @@ func IsPrint(s string) bool { return true } -var logger = logrus.WithField("?", "http") +var logger = logrus.WithField("module", "http") diff --git a/src/proxy/reverse_proxy_mod_test.go b/src/proxy/reverse_proxy_mod_test.go deleted file mode 100644 index 9ac0a0f..0000000 --- a/src/proxy/reverse_proxy_mod_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package proxy - -// import ( -// "net/http" -// "net/url" -// "os" -// "reflect" -// "testing" -// "time" -// ) - -// var proxy Entry -// var proxyUrl, _ = url.Parse("http://127.0.0.1:8181") -// var proxyServer = NewServer(ServerOptions{ -// Name: "proxy", -// HTTPAddr: ":8080", -// Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// NewReverseProxy(proxyUrl, &http.Transport{}, &proxy).ServeHTTP(w, r) -// }), -// }) - -// var testServer = NewServer(ServerOptions{ -// Name: "test", -// HTTPAddr: ":8181", -// Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -// h := r.Header -// for k, vv := range h { -// for _, v := range vv { -// w.Header().Add(k, v) -// } -// } -// w.WriteHeader(http.StatusOK) -// }), -// }) - -// var httpClient = http.DefaultClient - -// func TestMain(m *testing.M) { -// proxyServer.Start() -// testServer.Start() -// time.Sleep(100 * time.Millisecond) -// code := m.Run() -// proxyServer.Stop() -// testServer.Stop() -// os.Exit(code) -// } - -// func TestSetHeader(t *testing.T) { -// hWant := http.Header{"X-Test": []string{"foo", "bar"}, "X-Test2": []string{"baz"}} -// proxy = Entry{ -// Alias: "test", -// Scheme: "http", -// Host: "127.0.0.1", -// Port: "8181", -// SetHeaders: hWant, -// } -// req, err := http.NewRequest("HEAD", "http://127.0.0.1:8080", nil) -// if err != nil { -// t.Fatal(err) -// } -// resp, err := httpClient.Do(req) -// if err != nil { -// t.Fatal(err) -// } -// hGot := resp.Header -// t.Log("headers: ", hGot) -// for k, v := range hWant { -// if !reflect.DeepEqual(hGot[k], v) { -// t.Errorf("header %s: expected %v, got %v", k, v, hGot[k]) -// } -// } -// } - -// func TestHideHeader(t *testing.T) { -// hHide := []string{"X-Test", "X-Test2"} -// proxy = Entry{ -// Alias: "test", -// Scheme: "http", -// Host: "127.0.0.1", -// Port: "8181", -// HideHeaders: hHide, -// } -// req, err := http.NewRequest("HEAD", "http://127.0.0.1:8080", nil) -// for _, k := range hHide { -// req.Header.Set(k, "foo") -// } -// if err != nil { -// t.Fatal(err) -// } -// resp, err := httpClient.Do(req) -// if err != nil { -// t.Fatal(err) -// } -// hGot := resp.Header -// t.Log("headers: ", hGot) -// for _, v := range hHide { -// _, ok := hGot[v] -// if ok { -// t.Errorf("header %s: expected hidden, got %v", v, hGot[v]) -// } -// } -// } diff --git a/src/route/http_route.go b/src/route/http_route.go index 8c35e25..740062e 100755 --- a/src/route/http_route.go +++ b/src/route/http_route.go @@ -26,17 +26,15 @@ type ( } HTTPSubroute struct { - TargetURL URL `json:"targetURL"` + TargetURL *URL `json:"targetURL"` Path PathKey `json:"path"` proxy *P.ReverseProxy } - URL struct { - *url.URL - } - PathKey = string - SubdomainKey = string + URL url.URL + PathKey = PT.Path + SubdomainKey = PT.Alias HTTPSubroutes = map[PathKey]HTTPSubroute ) @@ -53,25 +51,25 @@ func NewHTTPRoute(entry *P.Entry) (*HTTPRoute, E.NestedError) { rp := P.NewReverseProxy(entry.URL, tr, entry) httpRoutes.Lock() + defer httpRoutes.Unlock() + var r *HTTPRoute - r, ok := httpRoutes.UnsafeGet(entry.Alias.String()) + r, ok := httpRoutes.UnsafeGet(entry.Alias) if !ok { r = &HTTPRoute{ Alias: entry.Alias, Subroutes: make(HTTPSubroutes), mux: http.NewServeMux(), } - httpRoutes.UnsafeSet(entry.Alias.String(), r) + httpRoutes.UnsafeSet(entry.Alias, r) } - path := entry.Path.String() + path := entry.Path if _, exists := r.Subroutes[path]; exists { - httpRoutes.Unlock() return nil, E.Duplicated("path", path) } - r.mux.HandleFunc(path, rp.ServeHTTP) + r.mux.HandleFunc(string(path), rp.ServeHTTP) if err := recover(); err != nil { - httpRoutes.Unlock() switch t := err.(type) { case error: // NOTE: likely path pattern error @@ -82,7 +80,7 @@ func NewHTTPRoute(entry *P.Entry) (*HTTPRoute, E.NestedError) { } sr := HTTPSubroute{ - TargetURL: URL{entry.URL}, + TargetURL: (*URL)(entry.URL), proxy: rp, Path: path, } @@ -102,21 +100,20 @@ func NewHTTPRoute(entry *P.Entry) (*HTTPRoute, E.NestedError) { } r.Subroutes[path] = sr - httpRoutes.Unlock() return r, E.Nil() } func (r *HTTPRoute) String() string { - return fmt.Sprintf("%s (reverse proxy)", r.Alias) + return string(r.Alias) } func (r *HTTPRoute) Start() E.NestedError { - httpRoutes.Set(r.Alias.String(), r) + httpRoutes.Set(r.Alias, r) return E.Nil() } func (r *HTTPRoute) Stop() E.NestedError { - httpRoutes.Delete(r.Alias.String()) + httpRoutes.Delete(r.Alias) return E.Nil() } @@ -125,7 +122,11 @@ func (r *HTTPRoute) GetSubroute(path PathKey) (HTTPSubroute, bool) { return sr, ok } -func (u URL) MarshalText() (text []byte, err error) { +func (u *URL) String() string { + return (*url.URL)(u).String() +} + +func (u *URL) MarshalText() (text []byte, err error) { return []byte(u.String()), nil } @@ -144,7 +145,7 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) { func findMux(host string, path PathKey) (*http.ServeMux, error) { sd := strings.Split(host, ".")[0] - if r, ok := httpRoutes.UnsafeGet(sd); ok { + if r, ok := httpRoutes.UnsafeGet(PT.Alias(sd)); ok { return r.mux, nil } return nil, E.NotExists("route", fmt.Sprintf("subdomain: %s, path: %s", sd, path)) diff --git a/src/route/stream_route.go b/src/route/stream_route.go index 1ac2154..7078cb5 100755 --- a/src/route/stream_route.go +++ b/src/route/stream_route.go @@ -39,18 +39,18 @@ func NewStreamRoute(entry *P.StreamEntry) (*StreamRoute, E.NestedError) { wg: sync.WaitGroup{}, stopCh: make(chan struct{}, 1), connCh: make(chan any), - l: logger.WithField("alias", entry.Alias), } if entry.Scheme.ListeningScheme.IsTCP() { base.StreamImpl = NewTCPRoute(base) } else { base.StreamImpl = NewUDPRoute(base) } + base.l = logrus.WithField("route", base.StreamImpl) return base, E.Nil() } func (r *StreamRoute) String() string { - return fmt.Sprintf("%s (%v stream)", r.Alias, r.Scheme) + return fmt.Sprintf("%s-stream: %s", r.Scheme, r.Alias) } func (r *StreamRoute) Start() E.NestedError { @@ -131,5 +131,3 @@ func (r *StreamRoute) grHandleConnections() { } } } - -var logger = logrus.WithField("?", "stream") diff --git a/src/route/tcp_route.go b/src/route/tcp_route.go index 4ee3c77..0f25bd2 100755 --- a/src/route/tcp_route.go +++ b/src/route/tcp_route.go @@ -53,7 +53,7 @@ func (route *TCPRoute) Handle(c interface{}) error { serverAddr := fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort) dialer := &net.Dialer{} - serverConn, err := dialer.DialContext(ctx, route.Scheme.ProxyScheme.String(), serverAddr) + serverConn, err := dialer.DialContext(ctx, string(route.Scheme.ProxyScheme), serverAddr) if err != nil { return err } diff --git a/src/route/udp_route.go b/src/route/udp_route.go index 2259897..1b69a0a 100755 --- a/src/route/udp_route.go +++ b/src/route/udp_route.go @@ -36,15 +36,15 @@ func NewUDPRoute(base *StreamRoute) StreamImpl { } func (route *UDPRoute) Setup() error { - laddr, err := net.ResolveUDPAddr(route.Scheme.ListeningScheme.String(), fmt.Sprintf(":%v", route.Port.ProxyPort)) + laddr, err := net.ResolveUDPAddr(string(route.Scheme.ListeningScheme), fmt.Sprintf(":%v", route.Port.ProxyPort)) if err != nil { return err } - source, err := net.ListenUDP(route.Scheme.ListeningScheme.String(), laddr) + source, err := net.ListenUDP(string(route.Scheme.ListeningScheme), laddr) if err != nil { return err } - raddr, err := net.ResolveUDPAddr(route.Scheme.ProxyScheme.String(), fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort)) + raddr, err := net.ResolveUDPAddr(string(route.Scheme.ProxyScheme), fmt.Sprintf("%s:%v", route.Host, route.Port.ProxyPort)) if err != nil { source.Close() return err diff --git a/src/server/server.go b/src/server/server.go index 4d44d33..e99b901 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -158,4 +158,4 @@ func redirectToTLSHandler(port string) http.HandlerFunc { } } -var logger = logrus.WithField("?", "server") +var logger = logrus.WithField("module", "server") diff --git a/src/utils/functional/stringable.go b/src/utils/functional/stringable.go deleted file mode 100644 index a223301..0000000 --- a/src/utils/functional/stringable.go +++ /dev/null @@ -1,68 +0,0 @@ -package functional - -import ( - "fmt" - "strconv" - "strings" -) - -type Stringable struct{ string } - -func NewStringable(v any) Stringable { - switch vv := v.(type) { - case string: - return Stringable{vv} - case fmt.Stringer: - return Stringable{vv.String()} - default: - return Stringable{fmt.Sprint(vv)} - } -} - -func (s Stringable) String() string { - return s.string -} - -func (s Stringable) Len() int { - return len(s.string) -} - -func (s Stringable) MarshalText() (text []byte, err error) { - return []byte(s.string), nil -} - -func (s Stringable) SubStr(start int, end int) Stringable { - return Stringable{s.string[start:end]} -} - -func (s Stringable) HasPrefix(p Stringable) bool { - return len(s.string) >= len(p.string) && s.string[0:len(p.string)] == p.string -} - -func (s Stringable) HasSuffix(p Stringable) bool { - return len(s.string) >= len(p.string) && s.string[len(s.string)-len(p.string):] == p.string -} - -func (s Stringable) IsEmpty() bool { - return len(s.string) == 0 -} - -func (s Stringable) IndexRune(r rune) int { - return strings.IndexRune(s.string, r) -} - -func (s Stringable) ToInt() (int, error) { - return strconv.Atoi(s.string) -} - -func (s Stringable) Split(sep string) []Stringable { - return Stringables(strings.Split(s.string, sep)) -} - -func Stringables(ss []string) []Stringable { - ret := make([]Stringable, len(ss)) - for i, s := range ss { - ret[i] = Stringable{s} - } - return ret -} diff --git a/src/watcher/docker_watcher.go b/src/watcher/docker_watcher.go index e0fc2fb..63433a9 100644 --- a/src/watcher/docker_watcher.go +++ b/src/watcher/docker_watcher.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/events" "github.com/docker/docker/api/types/filters" D "github.com/yusing/go-proxy/docker" E "github.com/yusing/go-proxy/error" @@ -30,14 +30,14 @@ func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Nest var err E.NestedError for range 3 { cl, err = D.ConnectClient(w.host) - if err.IsNotNil() { + if err.IsNil() { break } errCh <- E.From(err) time.Sleep(1 * time.Second) } if err.IsNotNil() { - errCh <- E.Failure("connect to docker") + errCh <- E.Failure("connecting to docker") return } @@ -50,14 +50,8 @@ func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Nest errCh <- E.From(<-cErrCh) return case msg := <-cEventCh: - containerName, ok := msg.Actor.Attributes["name"] - if !ok { - // NOTE: should not happen - // but if it happens, just ignore it - continue - } eventCh <- Event{ - ActorName: containerName, + ActorName: msg.Actor.Attributes["name"], Action: ActionModified, } case err := <-cErrCh: @@ -79,7 +73,7 @@ func (w *DockerWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.Nest return eventCh, errCh } -var dwOptions = types.EventsOptions{Filters: filters.NewArgs( +var dwOptions = events.ListOptions{Filters: filters.NewArgs( filters.Arg("type", "container"), filters.Arg("event", "start"), filters.Arg("event", "die"), // 'stop' already triggering 'die' diff --git a/src/watcher/event.go b/src/watcher/event.go index d7b4a34..ec0a6fa 100644 --- a/src/watcher/event.go +++ b/src/watcher/event.go @@ -16,7 +16,7 @@ const ( ActionCreated Action = "CREATED" ) -func (e *Event) String() string { +func (e Event) String() string { return fmt.Sprintf("%s %s", e.ActorName, e.Action) } diff --git a/src/watcher/file_watcher.go b/src/watcher/file_watcher.go index a871a11..f8f633c 100644 --- a/src/watcher/file_watcher.go +++ b/src/watcher/file_watcher.go @@ -18,6 +18,10 @@ func NewFileWatcher(filename string) Watcher { return &fileWatcher{filename: filename} } +func StopAllFileWatchers() { + fwHelper.close() +} + func (f *fileWatcher) Events(ctx context.Context) (<-chan Event, <-chan E.NestedError) { return fwHelper.Add(ctx, f) } diff --git a/src/watcher/file_watcher_helper.go b/src/watcher/file_watcher_helper.go index cb00cd8..a98fcc5 100644 --- a/src/watcher/file_watcher_helper.go +++ b/src/watcher/file_watcher_helper.go @@ -129,4 +129,4 @@ func (h *fileWatcherHelper) start() { } } -var fsLogger = logrus.WithField("?", "fsnotify") +var fsLogger = logrus.WithField("module", "fsnotify") diff --git a/version.txt b/version.txt index 1ca90c1..cfd6941 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.5.0-beta2 \ No newline at end of file +0.5.0-beta4 \ No newline at end of file