mirror of
https://github.com/yusing/godoxy.git
synced 2025-06-09 04:52:35 +02:00
v0.5: (BREAKING) simplified config format, improved output formatting, fixed docker watcher
This commit is contained in:
parent
719693deb7
commit
5be8659a99
34 changed files with 165 additions and 343 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -14,3 +14,5 @@ log/
|
|||
go.work.sum
|
||||
|
||||
!src/config/
|
||||
|
||||
todo.md
|
4
go.work
4
go.work
|
@ -1,3 +1,5 @@
|
|||
go 1.22
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.22.6
|
||||
|
||||
use ./src
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -255,4 +255,4 @@ func providerGenerator[CT any, PT challenge.Provider](
|
|||
}
|
||||
}
|
||||
|
||||
var logger = logrus.WithField("?", "autocert")
|
||||
var logger = logrus.WithField("module", "autocert")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -91,4 +91,4 @@ var clientOptEnvHost = []client.Opt{
|
|||
client.WithAPIVersionNegotiation(),
|
||||
}
|
||||
|
||||
var logger = logrus.WithField("?", "docker")
|
||||
var logger = logrus.WithField("module", "docker")
|
||||
|
|
34
src/go.mod
34
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
|
||||
)
|
||||
|
|
60
src/go.sum
60
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=
|
||||
|
|
|
@ -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()
|
||||
})
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 '/'")
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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() }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -535,4 +535,4 @@ func IsPrint(s string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
var logger = logrus.WithField("?", "http")
|
||||
var logger = logrus.WithField("module", "http")
|
||||
|
|
|
@ -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])
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -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))
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -158,4 +158,4 @@ func redirectToTLSHandler(port string) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
var logger = logrus.WithField("?", "server")
|
||||
var logger = logrus.WithField("module", "server")
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -129,4 +129,4 @@ func (h *fileWatcherHelper) start() {
|
|||
}
|
||||
}
|
||||
|
||||
var fsLogger = logrus.WithField("?", "fsnotify")
|
||||
var fsLogger = logrus.WithField("module", "fsnotify")
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.5.0-beta2
|
||||
0.5.0-beta4
|
Loading…
Add table
Reference in a new issue