mirror of
https://github.com/yusing/godoxy.git
synced 2026-01-15 23:03:50 +01:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abe81541db | ||
|
|
9e5d33714c | ||
|
|
93a81fd558 | ||
|
|
72923b8cfa | ||
|
|
24ba4c2a46 | ||
|
|
ed07bf42ce | ||
|
|
371e756307 | ||
|
|
32d8292b17 | ||
|
|
717fd0e58c | ||
|
|
2628d9e8a8 | ||
|
|
c90795e614 | ||
|
|
4a6bed7728 |
@@ -16,7 +16,7 @@ require (
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/yusing/go-proxy v0.0.0-00010101000000-000000000000
|
||||
github.com/yusing/go-proxy v0.13.6
|
||||
github.com/yusing/go-proxy/internal/utils v0.0.0
|
||||
github.com/yusing/go-proxy/socketproxy v0.0.0-00010101000000-000000000000
|
||||
)
|
||||
@@ -33,8 +33,8 @@ require (
|
||||
github.com/diskfs/go-diskfs v1.6.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/djherbis/times v1.6.0 // indirect
|
||||
github.com/docker/cli v28.1.1+incompatible // indirect
|
||||
github.com/docker/docker v28.1.1+incompatible // indirect
|
||||
github.com/docker/cli v28.2.1+incompatible // indirect
|
||||
github.com/docker/docker v28.2.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
@@ -46,7 +46,7 @@ require (
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20250501235452-c0086092b71a // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
|
||||
20
agent/go.sum
20
agent/go.sum
@@ -29,8 +29,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.2.1+incompatible h1:AYyTcuwvhl9dXdyCiXlOGXiIqSNYzTmaDNpxIISPGsM=
|
||||
github.com/docker/cli v28.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
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=
|
||||
@@ -45,8 +45,8 @@ github.com/go-acme/lego/v4 v4.23.1 h1:lZ5fGtGESA2L9FB8dNTvrQUq3/X4QOb8ExkKyY7LSV
|
||||
github.com/go-acme/lego/v4 v4.23.1/go.mod h1:7UMVR7oQbIYw6V7mTgGwi4Er7B6Ww0c+c8feiBM0EgI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
@@ -64,8 +64,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godoxy-app/docker v0.0.0-20250523125835-a2474a6ebe30 h1:+5pYG8clUrZbUDP+x149jkRfYAGaNpAXOwut0jluoYA=
|
||||
github.com/godoxy-app/docker v0.0.0-20250523125835-a2474a6ebe30/go.mod h1:7VkicOZ3VrlxOe/EP/8uwsWLGKI2wt2MV7CgxTDIYgA=
|
||||
@@ -318,10 +318,10 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
34
go.mod
34
go.mod
@@ -17,7 +17,7 @@ replace github.com/shirou/gopsutil/v4 => github.com/godoxy-app/gopsutil/v4 v4.0.
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // parsing HTML for extract fav icon
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 // oidc authentication
|
||||
github.com/docker/docker v28.1.1+incompatible // docker daemon
|
||||
github.com/docker/docker v28.2.1+incompatible // docker daemon
|
||||
github.com/fsnotify/fsnotify v1.9.0 // file watcher
|
||||
github.com/go-acme/lego/v4 v4.23.1 // acme client
|
||||
github.com/go-playground/validator/v10 v10.26.0 // validator
|
||||
@@ -36,8 +36,8 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/docker/cli v28.1.1+incompatible
|
||||
github.com/goccy/go-yaml v1.17.1 // yaml parsing for different config files
|
||||
github.com/docker/cli v28.2.1+incompatible
|
||||
github.com/goccy/go-yaml v1.18.0 // yaml parsing for different config files
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/luthermonson/go-proxmox v0.2.2
|
||||
github.com/oschwald/maxminddb-golang v1.13.1
|
||||
@@ -45,8 +45,8 @@ require (
|
||||
github.com/samber/slog-zerolog/v2 v2.7.3
|
||||
github.com/spf13/afero v1.14.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/yusing/go-proxy/agent v0.0.0-00010101000000-000000000000
|
||||
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-00010101000000-000000000000
|
||||
github.com/yusing/go-proxy/agent v0.0.0-20250529124236-93a81fd558e6
|
||||
github.com/yusing/go-proxy/internal/dnsproviders v0.0.0-20250529124236-93a81fd558e6
|
||||
github.com/yusing/go-proxy/internal/utils v0.0.0
|
||||
)
|
||||
|
||||
@@ -82,7 +82,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.228 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.229 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/buger/goterm v1.0.4 // indirect
|
||||
@@ -97,14 +97,14 @@ require (
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/exoscale/egoscale/v3 v3.1.18 // indirect
|
||||
github.com/exoscale/egoscale/v3 v3.1.20 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
@@ -126,7 +126,7 @@ require (
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152 // indirect
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
@@ -138,7 +138,7 @@ require (
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/linode/linodego v1.51.0 // indirect
|
||||
github.com/linode/linodego v1.52.0 // indirect
|
||||
github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
|
||||
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
|
||||
@@ -168,7 +168,7 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1 // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0 // indirect
|
||||
github.com/ovh/go-ovh v1.7.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
@@ -202,15 +202,15 @@ require (
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
github.com/tklauser/numcpus v0.10.0 // indirect
|
||||
github.com/transip/gotransip/v6 v6.26.0 // indirect
|
||||
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210 // indirect
|
||||
github.com/vultr/govultr/v3 v3.20.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
@@ -231,9 +231,9 @@ require (
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/api v0.234.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||
google.golang.org/grpc v1.72.1 // indirect
|
||||
google.golang.org/api v0.235.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
||||
58
go.sum
58
go.sum
@@ -710,8 +710,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjK
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/baidubce/bce-sdk-go v0.9.228 h1:XEY3/oAxXcsi7+3atib9fMI6YNE9sL5qo+WMZ+iqmNE=
|
||||
github.com/baidubce/bce-sdk-go v0.9.228/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/baidubce/bce-sdk-go v0.9.229 h1:oL+YlYDqeMrE6NHgPhkI+4T2geeIHz4PFVivvQ0ysug=
|
||||
github.com/baidubce/bce-sdk-go v0.9.229/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -803,8 +803,8 @@ github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c=
|
||||
github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||
github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY=
|
||||
github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8=
|
||||
github.com/docker/cli v28.1.1+incompatible h1:eyUemzeI45DY7eDPuwUcmDyDj1pM98oD5MdSpiItp8k=
|
||||
github.com/docker/cli v28.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/cli v28.2.1+incompatible h1:AYyTcuwvhl9dXdyCiXlOGXiIqSNYzTmaDNpxIISPGsM=
|
||||
github.com/docker/cli v28.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
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=
|
||||
@@ -835,8 +835,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/exoscale/egoscale/v3 v3.1.18 h1:9LvH61Cd0L/JC04KartbICl/hVva5AAwtTzzOxLtSYA=
|
||||
github.com/exoscale/egoscale/v3 v3.1.18/go.mod h1:t9+MpSEam94na48O/xgvvPFpQPRiwZ3kBN4/UuQtKco=
|
||||
github.com/exoscale/egoscale/v3 v3.1.20 h1:AZw7VWblEM4+77bjFt9pHBvOQj+spqLkDVxGxK7cbUU=
|
||||
github.com/exoscale/egoscale/v3 v3.1.20/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
@@ -895,8 +895,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
@@ -930,8 +930,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godoxy-app/docker v0.0.0-20250523125835-a2474a6ebe30 h1:+5pYG8clUrZbUDP+x149jkRfYAGaNpAXOwut0jluoYA=
|
||||
github.com/godoxy-app/docker v0.0.0-20250523125835-a2474a6ebe30/go.mod h1:7VkicOZ3VrlxOe/EP/8uwsWLGKI2wt2MV7CgxTDIYgA=
|
||||
@@ -1154,8 +1154,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150 h1:Ih+z79Ko1ClH4dlv7O1lyHRiVCjkb2NZYYk+1cSZbU8=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152 h1:3ebdqyhjb5cvRDzokKk7TKvI8Wud7tpQET+0yhBkXu4=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -1239,8 +1239,8 @@ github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/linode/linodego v1.51.0 h1:8S0vNQRUZAuumGFe8h/huCzbyExxlvOUR2Uf0oDoJ/8=
|
||||
github.com/linode/linodego v1.51.0/go.mod h1:zEN2sX+cSdp67EuRY1HJiyuLujoa7HqvVwNEcJv3iXw=
|
||||
github.com/linode/linodego v1.52.0 h1:SN1PSekrZBcHtRt1pADTz0JO7NX9pQv/Gf8Jc9s9l8w=
|
||||
github.com/linode/linodego v1.52.0/go.mod h1:zEN2sX+cSdp67EuRY1HJiyuLujoa7HqvVwNEcJv3iXw=
|
||||
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
|
||||
@@ -1402,8 +1402,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1 h1:jRE4jUiJd+sDhJTyTCXIJdzLjTx+99gA3PgzpVTaF/I=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0 h1:qLy3VH3aEO1c4RdKu58cmNrITtRbrgpRGOsYxgP2eXU=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw=
|
||||
@@ -1619,11 +1619,11 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1170/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172 h1:cfh0m0esFTjBZ6YZRCVWUDs772KOfxQR/mKY7zL8/qg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170 h1:qdjh5LP8N2bE8cPfBX6Y3S/3+5yD2JLJBx7EALVrgP0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170/go.mod h1:OS8GJ/x+p/6Wchc6Lp6iA9Gf9sQ/it0xatH1AXGX8PY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1174/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177 h1:Lcr72Dtd1eRYP4jz9xch9SN5lJ80e2RFnIwTHlaxAFY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174 h1:LRmjetOxA7ZjHIEiYKoZmVOntxpzscgrse50PDEUs/s=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174/go.mod h1:H0oIwVla6DcgpKnEvFcFEphENZng64Mqkq2p4alU4tE=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
|
||||
@@ -1647,8 +1647,8 @@ github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8A
|
||||
github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209 h1:aYCVO2fQ4meqLZ+XjVLcKzDn7kYfrUekqp48iioH3ug=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210 h1:cEOHlBxopRSQ939W+lxA7S8OwuyCkkBbC+NguES+3Z8=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
||||
github.com/vultr/govultr/v3 v3.20.0 h1:O+Om6gXpN6ehwAIIKq5DyGuekpyHaoRlwrxTb44bDzA=
|
||||
github.com/vultr/govultr/v3 v3.20.0/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
@@ -2298,8 +2298,8 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
|
||||
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
|
||||
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
|
||||
google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
|
||||
google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4=
|
||||
google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo=
|
||||
google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -2444,8 +2444,8 @@ google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRx
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -2488,8 +2488,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v
|
||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/utils"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -162,6 +163,8 @@ func (auth *OIDCProvider) HandleAuth(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
var rateLimit = rate.NewLimiter(rate.Every(time.Second), 1)
|
||||
|
||||
func (auth *OIDCProvider) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// check for session token
|
||||
sessionToken, err := r.Cookie(CookieOauthSessionToken)
|
||||
@@ -182,10 +185,21 @@ func (auth *OIDCProvider) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if !rateLimit.Allow() {
|
||||
http.Error(w, "auth rate limit exceeded", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
|
||||
state := generateState()
|
||||
SetTokenCookie(w, r, CookieOauthState, state, 300*time.Second)
|
||||
// redirect user to Idp
|
||||
http.Redirect(w, r, auth.oauthConfig.AuthCodeURL(state, optRedirectPostAuth(r)), http.StatusFound)
|
||||
url := auth.oauthConfig.AuthCodeURL(state, optRedirectPostAuth(r))
|
||||
if IsFrontend(r) {
|
||||
w.Header().Set("X-Redirect-To", url)
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
} else {
|
||||
http.Redirect(w, r, url, http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func parseClaims(idToken *oidc.IDToken) (*IDTokenClaims, error) {
|
||||
|
||||
@@ -124,7 +124,8 @@ func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http
|
||||
}
|
||||
|
||||
func (auth *UserPassAuth) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/login", http.StatusFound) // redirects to WebUI login page
|
||||
w.Header().Set("X-Redirect-To", "/login")
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
}
|
||||
|
||||
func (auth *UserPassAuth) LogoutHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -16,7 +17,15 @@ var (
|
||||
)
|
||||
|
||||
func IsFrontend(r *http.Request) bool {
|
||||
return r.Host == common.APIHTTPAddr
|
||||
return requestRemoteIP(r) == "127.0.0.1"
|
||||
}
|
||||
|
||||
func requestRemoteIP(r *http.Request) string {
|
||||
ip, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
func requestHost(r *http.Request) string {
|
||||
|
||||
@@ -117,13 +117,13 @@ func Reload() gperr.Error {
|
||||
newCfg := newConfig()
|
||||
err := newCfg.load()
|
||||
if err != nil {
|
||||
newCfg.task.Finish(err)
|
||||
newCfg.task.FinishAndWait(err)
|
||||
return gperr.New(ansi.Warning("using last config")).With(err)
|
||||
}
|
||||
|
||||
// cancel all current subtasks -> wait
|
||||
// -> replace config -> start new subtasks
|
||||
config.GetInstance().(*Config).Task().Finish("config changed")
|
||||
config.GetInstance().(*Config).Task().FinishAndWait("config changed")
|
||||
newCfg.Start(StartAllServers)
|
||||
config.SetInstance(newCfg)
|
||||
return nil
|
||||
|
||||
@@ -8,7 +8,7 @@ replace github.com/yusing/go-proxy/internal/utils => ../utils
|
||||
|
||||
require (
|
||||
github.com/go-acme/lego/v4 v4.23.1
|
||||
github.com/yusing/go-proxy v0.0.0-00010101000000-000000000000
|
||||
github.com/yusing/go-proxy v0.13.6
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -41,7 +41,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 // indirect
|
||||
github.com/aws/smithy-go v1.22.3 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.228 // indirect
|
||||
github.com/baidubce/bce-sdk-go v0.9.229 // indirect
|
||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
@@ -49,7 +49,7 @@ require (
|
||||
github.com/cloudflare/cloudflare-go v0.115.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dnsimple/dnsimple-go v1.7.0 // indirect
|
||||
github.com/exoscale/egoscale/v3 v3.1.18 // indirect
|
||||
github.com/exoscale/egoscale/v3 v3.1.20 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
@@ -57,7 +57,7 @@ require (
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
@@ -65,7 +65,7 @@ require (
|
||||
github.com/go-resty/resty/v2 v2.16.5 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
@@ -80,7 +80,7 @@ require (
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150 // indirect
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152 // indirect
|
||||
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
|
||||
github.com/infobloxopen/infoblox-go-client/v2 v2.10.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -91,7 +91,7 @@ require (
|
||||
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
|
||||
github.com/labbsr0x/goh v1.0.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/linode/linodego v1.51.0 // indirect
|
||||
github.com/linode/linodego v1.52.0 // indirect
|
||||
github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
|
||||
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
@@ -115,7 +115,7 @@ require (
|
||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1 // indirect
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0 // indirect
|
||||
github.com/ovh/go-ovh v1.7.0 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
@@ -148,13 +148,13 @@ require (
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/stretchr/testify v1.10.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/transip/gotransip/v6 v6.26.0 // indirect
|
||||
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209 // indirect
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210 // indirect
|
||||
github.com/vultr/govultr/v3 v3.20.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
@@ -177,9 +177,9 @@ require (
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/api v0.234.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
|
||||
google.golang.org/grpc v1.72.1 // indirect
|
||||
google.golang.org/api v0.235.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
||||
@@ -702,8 +702,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjK
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
|
||||
github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/baidubce/bce-sdk-go v0.9.228 h1:XEY3/oAxXcsi7+3atib9fMI6YNE9sL5qo+WMZ+iqmNE=
|
||||
github.com/baidubce/bce-sdk-go v0.9.228/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/baidubce/bce-sdk-go v0.9.229 h1:oL+YlYDqeMrE6NHgPhkI+4T2geeIHz4PFVivvQ0ysug=
|
||||
github.com/baidubce/bce-sdk-go v0.9.229/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
@@ -801,8 +801,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
|
||||
github.com/exoscale/egoscale/v3 v3.1.18 h1:9LvH61Cd0L/JC04KartbICl/hVva5AAwtTzzOxLtSYA=
|
||||
github.com/exoscale/egoscale/v3 v3.1.18/go.mod h1:t9+MpSEam94na48O/xgvvPFpQPRiwZ3kBN4/UuQtKco=
|
||||
github.com/exoscale/egoscale/v3 v3.1.20 h1:AZw7VWblEM4+77bjFt9pHBvOQj+spqLkDVxGxK7cbUU=
|
||||
github.com/exoscale/egoscale/v3 v3.1.20/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
@@ -861,8 +861,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
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.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
|
||||
@@ -890,8 +890,8 @@ github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVr
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
|
||||
@@ -1100,8 +1100,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150 h1:Ih+z79Ko1ClH4dlv7O1lyHRiVCjkb2NZYYk+1cSZbU8=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.150/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152 h1:3ebdqyhjb5cvRDzokKk7TKvI8Wud7tpQET+0yhBkXu4=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.152/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -1181,8 +1181,8 @@ github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk=
|
||||
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/linode/linodego v1.51.0 h1:8S0vNQRUZAuumGFe8h/huCzbyExxlvOUR2Uf0oDoJ/8=
|
||||
github.com/linode/linodego v1.51.0/go.mod h1:zEN2sX+cSdp67EuRY1HJiyuLujoa7HqvVwNEcJv3iXw=
|
||||
github.com/linode/linodego v1.52.0 h1:SN1PSekrZBcHtRt1pADTz0JO7NX9pQv/Gf8Jc9s9l8w=
|
||||
github.com/linode/linodego v1.52.0/go.mod h1:zEN2sX+cSdp67EuRY1HJiyuLujoa7HqvVwNEcJv3iXw=
|
||||
github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
|
||||
github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
|
||||
@@ -1322,8 +1322,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
|
||||
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1 h1:jRE4jUiJd+sDhJTyTCXIJdzLjTx+99gA3PgzpVTaF/I=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.91.1/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0 h1:qLy3VH3aEO1c4RdKu58cmNrITtRbrgpRGOsYxgP2eXU=
|
||||
github.com/oracle/oci-go-sdk/v65 v65.92.0/go.mod h1:u6XRPsw9tPziBh76K7GrrRXPa8P8W3BQeqJ6ZZt9VLA=
|
||||
github.com/ovh/go-ovh v1.7.0 h1:V14nF7FwDjQrZt9g7jzcvAAQ3HN6DNShRFRMC3jLoPw=
|
||||
github.com/ovh/go-ovh v1.7.0/go.mod h1:cTVDnl94z4tl8pP1uZ/8jlVxntjSIf09bNcQ5TJSC7c=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
@@ -1518,11 +1518,11 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1170/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172 h1:cfh0m0esFTjBZ6YZRCVWUDs772KOfxQR/mKY7zL8/qg=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1172/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170 h1:qdjh5LP8N2bE8cPfBX6Y3S/3+5yD2JLJBx7EALVrgP0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1170/go.mod h1:OS8GJ/x+p/6Wchc6Lp6iA9Gf9sQ/it0xatH1AXGX8PY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1174/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177 h1:Lcr72Dtd1eRYP4jz9xch9SN5lJ80e2RFnIwTHlaxAFY=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1177/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174 h1:LRmjetOxA7ZjHIEiYKoZmVOntxpzscgrse50PDEUs/s=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1174/go.mod h1:H0oIwVla6DcgpKnEvFcFEphENZng64Mqkq2p4alU4tE=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@@ -1538,8 +1538,8 @@ github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
|
||||
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209 h1:aYCVO2fQ4meqLZ+XjVLcKzDn7kYfrUekqp48iioH3ug=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.209/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210 h1:cEOHlBxopRSQ939W+lxA7S8OwuyCkkBbC+NguES+3Z8=
|
||||
github.com/volcengine/volc-sdk-golang v1.0.210/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
|
||||
github.com/vultr/govultr/v3 v3.20.0 h1:O+Om6gXpN6ehwAIIKq5DyGuekpyHaoRlwrxTb44bDzA=
|
||||
github.com/vultr/govultr/v3 v3.20.0/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
@@ -2155,8 +2155,8 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c
|
||||
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
|
||||
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
|
||||
google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
|
||||
google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4=
|
||||
google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo=
|
||||
google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -2301,8 +2301,8 @@ google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRx
|
||||
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -2345,8 +2345,8 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v
|
||||
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
|
||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
|
||||
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
|
||||
@@ -58,20 +58,16 @@ func initClientCleaner() {
|
||||
case <-ticker.C:
|
||||
closeTimedOutClients()
|
||||
case <-cleaner.Context().Done():
|
||||
clientMapMu.Lock()
|
||||
for _, c := range clientMap {
|
||||
delete(clientMap, c.Key())
|
||||
c.Client.Close()
|
||||
}
|
||||
clientMapMu.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
task.OnProgramExit("docker_clients_cleanup", func() {
|
||||
clientMapMu.Lock()
|
||||
defer clientMapMu.Unlock()
|
||||
|
||||
for _, c := range clientMap {
|
||||
delete(clientMap, c.Key())
|
||||
c.Client.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func closeTimedOutClients() {
|
||||
|
||||
@@ -92,7 +92,7 @@ func NewWatcher(parent task.Parent, r routes.Route) (*Watcher, error) {
|
||||
// same address, likely two routes from the same container
|
||||
return w, nil
|
||||
}
|
||||
w.task.Finish(causeReload)
|
||||
w.task.FinishAndWait(causeReload)
|
||||
}
|
||||
watcherMapMu.RUnlock()
|
||||
|
||||
@@ -156,14 +156,15 @@ func NewWatcher(parent task.Parent, r routes.Route) (*Watcher, error) {
|
||||
w.task = parent.Subtask("idlewatcher."+r.Name(), true)
|
||||
|
||||
watcherMapMu.Lock()
|
||||
defer watcherMapMu.Unlock()
|
||||
watcherMap[key] = w
|
||||
watcherMapMu.Unlock()
|
||||
|
||||
go func() {
|
||||
cause := w.watchUntilDestroy()
|
||||
if errors.Is(cause, causeContainerDestroy) || errors.Is(cause, task.ErrProgramExiting) {
|
||||
watcherMapMu.Lock()
|
||||
defer watcherMapMu.Unlock()
|
||||
delete(watcherMap, key)
|
||||
watcherMapMu.Unlock()
|
||||
w.l.Info().Msg("idlewatcher stopped")
|
||||
} else if !errors.Is(cause, causeReload) {
|
||||
gperr.LogError("idlewatcher stopped unexpectedly", cause, &w.l)
|
||||
|
||||
@@ -34,11 +34,16 @@ type (
|
||||
City = maxmind.City
|
||||
)
|
||||
|
||||
var (
|
||||
const (
|
||||
updateInterval = 24 * time.Hour
|
||||
httpClient = &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
updateTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
var httpClient = &http.Client{
|
||||
Timeout: updateTimeout,
|
||||
}
|
||||
|
||||
var (
|
||||
ErrResponseNotOK = gperr.New("response not OK")
|
||||
ErrDownloadFailure = gperr.New("download failure")
|
||||
)
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
type (
|
||||
cidrWhitelist struct {
|
||||
CIDRWhitelistOpts
|
||||
Tracer
|
||||
cachedAddr F.Map[string, bool] // cache for trusted IPs
|
||||
}
|
||||
CIDRWhitelistOpts struct {
|
||||
@@ -64,13 +63,11 @@ func (wl *cidrWhitelist) checkIP(w http.ResponseWriter, r *http.Request) bool {
|
||||
if cidr.Contains(ip) {
|
||||
wl.cachedAddr.Store(r.RemoteAddr, true)
|
||||
allow = true
|
||||
wl.AddTracef("client %s is allowed", ipStr).With("allowed CIDR", cidr)
|
||||
break
|
||||
}
|
||||
}
|
||||
if !allow {
|
||||
wl.cachedAddr.Store(r.RemoteAddr, false)
|
||||
wl.AddTracef("client %s is forbidden", ipStr).With("allowed CIDRs", wl.Allow)
|
||||
}
|
||||
}
|
||||
if !allow {
|
||||
|
||||
@@ -45,7 +45,7 @@ var CloudflareRealIP = NewMiddleware[cloudflareRealIP]()
|
||||
|
||||
// setup implements MiddlewareWithSetup.
|
||||
func (cri *cloudflareRealIP) setup() {
|
||||
cri.realIP.RealIPOpts = RealIPOpts{
|
||||
cri.realIP = realIP{
|
||||
Header: "CF-Connecting-IP",
|
||||
Recursive: true,
|
||||
}
|
||||
@@ -60,14 +60,6 @@ func (cri *cloudflareRealIP) before(w http.ResponseWriter, r *http.Request) bool
|
||||
return cri.realIP.before(w, r)
|
||||
}
|
||||
|
||||
func (cri *cloudflareRealIP) enableTrace() {
|
||||
cri.realIP.enableTrace()
|
||||
}
|
||||
|
||||
func (cri *cloudflareRealIP) getTracer() *Tracer {
|
||||
return cri.realIP.getTracer()
|
||||
}
|
||||
|
||||
func tryFetchCFCIDR() (cfCIDRs []*types.CIDR) {
|
||||
if time.Since(cfCIDRsLastUpdate.Load()) < cfCIDRsUpdateInterval {
|
||||
return
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
gphttp "github.com/yusing/go-proxy/internal/net/gphttp"
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
|
||||
@@ -52,10 +51,6 @@ type (
|
||||
MiddlewareFinalizerWithError interface {
|
||||
finalize() error
|
||||
}
|
||||
MiddlewareWithTracer interface {
|
||||
enableTrace()
|
||||
getTracer() *Tracer
|
||||
}
|
||||
)
|
||||
|
||||
const DefaultPriority = 10
|
||||
@@ -84,26 +79,6 @@ func NewMiddleware[ImplType any]() *Middleware {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Middleware) enableTrace() {
|
||||
if tracer, ok := m.impl.(MiddlewareWithTracer); ok {
|
||||
tracer.enableTrace()
|
||||
log.Trace().Msgf("middleware %s enabled trace", m.name)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Middleware) getTracer() *Tracer {
|
||||
if tracer, ok := m.impl.(MiddlewareWithTracer); ok {
|
||||
return tracer.getTracer()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Middleware) setParent(parent *Middleware) {
|
||||
if tracer := m.getTracer(); tracer != nil {
|
||||
tracer.SetParent(parent.getTracer())
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Middleware) setup() {
|
||||
if setup, ok := m.impl.(MiddlewareWithSetup); ok {
|
||||
setup.setup()
|
||||
|
||||
@@ -3,7 +3,6 @@ package middleware
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
)
|
||||
|
||||
@@ -24,14 +23,6 @@ func NewMiddlewareChain(name string, chain []*Middleware) *Middleware {
|
||||
if mr, ok := comp.impl.(ResponseModifier); ok {
|
||||
chainMid.modResps = append(chainMid.modResps, mr)
|
||||
}
|
||||
comp.setParent(m)
|
||||
}
|
||||
|
||||
if common.IsTrace {
|
||||
for _, child := range chain {
|
||||
child.enableTrace()
|
||||
}
|
||||
m.enableTrace()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
type (
|
||||
modifyRequest struct {
|
||||
ModifyRequestOpts
|
||||
Tracer
|
||||
}
|
||||
// order: add_prefix -> set_headers -> add_headers -> hide_headers
|
||||
ModifyRequestOpts struct {
|
||||
@@ -31,11 +30,14 @@ func (mr *ModifyRequestOpts) finalize() {
|
||||
|
||||
// before implements RequestModifier.
|
||||
func (mr *modifyRequest) before(w http.ResponseWriter, r *http.Request) (proceed bool) {
|
||||
mr.AddTraceRequest("before modify request", r)
|
||||
|
||||
mr.addPrefix(r, nil, r.URL.Path)
|
||||
mr.modifyHeaders(r, nil, r.Header)
|
||||
mr.AddTraceRequest("after modify request", r)
|
||||
if len(mr.AddPrefix) != 0 {
|
||||
mr.addPrefix(r, r.URL.Path)
|
||||
}
|
||||
if !mr.needVarSubstitution {
|
||||
mr.modifyHeaders(r, r.Header)
|
||||
} else {
|
||||
mr.modifyHeadersWithVarSubstitution(r, nil, r.Header)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -50,42 +52,40 @@ func (mr *ModifyRequestOpts) checkVarSubstitution() {
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *ModifyRequestOpts) modifyHeaders(req *http.Request, resp *http.Response, headers http.Header) {
|
||||
if !mr.needVarSubstitution {
|
||||
for k, v := range mr.SetHeaders {
|
||||
if req != nil && strings.EqualFold(k, "host") {
|
||||
defer func() {
|
||||
req.Host = v
|
||||
}()
|
||||
}
|
||||
headers[k] = []string{v}
|
||||
}
|
||||
for k, v := range mr.AddHeaders {
|
||||
headers[k] = append(headers[k], v)
|
||||
}
|
||||
} else {
|
||||
for k, v := range mr.SetHeaders {
|
||||
if req != nil && strings.EqualFold(k, "host") {
|
||||
defer func() {
|
||||
req.Host = varReplace(req, resp, v)
|
||||
}()
|
||||
}
|
||||
headers[k] = []string{varReplace(req, resp, v)}
|
||||
}
|
||||
for k, v := range mr.AddHeaders {
|
||||
headers[k] = append(headers[k], varReplace(req, resp, v))
|
||||
func (mr *ModifyRequestOpts) modifyHeaders(req *http.Request, headers http.Header) {
|
||||
for k, v := range mr.SetHeaders {
|
||||
if req != nil && strings.EqualFold(k, "host") {
|
||||
defer func() {
|
||||
req.Host = v
|
||||
}()
|
||||
}
|
||||
headers[k] = []string{v}
|
||||
}
|
||||
for k, v := range mr.AddHeaders {
|
||||
headers[k] = append(headers[k], v)
|
||||
}
|
||||
|
||||
for _, k := range mr.HideHeaders {
|
||||
delete(headers, k)
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *modifyRequest) addPrefix(r *http.Request, _ *http.Response, path string) {
|
||||
if len(mr.AddPrefix) == 0 {
|
||||
return
|
||||
func (mr *ModifyRequestOpts) modifyHeadersWithVarSubstitution(req *http.Request, resp *http.Response, headers http.Header) {
|
||||
for k, v := range mr.SetHeaders {
|
||||
if req != nil && strings.EqualFold(k, "host") {
|
||||
defer func() {
|
||||
req.Host = varReplace(req, resp, v)
|
||||
}()
|
||||
}
|
||||
headers[k] = []string{varReplace(req, resp, v)}
|
||||
}
|
||||
for k, v := range mr.AddHeaders {
|
||||
headers[k] = append(headers[k], varReplace(req, resp, v))
|
||||
}
|
||||
for _, k := range mr.HideHeaders {
|
||||
delete(headers, k)
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *modifyRequest) addPrefix(r *http.Request, path string) {
|
||||
r.URL.Path = filepath.Join(mr.AddPrefix, path)
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ import (
|
||||
|
||||
type modifyResponse struct {
|
||||
ModifyRequestOpts
|
||||
Tracer
|
||||
}
|
||||
|
||||
var ModifyResponse = NewMiddleware[modifyResponse]()
|
||||
|
||||
// modifyResponse implements ResponseModifier.
|
||||
func (mr *modifyResponse) modifyResponse(resp *http.Response) error {
|
||||
mr.AddTraceResponse("before modify response", resp)
|
||||
mr.modifyHeaders(resp.Request, resp, resp.Header)
|
||||
mr.AddTraceResponse("after modify response", resp)
|
||||
if !mr.needVarSubstitution {
|
||||
mr.modifyHeaders(resp.Request, resp.Header)
|
||||
} else {
|
||||
mr.modifyHeadersWithVarSubstitution(resp.Request, resp, resp.Header)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ type (
|
||||
requestMap = map[string]*rate.Limiter
|
||||
rateLimiter struct {
|
||||
RateLimiterOpts
|
||||
Tracer
|
||||
|
||||
requestMap requestMap
|
||||
mu sync.Mutex
|
||||
@@ -51,7 +50,6 @@ func (rl *rateLimiter) newLimiter() *rate.Limiter {
|
||||
func (rl *rateLimiter) limit(w http.ResponseWriter, r *http.Request) bool {
|
||||
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
||||
if err != nil {
|
||||
rl.AddTracef("unable to parse remote address %s", r.RemoteAddr)
|
||||
http.Error(w, "Internal error", http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -11,10 +11,7 @@ import (
|
||||
// https://nginx.org/en/docs/http/ngx_http_realip_module.html
|
||||
|
||||
type (
|
||||
realIP struct {
|
||||
RealIPOpts
|
||||
Tracer
|
||||
}
|
||||
realIP RealIPOpts
|
||||
RealIPOpts struct {
|
||||
// Header is the name of the header to use for the real client IP
|
||||
Header string `validate:"required"`
|
||||
@@ -42,7 +39,7 @@ var (
|
||||
|
||||
// setup implements MiddlewareWithSetup.
|
||||
func (ri *realIP) setup() {
|
||||
ri.RealIPOpts = realIPOptsDefault
|
||||
*ri = realIP(realIPOptsDefault)
|
||||
}
|
||||
|
||||
// before implements RequestModifier.
|
||||
@@ -77,7 +74,6 @@ func (ri *realIP) setRealIP(req *http.Request) {
|
||||
}
|
||||
}
|
||||
if !isTrusted {
|
||||
ri.AddTracef("client ip %s is not trusted", clientIP).With("allowed CIDRs", ri.From)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -90,7 +86,6 @@ func (ri *realIP) setRealIP(req *http.Request) {
|
||||
}
|
||||
|
||||
if len(realIPs) == 0 {
|
||||
ri.AddTracef("no real ip found in header %s", ri.Header).WithRequest(req)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -105,12 +100,10 @@ func (ri *realIP) setRealIP(req *http.Request) {
|
||||
}
|
||||
|
||||
if lastNonTrustedIP == "" {
|
||||
ri.AddTracef("no non-trusted ip found").With("allowed CIDRs", ri.From).With("ips", realIPs)
|
||||
return
|
||||
}
|
||||
|
||||
req.RemoteAddr = lastNonTrustedIP
|
||||
req.Header.Set(ri.Header, lastNonTrustedIP)
|
||||
req.Header.Set(httpheaders.HeaderXRealIP, lastNonTrustedIP)
|
||||
ri.AddTracef("set real ip %s", lastNonTrustedIP)
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ func TestSetRealIP(t *testing.T) {
|
||||
|
||||
result, err := newMiddlewareTest(mid, nil)
|
||||
ExpectNoError(t, err)
|
||||
t.Log(traces)
|
||||
ExpectEqual(t, result.ResponseStatus, http.StatusOK)
|
||||
ExpectEqual(t, strings.Split(result.RemoteAddr, ":")[0], testRealIP)
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/net/gphttp/httpheaders"
|
||||
)
|
||||
|
||||
type (
|
||||
Trace struct {
|
||||
Time string `json:"time,omitempty"`
|
||||
Caller string `json:"caller,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Message string `json:"msg"`
|
||||
ReqHeaders map[string]string `json:"req_headers,omitempty"`
|
||||
RespHeaders map[string]string `json:"resp_headers,omitempty"`
|
||||
RespStatus int `json:"resp_status,omitempty"`
|
||||
Additional map[string]any `json:"additional,omitempty"`
|
||||
}
|
||||
Traces []*Trace
|
||||
)
|
||||
|
||||
var (
|
||||
traces = make(Traces, 0)
|
||||
tracesMu sync.Mutex
|
||||
)
|
||||
|
||||
const MaxTraceNum = 100
|
||||
|
||||
func GetAllTrace() []*Trace {
|
||||
return traces
|
||||
}
|
||||
|
||||
func (tr *Trace) WithRequest(req *http.Request) *Trace {
|
||||
if tr == nil {
|
||||
return nil
|
||||
}
|
||||
tr.URL = req.RequestURI
|
||||
tr.ReqHeaders = httpheaders.HeaderToMap(req.Header)
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *Trace) WithResponse(resp *http.Response) *Trace {
|
||||
if tr == nil {
|
||||
return nil
|
||||
}
|
||||
tr.URL = resp.Request.RequestURI
|
||||
tr.ReqHeaders = httpheaders.HeaderToMap(resp.Request.Header)
|
||||
tr.RespHeaders = httpheaders.HeaderToMap(resp.Header)
|
||||
tr.RespStatus = resp.StatusCode
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *Trace) With(what string, additional any) *Trace {
|
||||
if tr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tr.Additional == nil {
|
||||
tr.Additional = map[string]any{}
|
||||
}
|
||||
tr.Additional[what] = additional
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *Trace) WithError(err error) *Trace {
|
||||
if tr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tr.Additional == nil {
|
||||
tr.Additional = map[string]any{}
|
||||
}
|
||||
tr.Additional["error"] = err.Error()
|
||||
return tr
|
||||
}
|
||||
|
||||
func addTrace(t *Trace) *Trace {
|
||||
tracesMu.Lock()
|
||||
defer tracesMu.Unlock()
|
||||
if len(traces) > MaxTraceNum {
|
||||
traces = traces[1:]
|
||||
}
|
||||
traces = append(traces, t)
|
||||
return t
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/utils/strutils"
|
||||
)
|
||||
|
||||
type Tracer struct {
|
||||
name string
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func _() {
|
||||
var _ MiddlewareWithTracer = &Tracer{}
|
||||
}
|
||||
|
||||
func (t *Tracer) enableTrace() {
|
||||
t.enabled = true
|
||||
}
|
||||
|
||||
func (t *Tracer) getTracer() *Tracer {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Tracer) SetParent(parent *Tracer) {
|
||||
if parent == nil {
|
||||
return
|
||||
}
|
||||
t.name = parent.name + "." + t.name
|
||||
}
|
||||
|
||||
func (t *Tracer) addTrace(msg string) *Trace {
|
||||
return addTrace(&Trace{
|
||||
Time: strutils.FormatTime(time.Now()),
|
||||
Caller: t.name,
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *Tracer) AddTracef(msg string, args ...any) *Trace {
|
||||
if !t.enabled {
|
||||
return nil
|
||||
}
|
||||
return t.addTrace(fmt.Sprintf(msg, args...))
|
||||
}
|
||||
|
||||
func (t *Tracer) AddTraceRequest(msg string, req *http.Request) *Trace {
|
||||
if !t.enabled {
|
||||
return nil
|
||||
}
|
||||
return t.addTrace(msg).WithRequest(req)
|
||||
}
|
||||
|
||||
func (t *Tracer) AddTraceResponse(msg string, resp *http.Response) *Trace {
|
||||
if !t.enabled {
|
||||
return nil
|
||||
}
|
||||
return t.addTrace(msg).WithResponse(resp)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Del("Forwarded")
|
||||
outreq.Header.Del("Forwarded")
|
||||
httpheaders.RemoveHopByHopHeaders(outreq.Header)
|
||||
|
||||
// Issue 21096: tell backend applications that care about trailer support
|
||||
@@ -312,7 +312,7 @@ func (p *ReverseProxy) handler(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
var reqScheme string
|
||||
if req.TLS != nil {
|
||||
if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
|
||||
reqScheme = "https"
|
||||
} else {
|
||||
reqScheme = "http"
|
||||
|
||||
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@@ -10,7 +11,7 @@ import (
|
||||
|
||||
func convertError(err error) error {
|
||||
switch {
|
||||
case err == nil, errors.Is(err, http.ErrServerClosed), errors.Is(err, context.Canceled):
|
||||
case err == nil, errors.Is(err, http.ErrServerClosed), errors.Is(err, context.Canceled), errors.Is(err, net.ErrClosed):
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
|
||||
@@ -3,6 +3,8 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
@@ -105,7 +107,7 @@ func (s *Server) Start(parent task.Parent) {
|
||||
}
|
||||
Start(subtask, h3, s.acl, &s.l)
|
||||
if s.http != nil {
|
||||
s.http.Handler = advertiseHTTP3(s.http.Handler, h3)
|
||||
s.http.Handler = advertiseHTTP3(s.http.Handler, h3)
|
||||
}
|
||||
// s.https is not nil (checked above)
|
||||
s.https.Handler = advertiseHTTP3(s.https.Handler, h3)
|
||||
@@ -115,7 +117,7 @@ func (s *Server) Start(parent task.Parent) {
|
||||
Start(subtask, s.https, s.acl, &s.l)
|
||||
}
|
||||
|
||||
func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, logger *zerolog.Logger) {
|
||||
func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, logger *zerolog.Logger) (port int) {
|
||||
if srv == nil {
|
||||
return
|
||||
}
|
||||
@@ -138,6 +140,7 @@ func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, l
|
||||
HandleError(logger, err, "failed to listen on port")
|
||||
return
|
||||
}
|
||||
port = l.Addr().(*net.TCPAddr).Port
|
||||
if srv.TLSConfig != nil {
|
||||
l = tls.NewListener(l, srv.TLSConfig)
|
||||
}
|
||||
@@ -145,32 +148,36 @@ func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, l
|
||||
l = acl.WrapTCP(l)
|
||||
}
|
||||
serveFunc = getServeFunc(l, srv.Serve)
|
||||
task.OnCancel("stop", func() {
|
||||
stop(srv, l, logger)
|
||||
})
|
||||
case *http3.Server:
|
||||
l, err := lc.ListenPacket(task.Context(), "udp", srv.Addr)
|
||||
if err != nil {
|
||||
HandleError(logger, err, "failed to listen on port")
|
||||
return
|
||||
}
|
||||
port = l.LocalAddr().(*net.UDPAddr).Port
|
||||
if acl != nil {
|
||||
l = acl.WrapUDP(l)
|
||||
}
|
||||
serveFunc = getServeFunc(l, srv.Serve)
|
||||
task.OnCancel("stop", func() {
|
||||
stop(srv, l, logger)
|
||||
})
|
||||
}
|
||||
task.OnCancel("stop", func() {
|
||||
stop(srv, logger)
|
||||
})
|
||||
logStarted(srv, logger)
|
||||
go func() {
|
||||
err := convertError(serveFunc())
|
||||
if err != nil {
|
||||
HandleError(logger, err, "failed to serve "+proto+" server")
|
||||
HandleError(logger, err, "failed to serve "+proto+" server")
|
||||
}
|
||||
task.Finish(err)
|
||||
}()
|
||||
return port
|
||||
}
|
||||
|
||||
func stop[Server httpServer](srv Server, logger *zerolog.Logger) {
|
||||
func stop[Server httpServer](srv Server, l io.Closer, logger *zerolog.Logger) {
|
||||
if srv == nil {
|
||||
return
|
||||
}
|
||||
@@ -180,7 +187,7 @@ func stop[Server httpServer](srv Server, logger *zerolog.Logger) {
|
||||
ctx, cancel := context.WithTimeout(task.RootContext(), 1*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := convertError(srv.Shutdown(ctx)); err != nil {
|
||||
if err := convertError(errors.Join(srv.Shutdown(ctx), l.Close())); err != nil {
|
||||
HandleError(logger, err, "failed to shutdown "+proto+" server")
|
||||
} else {
|
||||
logger.Info().Str("proto", proto).Str("addr", addr(srv)).Msg("server stopped")
|
||||
|
||||
@@ -86,7 +86,7 @@ func (f FieldsBody) Format(format *LogFormat) ([]byte, error) {
|
||||
case LogFormatRawJSON:
|
||||
return json.Marshal(f)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown format: %v", format)
|
||||
return f.Format(LogFormatMarkdown)
|
||||
}
|
||||
|
||||
func (l ListBody) Format(format *LogFormat) ([]byte, error) {
|
||||
@@ -104,7 +104,7 @@ func (l ListBody) Format(format *LogFormat) ([]byte, error) {
|
||||
case LogFormatRawJSON:
|
||||
return json.Marshal(l)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown format: %v", format)
|
||||
return l.Format(LogFormatMarkdown)
|
||||
}
|
||||
|
||||
func (m MessageBody) Format(format *LogFormat) ([]byte, error) {
|
||||
@@ -114,13 +114,13 @@ func (m MessageBody) Format(format *LogFormat) ([]byte, error) {
|
||||
case LogFormatRawJSON:
|
||||
return json.Marshal(m)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown format: %v", format)
|
||||
return m.Format(LogFormatMarkdown)
|
||||
}
|
||||
|
||||
func (e ErrorBody) Format(format *LogFormat) ([]byte, error) {
|
||||
switch format {
|
||||
case LogFormatRawJSON:
|
||||
return json.Marshal(e)
|
||||
return json.Marshal(e.Error)
|
||||
case LogFormatPlain:
|
||||
return gperr.Plain(e.Error), nil
|
||||
case LogFormatMarkdown:
|
||||
|
||||
@@ -100,9 +100,10 @@ func (p *Provider) startRoute(parent task.Parent, r *route.Route) gperr.Error {
|
||||
func (p *Provider) Start(parent task.Parent) gperr.Error {
|
||||
t := parent.Subtask("provider."+p.String(), false)
|
||||
|
||||
routesTask := t.Subtask("routes", false)
|
||||
errs := gperr.NewBuilder("routes error")
|
||||
for _, r := range p.routes {
|
||||
errs.Add(p.startRoute(t, r))
|
||||
errs.Add(p.startRoute(routesTask, r))
|
||||
}
|
||||
|
||||
eventQueue := events.NewEventQueue(
|
||||
@@ -111,7 +112,7 @@ func (p *Provider) Start(parent task.Parent) gperr.Error {
|
||||
func(events []events.Event) {
|
||||
handler := p.newEventHandler()
|
||||
// routes' lifetime should follow the provider's lifetime
|
||||
handler.Handle(t, events)
|
||||
handler.Handle(routesTask, events)
|
||||
handler.Log()
|
||||
},
|
||||
func(err gperr.Error) {
|
||||
|
||||
@@ -55,6 +55,9 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
||||
if httpConfig.ResponseHeaderTimeout > 0 {
|
||||
trans.ResponseHeaderTimeout = httpConfig.ResponseHeaderTimeout
|
||||
}
|
||||
if httpConfig.DisableCompression {
|
||||
trans.DisableCompression = true
|
||||
}
|
||||
}
|
||||
|
||||
service := base.Name()
|
||||
|
||||
@@ -227,7 +227,7 @@ func (r *Route) Finish(reason any) {
|
||||
if r.impl == nil {
|
||||
return
|
||||
}
|
||||
r.impl.Finish(reason)
|
||||
r.impl.Task().FinishAndWait(reason)
|
||||
r.impl = nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@ import (
|
||||
type HTTPConfig struct {
|
||||
NoTLSVerify bool `json:"no_tls_verify,omitempty"`
|
||||
ResponseHeaderTimeout time.Duration `json:"response_header_timeout,omitempty"`
|
||||
DisableCompression bool `json:"disable_compression,omitempty"`
|
||||
}
|
||||
|
||||
@@ -8,45 +8,59 @@ import (
|
||||
)
|
||||
|
||||
// debug only.
|
||||
func (t *Task) listStuckedCallbacks() []string {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
callbacks := make([]string, 0, len(t.callbacksOnFinish))
|
||||
for c := range t.callbacksOnFinish {
|
||||
callbacks = append(callbacks, c.about)
|
||||
func listStuckedCallbacks(t *Task) []string {
|
||||
callbacks := make([]string, 0)
|
||||
if t.onFinish != nil {
|
||||
for c := range t.onFinish.Range {
|
||||
callbacks = append(callbacks, c.about)
|
||||
}
|
||||
}
|
||||
if t.onCancel != nil {
|
||||
for c := range t.onCancel.Range {
|
||||
callbacks = append(callbacks, c.about)
|
||||
}
|
||||
}
|
||||
if t.children != nil {
|
||||
for c := range t.children.Range {
|
||||
callbacks = append(callbacks, listStuckedCallbacks(c)...)
|
||||
}
|
||||
}
|
||||
return callbacks
|
||||
}
|
||||
|
||||
// debug only.
|
||||
func (t *Task) listStuckedChildren() []string {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
children := make([]string, 0, len(t.children))
|
||||
for c := range t.children {
|
||||
if c.isFinished() {
|
||||
continue
|
||||
}
|
||||
children = append(children, c.String())
|
||||
if len(c.children) > 0 {
|
||||
children = append(children, c.listStuckedChildren()...)
|
||||
func listStuckedChildren(t *Task) []string {
|
||||
if t.children != nil {
|
||||
children := make([]string, 0)
|
||||
for c := range t.children.Range {
|
||||
children = append(children, c.String())
|
||||
children = append(children, listStuckedCallbacks(c)...)
|
||||
}
|
||||
return children
|
||||
}
|
||||
return children
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Task) reportStucked() {
|
||||
callbacks := t.listStuckedCallbacks()
|
||||
children := t.listStuckedChildren()
|
||||
callbacks := listStuckedCallbacks(t)
|
||||
children := listStuckedChildren(t)
|
||||
if len(callbacks) == 0 && len(children) == 0 {
|
||||
return
|
||||
}
|
||||
fmtOutput := gperr.NewBuilder(fmt.Sprintf("%s stucked callbacks: %d, stucked children: %d", t.String(), len(callbacks), len(children)))
|
||||
if len(callbacks) > 0 {
|
||||
fmtOutput.Add(gperr.New("callbacks").With(gperr.Multiline().AddLinesString(callbacks...)))
|
||||
callbackBuilder := gperr.NewBuilder("callbacks")
|
||||
for _, c := range callbacks {
|
||||
callbackBuilder.Adds(c)
|
||||
}
|
||||
fmtOutput.Add(callbackBuilder.Error())
|
||||
}
|
||||
if len(children) > 0 {
|
||||
fmtOutput.Add(gperr.New("children").With(gperr.Multiline().AddLinesString(children...)))
|
||||
childrenBuilder := gperr.NewBuilder("children")
|
||||
for _, c := range children {
|
||||
childrenBuilder.Adds(c)
|
||||
}
|
||||
fmtOutput.Add(childrenBuilder.Error())
|
||||
}
|
||||
log.Warn().Msg(fmtOutput.String())
|
||||
}
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var (
|
||||
taskPool = make(chan *Task, 100)
|
||||
|
||||
voidTask = &Task{ctx: context.Background()}
|
||||
root = newRoot()
|
||||
|
||||
cancelCtx context.Context
|
||||
)
|
||||
|
||||
func init() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
cancelCtx = ctx //nolint:fatcontext
|
||||
|
||||
voidTask.parent = root
|
||||
}
|
||||
|
||||
func testCleanup() {
|
||||
root = newRoot()
|
||||
}
|
||||
|
||||
func newRoot() *Task {
|
||||
return newTask("root", voidTask, true)
|
||||
}
|
||||
|
||||
func noCancel(error) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func newTask(name string, parent *Task, needFinish bool) *Task {
|
||||
var t *Task
|
||||
select {
|
||||
case t = <-taskPool:
|
||||
t.finished.Store(false)
|
||||
default:
|
||||
t = &Task{}
|
||||
}
|
||||
t.name = name
|
||||
t.parent = parent
|
||||
if needFinish {
|
||||
t.ctx, t.cancel = context.WithCancelCause(parent.ctx)
|
||||
} else {
|
||||
t.ctx, t.cancel = parent.ctx, noCancel
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (t *Task) needFinish() bool {
|
||||
return t.ctx != t.parent.ctx
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (t *Task) isCanceled() bool {
|
||||
return t.cancel == nil
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func putTask(t *Task) {
|
||||
select {
|
||||
case taskPool <- t:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (t *Task) addCallback(about string, fn func(), waitSubTasks bool) {
|
||||
if !t.needFinish() {
|
||||
if waitSubTasks {
|
||||
t.parent.addCallback(about, func() {
|
||||
if !t.waitFinish(taskTimeout) {
|
||||
t.reportStucked()
|
||||
}
|
||||
fn()
|
||||
}, false)
|
||||
} else {
|
||||
t.parent.addCallback(about, fn, false)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !waitSubTasks {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
if t.callbacksOnCancel == nil {
|
||||
t.callbacksOnCancel = make(callbacksSet)
|
||||
go func() {
|
||||
<-t.ctx.Done()
|
||||
for c := range t.callbacksOnCancel {
|
||||
go func() {
|
||||
invokeWithRecover(c)
|
||||
t.mu.Lock()
|
||||
delete(t.callbacksOnCancel, c)
|
||||
t.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
t.callbacksOnCancel[&Callback{fn: fn, about: about}] = struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.isCanceled() {
|
||||
log.Panic().
|
||||
Str("task", t.String()).
|
||||
Str("callback", about).
|
||||
Msg("callback added to canceled task")
|
||||
return
|
||||
}
|
||||
|
||||
if t.callbacksOnFinish == nil {
|
||||
t.callbacksOnFinish = make(callbacksSet)
|
||||
}
|
||||
t.callbacksOnFinish[&Callback{
|
||||
fn: fn,
|
||||
about: about,
|
||||
}] = struct{}{}
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (t *Task) addChild(child *Task) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
|
||||
if t.isCanceled() {
|
||||
log.Panic().
|
||||
Str("task", t.String()).
|
||||
Str("child", child.Name()).
|
||||
Msg("child added to canceled task")
|
||||
return
|
||||
}
|
||||
|
||||
if t.children == nil {
|
||||
t.children = make(childrenSet)
|
||||
}
|
||||
t.children[child] = struct{}{}
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func (t *Task) removeChild(child *Task) {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
delete(t.children, child)
|
||||
}
|
||||
|
||||
func (t *Task) runOnFinishCallbacks() {
|
||||
if len(t.callbacksOnFinish) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for c := range t.callbacksOnFinish {
|
||||
go func() {
|
||||
invokeWithRecover(c)
|
||||
t.mu.Lock()
|
||||
delete(t.callbacksOnFinish, c)
|
||||
t.mu.Unlock()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Task) waitFinish(timeout time.Duration) bool {
|
||||
// return directly if already finished
|
||||
if t.isFinished() {
|
||||
return true
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
children, callbacksOnCancel, callbacksOnFinish := t.children, t.callbacksOnCancel, t.callbacksOnFinish
|
||||
t.mu.Unlock()
|
||||
|
||||
ok := true
|
||||
if len(children) != 0 {
|
||||
ok = waitEmpty(children, timeout)
|
||||
}
|
||||
|
||||
if len(callbacksOnCancel) != 0 {
|
||||
ok = ok && waitEmpty(callbacksOnCancel, timeout)
|
||||
}
|
||||
|
||||
if len(callbacksOnFinish) != 0 {
|
||||
ok = ok && waitEmpty(callbacksOnFinish, timeout)
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func waitEmpty[T comparable](set map[T]struct{}, timeout time.Duration) bool {
|
||||
if len(set) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
timer := time.NewTimer(timeout)
|
||||
defer timer.Stop()
|
||||
|
||||
for {
|
||||
if len(set) == 0 {
|
||||
return true
|
||||
}
|
||||
select {
|
||||
case <-timer.C:
|
||||
return false
|
||||
default:
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func fmtCause(cause any) error {
|
||||
switch cause := cause.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case error:
|
||||
return cause
|
||||
case string:
|
||||
return errors.New(cause)
|
||||
default:
|
||||
return fmt.Errorf("%v", cause)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
// This file has the abstract logic of the task system.
|
||||
//
|
||||
// The implementation of the task system is in the impl.go file.
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/yusing/go-proxy/internal/gperr"
|
||||
)
|
||||
|
||||
@@ -35,21 +30,23 @@ type (
|
||||
//
|
||||
// Use Task.Finish to stop all subtasks of the Task.
|
||||
Task struct {
|
||||
name string
|
||||
parent *Task
|
||||
name string
|
||||
ctx context.Context
|
||||
cancel context.CancelCauseFunc
|
||||
done chan struct{}
|
||||
finishCalled bool
|
||||
onCancel *withWg[*Callback]
|
||||
onFinish *withWg[*Callback]
|
||||
children *withWg[*Task]
|
||||
|
||||
parent *Task
|
||||
children childrenSet
|
||||
callbacksOnFinish callbacksSet
|
||||
callbacksOnCancel callbacksSet
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelCauseFunc
|
||||
|
||||
finished atomic.Bool
|
||||
mu sync.Mutex
|
||||
mu sync.Mutex
|
||||
}
|
||||
Parent interface {
|
||||
Context() context.Context
|
||||
// Subtask returns a new subtask with the given name, derived from the parent's context.
|
||||
//
|
||||
// This should not be called after Finish is called on the task or its parent task.
|
||||
Subtask(name string, needFinish bool) *Task
|
||||
Name() string
|
||||
Finish(reason any)
|
||||
@@ -57,124 +54,193 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
childrenSet = map[*Task]struct{}
|
||||
callbacksSet = map[*Callback]struct{}
|
||||
)
|
||||
|
||||
const taskTimeout = 3 * time.Second
|
||||
|
||||
func (t *Task) Context() context.Context {
|
||||
return t.ctx
|
||||
}
|
||||
|
||||
// FinishCause returns the reason / error that caused the task to be finished.
|
||||
func (t *Task) FinishCause() error {
|
||||
return context.Cause(t.ctx)
|
||||
}
|
||||
|
||||
// OnFinished calls fn when the task is canceled and all subtasks are finished.
|
||||
//
|
||||
// It should not be called after Finish is called.
|
||||
func (t *Task) OnFinished(about string, fn func()) {
|
||||
t.addCallback(about, fn, true)
|
||||
}
|
||||
|
||||
// OnCancel calls fn when the task is canceled.
|
||||
//
|
||||
// It should not be called after Finish is called.
|
||||
func (t *Task) OnCancel(about string, fn func()) {
|
||||
t.addCallback(about, fn, false)
|
||||
}
|
||||
|
||||
// Finish cancel all subtasks and wait for them to finish,
|
||||
// then marks the task as finished, with the given reason (if any).
|
||||
func (t *Task) Finish(reason any) {
|
||||
t.mu.Lock()
|
||||
if t.isCanceled() {
|
||||
t.mu.Unlock()
|
||||
return
|
||||
}
|
||||
t.cancel(fmtCause(reason))
|
||||
t.ctx, t.cancel = cancelCtx, nil
|
||||
|
||||
t.mu.Unlock()
|
||||
|
||||
t.finishAndWait()
|
||||
t.finished.Store(true)
|
||||
}
|
||||
|
||||
func (t *Task) finishAndWait() {
|
||||
ok := true
|
||||
|
||||
if !waitEmpty(t.children, taskTimeout) {
|
||||
t.reportStucked()
|
||||
ok = false
|
||||
}
|
||||
t.runOnFinishCallbacks()
|
||||
|
||||
if !t.waitFinish(taskTimeout) {
|
||||
t.reportStucked()
|
||||
ok = false
|
||||
}
|
||||
// clear anyway
|
||||
clear(t.children)
|
||||
clear(t.callbacksOnFinish)
|
||||
|
||||
if t != root && t.needFinish() {
|
||||
t.parent.removeChild(t)
|
||||
}
|
||||
logFinished(t)
|
||||
|
||||
if ok {
|
||||
putTask(t)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Task) isFinished() bool {
|
||||
return t.finished.Load()
|
||||
}
|
||||
|
||||
// Subtask returns a new subtask with the given name, derived from the parent's context.
|
||||
//
|
||||
// This should not be called after Finish is called on the task or its parent task.
|
||||
func (t *Task) Subtask(name string, needFinish bool) *Task {
|
||||
panicIfFinished(t, "Subtask is called")
|
||||
|
||||
child := newTask(name, t, needFinish)
|
||||
|
||||
if needFinish {
|
||||
t.addChild(child)
|
||||
}
|
||||
|
||||
logStarted(child)
|
||||
return child
|
||||
}
|
||||
|
||||
// Name returns the name of the task without parent names.
|
||||
func (t *Task) Name() string {
|
||||
return t.name
|
||||
}
|
||||
|
||||
// String returns the full name of the task.
|
||||
func (t *Task) String() string {
|
||||
if t.parent != root {
|
||||
return t.parent.String() + "." + t.name
|
||||
}
|
||||
return t.name
|
||||
return t.fullName()
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (t *Task) MarshalText() ([]byte, error) {
|
||||
return []byte(t.String()), nil
|
||||
return []byte(t.fullName()), nil
|
||||
}
|
||||
|
||||
func invokeWithRecover(cb *Callback) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Err(fmtCause(err)).Str("callback", cb.about).Msg("panic")
|
||||
panicWithDebugStack()
|
||||
}
|
||||
}()
|
||||
cb.fn()
|
||||
// Finish marks the task as finished, with the given reason (if any).
|
||||
func (t *Task) Finish(reason any) {
|
||||
t.finish(reason, false)
|
||||
}
|
||||
|
||||
// FinishCause returns the reason / error that caused the task to be finished.
|
||||
func (t *Task) FinishCause() error {
|
||||
return context.Cause(t.ctx)
|
||||
}
|
||||
|
||||
// FinishAndWait cancel all subtasks and wait for them to finish,
|
||||
// then marks the task as finished, with the given reason (if any).
|
||||
func (t *Task) FinishAndWait(reason any) {
|
||||
t.finish(reason, true)
|
||||
}
|
||||
|
||||
// OnFinished calls fn when the task is canceled and all subtasks are finished.
|
||||
//
|
||||
// It should not be called after Finish is called.
|
||||
func (t *Task) OnFinished(about string, fn func()) {
|
||||
if !t.needFinish() {
|
||||
t.OnCancel(about, fn)
|
||||
return
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
if t.onFinish == nil {
|
||||
t.onFinish = newWithWg[*Callback]()
|
||||
t.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
<-t.ctx.Done()
|
||||
<-t.done
|
||||
for cb := range t.onFinish.Range {
|
||||
go func(cb *Callback) {
|
||||
invokeWithRecover(cb)
|
||||
t.onFinish.Delete(cb)
|
||||
}(cb)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
t.onFinish.Add(&Callback{fn: fn, about: about})
|
||||
}
|
||||
|
||||
// OnCancel calls fn when the task is canceled.
|
||||
//
|
||||
// It should not be called after Finish is called.
|
||||
func (t *Task) OnCancel(about string, fn func()) {
|
||||
t.mu.Lock()
|
||||
if t.onCancel == nil {
|
||||
t.onCancel = newWithWg[*Callback]()
|
||||
t.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
<-t.ctx.Done()
|
||||
for cb := range t.onCancel.Range {
|
||||
go func(cb *Callback) {
|
||||
invokeWithRecover(cb)
|
||||
t.onCancel.Delete(cb)
|
||||
}(cb)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
t.onCancel.Add(&Callback{fn: fn, about: about})
|
||||
}
|
||||
|
||||
// Subtask returns a new subtask with the given name, derived from the parent's context.
|
||||
//
|
||||
// This should not be called after Finish is called on the task or its parent task.
|
||||
func (t *Task) Subtask(name string, needFinish bool) *Task {
|
||||
t.mu.Lock()
|
||||
if t.children == nil {
|
||||
t.children = newWithWg[*Task]()
|
||||
t.mu.Unlock()
|
||||
} else {
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
child := &Task{
|
||||
name: name,
|
||||
parent: t,
|
||||
}
|
||||
|
||||
t.children.Add(child)
|
||||
|
||||
child.ctx, child.cancel = context.WithCancelCause(t.ctx)
|
||||
|
||||
if needFinish {
|
||||
child.done = make(chan struct{})
|
||||
} else {
|
||||
child.done = closedCh
|
||||
go func() {
|
||||
<-child.ctx.Done()
|
||||
child.Finish(t.FinishCause())
|
||||
}()
|
||||
}
|
||||
|
||||
logStarted(child)
|
||||
return child
|
||||
}
|
||||
|
||||
func (t *Task) finish(reason any, wait bool) {
|
||||
t.mu.Lock()
|
||||
if t.finishCalled {
|
||||
t.mu.Unlock()
|
||||
// wait but not report stucked (again)
|
||||
t.waitFinish(taskTimeout)
|
||||
return
|
||||
}
|
||||
|
||||
t.finishCalled = true
|
||||
t.mu.Unlock()
|
||||
|
||||
if t.needFinish() {
|
||||
close(t.done)
|
||||
}
|
||||
|
||||
t.cancel(fmtCause(reason))
|
||||
if wait && !t.waitFinish(taskTimeout) {
|
||||
t.reportStucked()
|
||||
}
|
||||
if t != root {
|
||||
t.parent.children.Delete(t)
|
||||
}
|
||||
logFinished(t)
|
||||
}
|
||||
|
||||
func (t *Task) waitFinish(timeout time.Duration) bool {
|
||||
if t.children == nil && t.onCancel == nil && t.onFinish == nil {
|
||||
return true
|
||||
}
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
if t.children != nil {
|
||||
t.children.Wait()
|
||||
}
|
||||
if t.onCancel != nil {
|
||||
t.onCancel.Wait()
|
||||
}
|
||||
if t.onFinish != nil {
|
||||
t.onFinish.Wait()
|
||||
}
|
||||
<-t.done
|
||||
close(done)
|
||||
}()
|
||||
timeoutCh := time.After(timeout)
|
||||
select {
|
||||
case <-done:
|
||||
return true
|
||||
case <-timeoutCh:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Task) fullName() string {
|
||||
if t.parent == root {
|
||||
return t.name
|
||||
}
|
||||
return t.parent.fullName() + "." + t.name
|
||||
}
|
||||
|
||||
func (t *Task) needFinish() bool {
|
||||
return t.done != closedCh
|
||||
}
|
||||
|
||||
@@ -12,12 +12,6 @@ func panicWithDebugStack() {
|
||||
panic(string(debug.Stack()))
|
||||
}
|
||||
|
||||
func panicIfFinished(t *Task, reason string) {
|
||||
if t.isFinished() {
|
||||
log.Panic().Msg("task " + t.String() + " is finished but " + reason)
|
||||
}
|
||||
}
|
||||
|
||||
func logStarted(t *Task) {
|
||||
log.Info().Msg("task " + t.String() + " started")
|
||||
}
|
||||
|
||||
@@ -6,10 +6,6 @@ func panicWithDebugStack() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func panicIfFinished(t *Task, reason string) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func logStarted(t *Task) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
expect "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
)
|
||||
|
||||
func testTask() *Task {
|
||||
@@ -35,7 +35,7 @@ func TestChildTaskCancellation(t *testing.T) {
|
||||
|
||||
select {
|
||||
case <-child.Context().Done():
|
||||
ExpectError(t, context.Canceled, child.Context().Err())
|
||||
expect.ErrorIs(t, context.Canceled, child.Context().Err())
|
||||
default:
|
||||
t.Fatal("subTask context was not canceled as expected")
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func TestTaskStuck(t *testing.T) {
|
||||
})
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
task.Finish(nil)
|
||||
task.FinishAndWait(nil)
|
||||
close(done)
|
||||
}()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
@@ -80,10 +80,10 @@ func TestTaskOnCancelOnFinished(t *testing.T) {
|
||||
shouldTrueOnFinish = true
|
||||
})
|
||||
|
||||
ExpectFalse(t, shouldTrueOnFinish)
|
||||
task.Finish(nil)
|
||||
ExpectTrue(t, shouldTrueOnCancel)
|
||||
ExpectTrue(t, shouldTrueOnFinish)
|
||||
expect.False(t, shouldTrueOnFinish)
|
||||
task.FinishAndWait(nil)
|
||||
expect.True(t, shouldTrueOnCancel)
|
||||
expect.True(t, shouldTrueOnFinish)
|
||||
}
|
||||
|
||||
func TestCommonFlowWithGracefulShutdown(t *testing.T) {
|
||||
@@ -97,7 +97,7 @@ func TestCommonFlowWithGracefulShutdown(t *testing.T) {
|
||||
})
|
||||
|
||||
go func() {
|
||||
defer task.Finish(nil)
|
||||
defer task.FinishAndWait(nil)
|
||||
for {
|
||||
select {
|
||||
case <-task.Context().Done():
|
||||
@@ -108,29 +108,28 @@ func TestCommonFlowWithGracefulShutdown(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
ExpectNoError(t, gracefulShutdown(1*time.Second))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
ExpectTrue(t, finished)
|
||||
expect.NoError(t, gracefulShutdown(1*time.Second))
|
||||
expect.True(t, finished)
|
||||
|
||||
ExpectTrue(t, root.waitFinish(1*time.Second))
|
||||
ExpectError(t, context.Canceled, context.Cause(task.Context()))
|
||||
ExpectError(t, ErrProgramExiting, task.Context().Err())
|
||||
ExpectError(t, ErrProgramExiting, task.FinishCause())
|
||||
expect.ErrorIs(t, ErrProgramExiting, context.Cause(task.Context()))
|
||||
expect.ErrorIs(t, context.Canceled, task.Context().Err())
|
||||
expect.ErrorIs(t, ErrProgramExiting, task.FinishCause())
|
||||
}
|
||||
|
||||
func TestTimeoutOnGracefulShutdown(t *testing.T) {
|
||||
t.Cleanup(testCleanup)
|
||||
_ = testTask()
|
||||
|
||||
ExpectError(t, context.DeadlineExceeded, gracefulShutdown(time.Millisecond))
|
||||
expect.ErrorIs(t, context.DeadlineExceeded, gracefulShutdown(time.Millisecond))
|
||||
}
|
||||
|
||||
func TestFinishMultipleCalls(t *testing.T) {
|
||||
t.Cleanup(testCleanup)
|
||||
task := testTask()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(5)
|
||||
for range 5 {
|
||||
n := 20
|
||||
wg.Add(n)
|
||||
for range n {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
task.Finish(nil)
|
||||
@@ -157,8 +156,8 @@ func BenchmarkTasksNeedFinish(b *testing.B) {
|
||||
|
||||
func BenchmarkContextWithCancel(b *testing.B) {
|
||||
for b.Loop() {
|
||||
task, taskCancel := context.WithCancel(b.Context())
|
||||
taskCancel()
|
||||
task, taskCancel := context.WithCancelCause(b.Context())
|
||||
taskCancel(nil)
|
||||
<-task.Done()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package task
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
@@ -13,6 +14,31 @@ import (
|
||||
|
||||
var ErrProgramExiting = errors.New("program exiting")
|
||||
|
||||
var root *Task
|
||||
|
||||
var closedCh = make(chan struct{})
|
||||
|
||||
func init() {
|
||||
close(closedCh)
|
||||
initRoot()
|
||||
}
|
||||
|
||||
func initRoot() {
|
||||
ctx, cancel := context.WithCancelCause(context.Background())
|
||||
root = &Task{
|
||||
name: "root",
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
done: closedCh,
|
||||
}
|
||||
root.parent = root
|
||||
}
|
||||
|
||||
func testCleanup() {
|
||||
root.cancel(nil)
|
||||
initRoot()
|
||||
}
|
||||
|
||||
// RootTask returns a new Task with the given name, derived from the root context.
|
||||
//
|
||||
//go:inline
|
||||
@@ -29,7 +55,7 @@ func RootContextCanceled() <-chan struct{} {
|
||||
}
|
||||
|
||||
func OnProgramExit(about string, fn func()) {
|
||||
root.OnFinished(about, fn)
|
||||
root.OnCancel(about, fn)
|
||||
}
|
||||
|
||||
// WaitExit waits for a signal to shutdown the program, and then waits for all tasks to finish, up to the given timeout.
|
||||
@@ -59,19 +85,33 @@ func WaitExit(shutdownTimeout int) {
|
||||
// still running when the timeout was reached, and their current tree
|
||||
// of subtasks.
|
||||
func gracefulShutdown(timeout time.Duration) error {
|
||||
root.mu.Lock()
|
||||
if root.isCanceled() {
|
||||
cause := context.Cause(root.ctx)
|
||||
root.mu.Unlock()
|
||||
return cause
|
||||
}
|
||||
root.mu.Unlock()
|
||||
|
||||
root.cancel(ErrProgramExiting)
|
||||
ok := waitEmpty(root.children, timeout)
|
||||
root.runOnFinishCallbacks()
|
||||
if !ok || !root.waitFinish(timeout) {
|
||||
go root.Finish(ErrProgramExiting)
|
||||
if !root.waitFinish(timeout) {
|
||||
return context.DeadlineExceeded
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func invokeWithRecover(cb *Callback) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Err(fmtCause(err)).Str("callback", cb.about).Msg("panic")
|
||||
panicWithDebugStack()
|
||||
}
|
||||
}()
|
||||
cb.fn()
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func fmtCause(cause any) error {
|
||||
switch cause := cause.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case error:
|
||||
return cause
|
||||
case string:
|
||||
return errors.New(cause)
|
||||
default:
|
||||
return fmt.Errorf("%v", cause)
|
||||
}
|
||||
}
|
||||
|
||||
48
internal/task/with.go
Normal file
48
internal/task/with.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/puzpuzpuz/xsync/v4"
|
||||
)
|
||||
|
||||
type withWg[T comparable] struct {
|
||||
m *xsync.Map[T, struct{}]
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func newWithWg[T comparable]() *withWg[T] {
|
||||
return &withWg[T]{
|
||||
m: xsync.NewMap[T, struct{}](),
|
||||
}
|
||||
}
|
||||
|
||||
func (w *withWg[T]) Add(ele T) {
|
||||
w.wg.Add(1)
|
||||
w.m.Store(ele, struct{}{})
|
||||
}
|
||||
|
||||
func (w *withWg[T]) AddWithoutWG(ele T) {
|
||||
w.m.Store(ele, struct{}{})
|
||||
}
|
||||
|
||||
func (w *withWg[T]) Delete(key T) {
|
||||
w.wg.Done()
|
||||
w.m.Delete(key)
|
||||
}
|
||||
|
||||
func (w *withWg[T]) DeleteWithoutWG(key T) {
|
||||
w.m.Delete(key)
|
||||
}
|
||||
|
||||
func (w *withWg[T]) Wait() {
|
||||
w.wg.Wait()
|
||||
}
|
||||
|
||||
func (w *withWg[T]) Range(yield func(T) bool) {
|
||||
for ele := range w.m.Range {
|
||||
if !yield(ele) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ module github.com/yusing/go-proxy/internal/utils
|
||||
go 1.24.3
|
||||
|
||||
require (
|
||||
github.com/goccy/go-yaml v1.17.1
|
||||
github.com/goccy/go-yaml v1.18.0
|
||||
github.com/puzpuzpuz/xsync/v4 v4.1.0
|
||||
github.com/rs/zerolog v1.34.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
|
||||
@@ -6,7 +6,7 @@ replace github.com/yusing/go-proxy/internal/utils => ../internal/utils
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/yusing/go-proxy/internal/utils v0.0.0-00010101000000-000000000000
|
||||
github.com/yusing/go-proxy/internal/utils v0.0.0-20250529124236-93a81fd558e6
|
||||
golang.org/x/net v0.40.0
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user