mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-24 17:28:31 +02:00
Apply compat patch
This commit is contained in:
@@ -20,7 +20,6 @@ replace (
|
|||||||
exclude github.com/containerd/nerdctl/mod/tigron v0.0.0
|
exclude github.com/containerd/nerdctl/mod/tigron v0.0.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/sonic v1.15.0
|
|
||||||
github.com/gin-gonic/gin v1.11.0
|
github.com/gin-gonic/gin v1.11.0
|
||||||
github.com/gorilla/websocket v1.5.3
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/pion/dtls/v3 v3.1.2
|
github.com/pion/dtls/v3 v3.1.2
|
||||||
@@ -33,9 +32,11 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||||
|
github.com/bytedance/sonic v1.15.0 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
github.com/bytedance/sonic/loader v0.5.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
@@ -44,6 +45,7 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/cli v29.2.1+incompatible // indirect
|
github.com/docker/cli v29.2.1+incompatible // indirect
|
||||||
|
github.com/docker/docker v28.5.2+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.6.0 // indirect
|
github.com/docker/go-connections v0.6.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/ebitengine/purego v0.10.0 // indirect
|
github.com/ebitengine/purego v0.10.0 // indirect
|
||||||
@@ -68,7 +70,7 @@ require (
|
|||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
github.com/moby/moby/api v1.52.0 // indirect
|
github.com/moby/moby/api v1.52.0 // indirect
|
||||||
github.com/moby/moby/client v0.2.1 // indirect
|
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
@@ -76,6 +78,7 @@ require (
|
|||||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pion/logging v0.2.4 // indirect
|
github.com/pion/logging v0.2.4 // indirect
|
||||||
github.com/pion/transport/v4 v4.0.1 // indirect
|
github.com/pion/transport/v4 v4.0.1 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect
|
github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect
|
||||||
@@ -97,8 +100,10 @@ require (
|
|||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.40.0 // indirect
|
go.opentelemetry.io/otel v1.40.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||||
golang.org/x/arch v0.24.0 // indirect
|
golang.org/x/arch v0.24.0 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.50.0 // indirect
|
golang.org/x/net v0.50.0 // indirect
|
||||||
|
|||||||
34
agent/go.sum
34
agent/go.sum
@@ -1,3 +1,5 @@
|
|||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
||||||
@@ -24,6 +26,8 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG
|
|||||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
||||||
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
@@ -39,6 +43,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/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
|
github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
|
||||||
github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
@@ -95,6 +101,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
|
|||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotify/server/v2 v2.9.0 h1:2zRCl28wkq0oc6YNbyJS2n0dDOOVvOS3Oez5AG2ij54=
|
github.com/gotify/server/v2 v2.9.0 h1:2zRCl28wkq0oc6YNbyJS2n0dDOOVvOS3Oez5AG2ij54=
|
||||||
github.com/gotify/server/v2 v2.9.0/go.mod h1:249wwlUqHTr0QsiKARGtFVqds0pNLIMjYLinHyMACdQ=
|
github.com/gotify/server/v2 v2.9.0/go.mod h1:249wwlUqHTr0QsiKARGtFVqds0pNLIMjYLinHyMACdQ=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
|
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 h1:9Nu54bhS/H/Kgo2/7xNSUuC5G28VR8ljfrLKU2G4IjU=
|
||||||
@@ -130,13 +138,19 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
|||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
||||||
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
||||||
github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
|
||||||
|
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
@@ -155,6 +169,7 @@ github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k
|
|||||||
github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=
|
github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM=
|
||||||
github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4=
|
github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4=
|
||||||
github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
@@ -220,6 +235,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb
|
|||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||||
@@ -228,6 +247,8 @@ go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4A
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
@@ -246,6 +267,7 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
|||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@@ -258,6 +280,12 @@ golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
|||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260223185530-2f722ef697dc h1:51Wupg8spF+5FC6D+iMKbOddFjMckETnNnEiZ+HX37s=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260223185530-2f722ef697dc/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||||
|
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -268,5 +296,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
|
|
||||||
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -15,7 +16,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/agent/pkg/agent/common"
|
"github.com/yusing/godoxy/agent/pkg/agent/common"
|
||||||
@@ -366,7 +366,7 @@ func (cfg *AgentConfig) fetchJSON(ctx context.Context, endpoint string, out any)
|
|||||||
return resp.StatusCode, nil
|
return resp.StatusCode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sonic.Unmarshal(data, out)
|
err = json.Unmarshal(data, out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package agentproxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
route "github.com/yusing/godoxy/internal/route/types"
|
route "github.com/yusing/godoxy/internal/route/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ func proxyConfigFromHeaders(h http.Header) (cfg Config, err error) {
|
|||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sonic.Unmarshal(cfgJSON, &cfg)
|
err = json.Unmarshal(cfgJSON, &cfg)
|
||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ func (cfg *Config) SetAgentProxyConfigHeadersLegacy(h http.Header) {
|
|||||||
func (cfg *Config) SetAgentProxyConfigHeaders(h http.Header) {
|
func (cfg *Config) SetAgentProxyConfigHeaders(h http.Header) {
|
||||||
h.Set(HeaderXProxyHost, cfg.Host)
|
h.Set(HeaderXProxyHost, cfg.Host)
|
||||||
h.Set(HeaderXProxyScheme, string(cfg.Scheme))
|
h.Set(HeaderXProxyScheme, string(cfg.Scheme))
|
||||||
cfgJSON, _ := sonic.Marshal(cfg.HTTPConfig)
|
cfgJSON, _ := json.Marshal(cfg.HTTPConfig)
|
||||||
cfgBase64 := base64.StdEncoding.EncodeToString(cfgJSON)
|
cfgBase64 := base64.StdEncoding.EncodeToString(cfgJSON)
|
||||||
h.Set(HeaderXProxyConfig, cfgBase64)
|
h.Set(HeaderXProxyConfig, cfgBase64)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -8,7 +9,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
healthcheck "github.com/yusing/godoxy/internal/health/check"
|
healthcheck "github.com/yusing/godoxy/internal/health/check"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ func CheckHealth(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
sonic.ConfigDefault.NewEncoder(w).Encode(result)
|
json.NewEncoder(w).Encode(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseMsOrDefault(msStr string) time.Duration {
|
func parseMsOrDefault(msStr string) time.Duration {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
@@ -51,7 +51,7 @@ func NewAgentHandler() http.Handler {
|
|||||||
Runtime: env.Runtime,
|
Runtime: env.Runtime,
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
sonic.ConfigDefault.NewEncoder(w).Encode(agentInfo)
|
json.NewEncoder(w).Encode(agentInfo)
|
||||||
})
|
})
|
||||||
mux.HandleEndpoint("GET", agent.EndpointHealth, CheckHealth)
|
mux.HandleEndpoint("GET", agent.EndpointHealth, CheckHealth)
|
||||||
mux.HandleEndpoint("GET", agent.EndpointSystemInfo, metricsHandler.ServeHTTP)
|
mux.HandleEndpoint("GET", agent.EndpointSystemInfo, metricsHandler.ServeHTTP)
|
||||||
|
|||||||
13
go.mod
13
go.mod
@@ -44,13 +44,12 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bytedance/gopkg v0.1.3 // xxhash64 for fast hash
|
github.com/bytedance/gopkg v0.1.3 // xxhash64 for fast hash
|
||||||
github.com/bytedance/sonic v1.15.0 // fast json parsing
|
github.com/bytedance/sonic v1.15.0 // indirect; fast json parsing
|
||||||
github.com/docker/cli v29.2.1+incompatible // needs docker/cli/cli/connhelper connection helper for docker client
|
github.com/docker/cli v29.2.1+incompatible // needs docker/cli/cli/connhelper connection helper for docker client
|
||||||
github.com/goccy/go-yaml v1.19.2 // yaml parsing for different config files
|
github.com/goccy/go-yaml v1.19.2 // yaml parsing for different config files
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1 // jwt authentication
|
github.com/golang-jwt/jwt/v5 v5.3.1 // jwt authentication
|
||||||
github.com/luthermonson/go-proxmox v0.4.0 // proxmox API client
|
github.com/luthermonson/go-proxmox v0.4.0 // proxmox API client
|
||||||
github.com/moby/moby/api v1.52.0 // docker API
|
github.com/moby/moby/api v1.52.0 // docker API
|
||||||
github.com/moby/moby/client v0.2.1 // docker client
|
|
||||||
github.com/oschwald/maxminddb-golang v1.13.1 // maxminddb for geoip database
|
github.com/oschwald/maxminddb-golang v1.13.1 // maxminddb for geoip database
|
||||||
github.com/quic-go/quic-go v0.59.0 // http3 support
|
github.com/quic-go/quic-go v0.59.0 // http3 support
|
||||||
github.com/shirou/gopsutil/v4 v4.26.1 // system information
|
github.com/shirou/gopsutil/v4 v4.26.1 // system information
|
||||||
@@ -160,6 +159,7 @@ require (
|
|||||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
|
github.com/docker/docker v28.5.2+incompatible
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
@@ -194,3 +194,12 @@ require (
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
golang.org/x/arch v0.24.0 // indirect
|
golang.org/x/arch v0.24.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||||
|
github.com/moby/term v0.5.2 // indirect
|
||||||
|
github.com/morikuni/aec v1.1.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect
|
||||||
|
)
|
||||||
|
|||||||
27
go.sum
27
go.sum
@@ -23,6 +23,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
|
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
|
||||||
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
|
||||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
|
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
|
||||||
@@ -65,6 +67,8 @@ github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG
|
|||||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
|
||||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||||
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -78,6 +82,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/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0=
|
||||||
github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
|
github.com/docker/cli v29.2.1+incompatible h1:n3Jt0QVCN65eiVBoUTZQM9mcQICCJt3akW4pKAbKdJg=
|
||||||
github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v29.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
|
||||||
|
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
|
||||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
@@ -159,6 +165,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
|
|||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gotify/server/v2 v2.9.0 h1:2zRCl28wkq0oc6YNbyJS2n0dDOOVvOS3Oez5AG2ij54=
|
github.com/gotify/server/v2 v2.9.0 h1:2zRCl28wkq0oc6YNbyJS2n0dDOOVvOS3Oez5AG2ij54=
|
||||||
github.com/gotify/server/v2 v2.9.0/go.mod h1:249wwlUqHTr0QsiKARGtFVqds0pNLIMjYLinHyMACdQ=
|
github.com/gotify/server/v2 v2.9.0/go.mod h1:249wwlUqHTr0QsiKARGtFVqds0pNLIMjYLinHyMACdQ=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
|
||||||
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
|
||||||
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||||
@@ -216,13 +224,19 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
|||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
github.com/moby/moby/api v1.52.0 h1:00BtlJY4MXkkt84WhUZPRqt5TvPbgig2FZvTbe3igYg=
|
||||||
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
github.com/moby/moby/api v1.52.0/go.mod h1:8mb+ReTlisw4pS6BRzCMts5M49W5M7bKt1cJy/YbAqc=
|
||||||
github.com/moby/moby/client v0.2.1 h1:1Grh1552mvv6i+sYOdY+xKKVTvzJegcVMhuXocyDz/k=
|
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
|
||||||
github.com/moby/moby/client v0.2.1/go.mod h1:O+/tw5d4a1Ha/ZA/tPxIZJapJRUS6LNZ1wiVRxYHyUE=
|
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
|
||||||
|
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
|
||||||
|
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||||
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ=
|
||||||
|
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||||
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
|
github.com/nrdcg/goacmedns v0.2.0 h1:ADMbThobzEMnr6kg2ohs4KGa3LFqmgiBA22/6jUWJR0=
|
||||||
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
github.com/nrdcg/goacmedns v0.2.0/go.mod h1:T5o6+xvSLrQpugmwHvrSNkzWht0UGAwj2ACBMhh73Cg=
|
||||||
github.com/nrdcg/goinwx v0.12.0 h1:ujdUqDBnaRSFwzVnImvPHYw3w3m9XgmGImNUw1GyMb4=
|
github.com/nrdcg/goinwx v0.12.0 h1:ujdUqDBnaRSFwzVnImvPHYw3w3m9XgmGImNUw1GyMb4=
|
||||||
@@ -255,6 +269,7 @@ github.com/pires/go-proxyproto v0.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG6
|
|||||||
github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
|
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
|
||||||
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||||
@@ -341,6 +356,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb
|
|||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||||
@@ -349,6 +368,8 @@ go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4A
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
@@ -472,5 +493,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
|
|
||||||
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package agentpool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
agentPkg "github.com/yusing/godoxy/agent/pkg/agent"
|
agentPkg "github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
@@ -63,7 +63,7 @@ func (agent *Agent) DoHealthCheck(timeout time.Duration, query string) (ret Heal
|
|||||||
ret.Detail = fmt.Sprintf("HTTP %d %s", status, resp.Body())
|
ret.Detail = fmt.Sprintf("HTTP %d %s", status, resp.Body())
|
||||||
return ret, nil
|
return ret, nil
|
||||||
} else {
|
} else {
|
||||||
err = sonic.Unmarshal(resp.Body(), &ret)
|
err = json.Unmarshal(resp.Body(), &ret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gin-gonic/gin/codec/json"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
apiV1 "github.com/yusing/godoxy/internal/api/v1"
|
apiV1 "github.com/yusing/godoxy/internal/api/v1"
|
||||||
@@ -49,8 +47,6 @@ func NewHandler(requireAuth bool) *gin.Engine {
|
|||||||
r.Use(ErrorLoggingMiddleware())
|
r.Use(ErrorLoggingMiddleware())
|
||||||
r.Use(NoCache())
|
r.Use(NoCache())
|
||||||
|
|
||||||
log.Debug().Msg("gin codec json.API: " + reflect.TypeOf(json.API).Name())
|
|
||||||
|
|
||||||
r.GET("/api/v1/version", apiV1.Version)
|
r.GET("/api/v1/version", apiV1.Version)
|
||||||
|
|
||||||
if auth.IsEnabled() && requireAuth {
|
if auth.IsEnabled() && requireAuth {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
apitypes "github.com/yusing/goutils/apitypes"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
)
|
)
|
||||||
@@ -43,22 +42,22 @@ func GetContainer(c *gin.Context) {
|
|||||||
|
|
||||||
defer dockerClient.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
cont, err := dockerClient.ContainerInspect(c.Request.Context(), id, client.ContainerInspectOptions{})
|
cont, err := dockerClient.ContainerInspect(c.Request.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to inspect container"))
|
c.Error(apitypes.InternalServerError(err, "failed to inspect container"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var state ContainerState
|
var state ContainerState
|
||||||
if cont.Container.State != nil {
|
if cont.State != nil {
|
||||||
state = cont.Container.State.Status
|
state = cont.State.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, &Container{
|
c.JSON(http.StatusOK, &Container{
|
||||||
Server: dockerCfg.URL,
|
Server: dockerCfg.URL,
|
||||||
Name: cont.Container.Name,
|
Name: cont.Name,
|
||||||
ID: cont.Container.ID,
|
ID: cont.ID,
|
||||||
Image: cont.Container.Image,
|
Image: cont.Image,
|
||||||
State: state,
|
State: state,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/api/types/container"
|
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
|
|
||||||
@@ -41,12 +40,12 @@ func GetContainers(ctx context.Context, dockerClients DockerClients) ([]Containe
|
|||||||
errs := gperr.NewBuilder("failed to get containers")
|
errs := gperr.NewBuilder("failed to get containers")
|
||||||
containers := make([]Container, 0)
|
containers := make([]Container, 0)
|
||||||
for name, dockerClient := range dockerClients {
|
for name, dockerClient := range dockerClients {
|
||||||
conts, err := dockerClient.ContainerList(ctx, client.ContainerListOptions{All: true})
|
conts, err := dockerClient.ContainerList(ctx, container.ListOptions{All: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.AddSubject(err, name)
|
errs.AddSubject(err, name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, cont := range conts.Items {
|
for _, cont := range conts {
|
||||||
containers = append(containers, Container{
|
containers = append(containers, Container{
|
||||||
Server: name,
|
Server: name,
|
||||||
Name: cont.Names[0],
|
Name: cont.Names[0],
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
dockerSystem "github.com/docker/docker/api/types/system"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
dockerSystem "github.com/moby/moby/api/types/system"
|
|
||||||
"github.com/moby/moby/client"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
strutils "github.com/yusing/goutils/strings"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
|
|
||||||
@@ -65,13 +64,13 @@ func GetDockerInfo(ctx context.Context, dockerClients DockerClients) ([]dockerIn
|
|||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for name, dockerClient := range dockerClients {
|
for name, dockerClient := range dockerClients {
|
||||||
info, err := dockerClient.Info(ctx, client.InfoOptions{})
|
info, err := dockerClient.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.AddSubject(err, name)
|
errs.AddSubject(err, name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info.Info.Name = name
|
info.Name = name
|
||||||
dockerInfos[i] = toDockerInfo(info.Info)
|
dockerInfos[i] = toDockerInfo(info)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/api/pkg/stdcopy"
|
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
apitypes "github.com/yusing/goutils/apitypes"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
@@ -73,7 +73,7 @@ func Logs(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
defer dockerClient.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
opts := client.ContainerLogsOptions{
|
opts := container.LogsOptions{
|
||||||
ShowStdout: queryParams.Stdout,
|
ShowStdout: queryParams.Stdout,
|
||||||
ShowStderr: queryParams.Stderr,
|
ShowStderr: queryParams.Stderr,
|
||||||
Since: queryParams.Since,
|
Since: queryParams.Since,
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package dockerapi
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
apitypes "github.com/yusing/goutils/apitypes"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RestartRequest struct {
|
type RestartRequest struct {
|
||||||
ID string `json:"id" binding:"required"`
|
ID string `json:"id" binding:"required"`
|
||||||
client.ContainerRestartOptions
|
container.StopOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// @x-id "restart"
|
// @x-id "restart"
|
||||||
@@ -20,7 +20,7 @@ type RestartRequest struct {
|
|||||||
// @Description Restart container by container id
|
// @Description Restart container by container id
|
||||||
// @Tags docker
|
// @Tags docker
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body RestartRequest true "Request"
|
// @Param request body StopRequest true "Request"
|
||||||
// @Success 200 {object} apitypes.SuccessResponse
|
// @Success 200 {object} apitypes.SuccessResponse
|
||||||
// @Failure 400 {object} apitypes.ErrorResponse "Invalid request"
|
// @Failure 400 {object} apitypes.ErrorResponse "Invalid request"
|
||||||
// @Failure 403 {object} apitypes.ErrorResponse
|
// @Failure 403 {object} apitypes.ErrorResponse
|
||||||
@@ -48,7 +48,7 @@ func Restart(c *gin.Context) {
|
|||||||
|
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
_, err = client.ContainerRestart(c.Request.Context(), req.ID, req.ContainerRestartOptions)
|
err = client.ContainerRestart(c.Request.Context(), req.ID, req.StopOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to restart container"))
|
c.Error(apitypes.InternalServerError(err, "failed to restart container"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package dockerapi
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
apitypes "github.com/yusing/goutils/apitypes"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StartRequest struct {
|
type StartRequest struct {
|
||||||
ID string `json:"id" binding:"required"`
|
ID string `json:"id" binding:"required"`
|
||||||
client.ContainerStartOptions
|
container.StartOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// @x-id "start"
|
// @x-id "start"
|
||||||
@@ -48,7 +48,7 @@ func Start(c *gin.Context) {
|
|||||||
|
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
_, err = client.ContainerStart(c.Request.Context(), req.ID, req.ContainerStartOptions)
|
err = client.ContainerStart(c.Request.Context(), req.ID, req.StartOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to start container"))
|
c.Error(apitypes.InternalServerError(err, "failed to start container"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/moby/moby/api/types/container"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
@@ -68,7 +67,7 @@ func Stats(c *gin.Context) {
|
|||||||
defer dockerClient.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
if httpheaders.IsWebsocket(c.Request.Header) {
|
if httpheaders.IsWebsocket(c.Request.Header) {
|
||||||
stats, err := dockerClient.ContainerStats(c.Request.Context(), id, client.ContainerStatsOptions{Stream: true})
|
stats, err := dockerClient.ContainerStats(c.Request.Context(), id, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to get container stats"))
|
c.Error(apitypes.InternalServerError(err, "failed to get container stats"))
|
||||||
return
|
return
|
||||||
@@ -102,7 +101,7 @@ func Stats(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stats, err := dockerClient.ContainerStats(c.Request.Context(), id, client.ContainerStatsOptions{Stream: false})
|
stats, err := dockerClient.ContainerStats(c.Request.Context(), id, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to get container stats"))
|
c.Error(apitypes.InternalServerError(err, "failed to get container stats"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ package dockerapi
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
apitypes "github.com/yusing/goutils/apitypes"
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StopRequest struct {
|
type StopRequest struct {
|
||||||
ID string `json:"id" binding:"required"`
|
ID string `json:"id" binding:"required"`
|
||||||
client.ContainerStopOptions
|
container.StopOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// @x-id "stop"
|
// @x-id "stop"
|
||||||
@@ -48,7 +48,7 @@ func Stop(c *gin.Context) {
|
|||||||
|
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
_, err = client.ContainerStop(c.Request.Context(), req.ID, req.ContainerStopOptions)
|
err = client.ContainerStop(c.Request.Context(), req.ID, req.StopOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(apitypes.InternalServerError(err, "failed to stop container"))
|
c.Error(apitypes.InternalServerError(err, "failed to stop container"))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/cenkalti/backoff/v5"
|
"github.com/cenkalti/backoff/v5"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
@@ -241,7 +240,7 @@ func marshalSystemInfo(ws *websocket.Manager, agentName string, systemInfo any)
|
|||||||
defer bufFromPool.release(bufFromPool.RawMessage)
|
defer bufFromPool.release(bufFromPool.RawMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := sonic.ConfigDefault.NewEncoder(buf).Encode(map[string]any{
|
err := json.NewEncoder(buf).Encode(map[string]any{
|
||||||
agentName: systemInfo,
|
agentName: systemInfo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
httputils "github.com/yusing/goutils/http"
|
httputils "github.com/yusing/goutils/http"
|
||||||
@@ -107,7 +107,7 @@ type UserPassAuthCallbackRequest struct {
|
|||||||
|
|
||||||
func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
func (auth *UserPassAuth) PostAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var creds UserPassAuthCallbackRequest
|
var creds UserPassAuthCallbackRequest
|
||||||
err := sonic.ConfigDefault.NewDecoder(r.Body).Decode(&creds)
|
err := json.NewDecoder(r.Body).Decode(&creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "invalid request", http.StatusBadRequest)
|
http.Error(w, "invalid request", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/connhelper"
|
"github.com/docker/cli/cli/connhelper"
|
||||||
"github.com/moby/moby/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/godoxy/internal/agentpool"
|
"github.com/yusing/godoxy/internal/agentpool"
|
||||||
@@ -198,7 +198,9 @@ func NewClient(cfg types.DockerProviderConfig, unique ...bool) (*SharedClient, e
|
|||||||
opt = append(opt, client.WithTLSClientConfig(cfg.TLS.CAFile, cfg.TLS.CertFile, cfg.TLS.KeyFile))
|
opt = append(opt, client.WithTLSClientConfig(cfg.TLS.CAFile, cfg.TLS.CertFile, cfg.TLS.KeyFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := client.New(opt...)
|
opt = append(opt, client.WithAPIVersionNegotiation())
|
||||||
|
|
||||||
|
client, err := client.NewClientWithOpts(opt...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/moby/moby/api/types/container"
|
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||||
"github.com/yusing/godoxy/internal/agentpool"
|
"github.com/yusing/godoxy/internal/agentpool"
|
||||||
"github.com/yusing/godoxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
@@ -99,18 +98,18 @@ func UpdatePorts(ctx context.Context, c *types.Container) error {
|
|||||||
}
|
}
|
||||||
defer dockerClient.Close()
|
defer dockerClient.Close()
|
||||||
|
|
||||||
inspect, err := dockerClient.ContainerInspect(ctx, c.ContainerID, client.ContainerInspectOptions{})
|
inspect, err := dockerClient.ContainerInspect(ctx, c.ContainerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for port := range inspect.Container.Config.ExposedPorts {
|
for port := range inspect.Config.ExposedPorts {
|
||||||
proto, portStr := nat.SplitProtoPort(port.String())
|
proto, portStr := nat.SplitProtoPort(string(port))
|
||||||
portInt, _ := nat.ParsePort(portStr)
|
portInt, _ := nat.ParsePort(portStr)
|
||||||
if portInt == 0 {
|
if portInt == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.PublicPortMapping[portInt] = container.PortSummary{
|
c.PublicPortMapping[portInt] = container.Port{
|
||||||
PublicPort: uint16(portInt), //nolint:gosec
|
PublicPort: uint16(portInt), //nolint:gosec
|
||||||
PrivatePort: uint16(portInt), //nolint:gosec
|
PrivatePort: uint16(portInt), //nolint:gosec
|
||||||
Type: proto,
|
Type: proto,
|
||||||
@@ -211,8 +210,8 @@ func setPrivateHostname(c *types.Container, helper containerHelper) {
|
|||||||
}
|
}
|
||||||
if c.Network != "" {
|
if c.Network != "" {
|
||||||
v, hasNetwork := helper.NetworkSettings.Networks[c.Network]
|
v, hasNetwork := helper.NetworkSettings.Networks[c.Network]
|
||||||
if hasNetwork && v.IPAddress.IsValid() {
|
if hasNetwork && v.IPAddress != "" {
|
||||||
c.PrivateHostname = v.IPAddress.String()
|
c.PrivateHostname = v.IPAddress
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var hasComposeNetwork bool
|
var hasComposeNetwork bool
|
||||||
@@ -220,9 +219,9 @@ func setPrivateHostname(c *types.Container, helper containerHelper) {
|
|||||||
if proj := DockerComposeProject(c); proj != "" {
|
if proj := DockerComposeProject(c); proj != "" {
|
||||||
newNetwork := fmt.Sprintf("%s_%s", proj, c.Network)
|
newNetwork := fmt.Sprintf("%s_%s", proj, c.Network)
|
||||||
v, hasComposeNetwork = helper.NetworkSettings.Networks[newNetwork]
|
v, hasComposeNetwork = helper.NetworkSettings.Networks[newNetwork]
|
||||||
if hasComposeNetwork && v.IPAddress.IsValid() {
|
if hasComposeNetwork && v.IPAddress != "" {
|
||||||
c.Network = newNetwork // update network to the new one
|
c.Network = newNetwork // update network to the new one
|
||||||
c.PrivateHostname = v.IPAddress.String()
|
c.PrivateHostname = v.IPAddress
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,9 +234,9 @@ func setPrivateHostname(c *types.Container, helper containerHelper) {
|
|||||||
}
|
}
|
||||||
// fallback to first network if no network is specified
|
// fallback to first network if no network is specified
|
||||||
for k, v := range helper.NetworkSettings.Networks {
|
for k, v := range helper.NetworkSettings.Networks {
|
||||||
if v.IPAddress.IsValid() {
|
if v.IPAddress != "" {
|
||||||
c.Network = k // update network to the first network
|
c.Network = k // update network to the first network
|
||||||
c.PrivateHostname = v.IPAddress.String()
|
c.PrivateHostname = v.IPAddress
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package docker
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/yusing/ds/ordered"
|
"github.com/yusing/ds/ordered"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
strutils "github.com/yusing/goutils/strings"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package docker
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
expect "github.com/yusing/goutils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ package docker
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/moby/moby/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var listOptions = client.ContainerListOptions{
|
var listOptions = container.ListOptions{
|
||||||
// created|restarting|running|removing|paused|exited|dead
|
// created|restarting|running|removing|paused|exited|dead
|
||||||
// Filters: filters.NewArgs(
|
// Filters: filters.NewArgs(
|
||||||
// filters.Arg("status", "created"),
|
// filters.Arg("status", "created"),
|
||||||
@@ -31,7 +31,7 @@ func ListContainers(ctx context.Context, dockerCfg types.DockerProviderConfig) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return containers.Items, nil
|
return containers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsErrConnectionFailed(err error) bool {
|
func IsErrConnectionFailed(err error) bool {
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ package healthcheck
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/moby/moby/api/types/container"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
httputils "github.com/yusing/goutils/http"
|
httputils "github.com/yusing/goutils/http"
|
||||||
@@ -46,7 +45,7 @@ func Docker(ctx context.Context, state *DockerHealthcheckState, timeout time.Dur
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// the actual inspect response is intercepted and returned as RequestInterceptedError
|
// the actual inspect response is intercepted and returned as RequestInterceptedError
|
||||||
_, err := state.client.ContainerInspect(ctx, state.containerID, client.ContainerInspectOptions{})
|
_, err := state.client.ContainerInspect(ctx, state.containerID)
|
||||||
|
|
||||||
var interceptedErr *httputils.RequestInterceptedError
|
var interceptedErr *httputils.RequestInterceptedError
|
||||||
if !httputils.AsRequestInterceptedError(err, &interceptedErr) {
|
if !httputils.AsRequestInterceptedError(err, &interceptedErr) {
|
||||||
@@ -108,7 +107,7 @@ func interceptDockerInspectResponse(resp *http.Response) (intercepted bool, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
var state container.State
|
var state container.State
|
||||||
err = sonic.Unmarshal(body, &state)
|
err = json.Unmarshal(body, &state)
|
||||||
release(body)
|
release(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package iconlist
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
@@ -55,7 +55,7 @@ func init() {
|
|||||||
|
|
||||||
func InitCache() {
|
func InitCache() {
|
||||||
m := make(IconMap)
|
m := make(IconMap)
|
||||||
err := serialization.LoadFileIfExist(common.IconListCachePath, &m, sonic.Unmarshal)
|
err := serialization.LoadFileIfExist(common.IconListCachePath, &m, json.Unmarshal)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
// backward compatible
|
// backward compatible
|
||||||
@@ -63,13 +63,13 @@ func InitCache() {
|
|||||||
Icons IconMap
|
Icons IconMap
|
||||||
LastUpdate time.Time
|
LastUpdate time.Time
|
||||||
}{}
|
}{}
|
||||||
err = serialization.LoadFileIfExist(common.IconListCachePath, &oldFormat, sonic.Unmarshal)
|
err = serialization.LoadFileIfExist(common.IconListCachePath, &oldFormat, json.Unmarshal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("failed to load icons")
|
log.Error().Err(err).Msg("failed to load icons")
|
||||||
} else {
|
} else {
|
||||||
m = oldFormat.Icons
|
m = oldFormat.Icons
|
||||||
// store it to disk immediately
|
// store it to disk immediately
|
||||||
_ = serialization.SaveFile(common.IconListCachePath, &m, 0o644, sonic.Marshal)
|
_ = serialization.SaveFile(common.IconListCachePath, &m, 0o644, json.Marshal)
|
||||||
}
|
}
|
||||||
case len(m) > 0:
|
case len(m) > 0:
|
||||||
log.Info().
|
log.Info().
|
||||||
@@ -85,7 +85,7 @@ func InitCache() {
|
|||||||
|
|
||||||
task.OnProgramExit("save_icons_cache", func() {
|
task.OnProgramExit("save_icons_cache", func() {
|
||||||
icons := iconsCache.Load()
|
icons := iconsCache.Load()
|
||||||
_ = serialization.SaveFile(common.IconListCachePath, &icons, 0o644, sonic.Marshal)
|
_ = serialization.SaveFile(common.IconListCachePath, &icons, 0o644, json.Marshal)
|
||||||
})
|
})
|
||||||
|
|
||||||
go backgroundUpdateIcons()
|
go backgroundUpdateIcons()
|
||||||
@@ -106,7 +106,7 @@ func backgroundUpdateIcons() {
|
|||||||
// swap old cache with new cache
|
// swap old cache with new cache
|
||||||
iconsCache.Store(newCache)
|
iconsCache.Store(newCache)
|
||||||
// save it to disk
|
// save it to disk
|
||||||
err := serialization.SaveFile(common.IconListCachePath, &newCache, 0o644, sonic.Marshal)
|
err := serialization.SaveFile(common.IconListCachePath, &newCache, 0o644, json.Marshal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msg("failed to save icons")
|
log.Warn().Err(err).Msg("failed to save icons")
|
||||||
}
|
}
|
||||||
@@ -286,7 +286,7 @@ func UpdateWalkxCodeIcons(m IconMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := make(map[string][]string)
|
data := make(map[string][]string)
|
||||||
err = sonic.Unmarshal(body, &data)
|
err = json.Unmarshal(body, &data)
|
||||||
release(body)
|
release(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -365,7 +365,7 @@ func UpdateSelfhstIcons(m IconMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data := make([]SelfhStIcon, 0)
|
data := make([]SelfhStIcon, 0)
|
||||||
err = sonic.Unmarshal(body, &data) //nolint:musttag
|
err = json.Unmarshal(body, &data) //nolint:musttag
|
||||||
release(body)
|
release(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package qbittorrent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/yusing/godoxy/internal/homepage/widgets"
|
"github.com/yusing/godoxy/internal/homepage/widgets"
|
||||||
strutils "github.com/yusing/goutils/strings"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
@@ -71,7 +71,7 @@ func jsonRequest[T any](ctx context.Context, client *Client, endpoint string, qu
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
err = sonic.ConfigDefault.NewDecoder(resp.Body).Decode(&result)
|
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package qbittorrent
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const endpointLogs = "/api/v2/log/main"
|
const endpointLogs = "/api/v2/log/main"
|
||||||
@@ -45,7 +44,7 @@ func (l *LogEntry) Level() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *LogEntry) MarshalJSON() ([]byte, error) {
|
func (l *LogEntry) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
"id": l.ID,
|
"id": l.ID,
|
||||||
"timestamp": l.Timestamp,
|
"timestamp": l.Timestamp,
|
||||||
"level": l.Level(),
|
"level": l.Level(),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package idlewatcher
|
package idlewatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"iter"
|
"iter"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
strutils "github.com/yusing/goutils/strings"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ type watcherDebug struct {
|
|||||||
|
|
||||||
func (w watcherDebug) MarshalJSON() ([]byte, error) {
|
func (w watcherDebug) MarshalJSON() ([]byte, error) {
|
||||||
state := w.state.Load()
|
state := w.state.Load()
|
||||||
return sonic.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
"name": w.Name(),
|
"name": w.Name(),
|
||||||
"state": map[string]string{
|
"state": map[string]string{
|
||||||
"status": string(state.status),
|
"status": string(state.status),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package idlewatcher
|
package idlewatcher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
"github.com/yusing/goutils/events"
|
||||||
gevents "github.com/yusing/goutils/events"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WakeEvent struct {
|
type WakeEvent struct {
|
||||||
@@ -26,7 +26,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func writeSSE(w io.Writer, v any) error {
|
func writeSSE(w io.Writer, v any) error {
|
||||||
data, err := sonic.Marshal(v)
|
data, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -58,12 +58,12 @@ func (w *Watcher) sendEvent(eventType WakeEventType, message string, err error)
|
|||||||
|
|
||||||
w.l.Debug().Str("event", string(eventType)).Str("message", message).Err(err).Msg("sending event")
|
w.l.Debug().Str("event", string(eventType)).Str("message", message).Err(err).Msg("sending event")
|
||||||
|
|
||||||
level := gevents.LevelInfo
|
level := events.LevelInfo
|
||||||
if eventType == WakeEventError {
|
if eventType == WakeEventError {
|
||||||
level = gevents.LevelError
|
level = events.LevelError
|
||||||
}
|
}
|
||||||
|
|
||||||
w.events.Add(gevents.NewEvent(
|
w.events.Add(events.NewEvent(
|
||||||
level,
|
level,
|
||||||
w.cfg.ContainerName(),
|
w.cfg.ContainerName(),
|
||||||
string(eventType),
|
string(eventType),
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/moby/moby/client"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
idlewatcher "github.com/yusing/godoxy/internal/idlewatcher/types"
|
idlewatcher "github.com/yusing/godoxy/internal/idlewatcher/types"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
@@ -18,7 +17,7 @@ type DockerProvider struct {
|
|||||||
containerID string
|
containerID string
|
||||||
}
|
}
|
||||||
|
|
||||||
var startOptions = client.ContainerStartOptions{}
|
var startOptions = container.StartOptions{}
|
||||||
|
|
||||||
func NewDockerProvider(dockerCfg types.DockerProviderConfig, containerID string) (idlewatcher.Provider, error) {
|
func NewDockerProvider(dockerCfg types.DockerProviderConfig, containerID string) (idlewatcher.Provider, error) {
|
||||||
client, err := docker.NewClient(dockerCfg)
|
client, err := docker.NewClient(dockerCfg)
|
||||||
@@ -33,41 +32,34 @@ func NewDockerProvider(dockerCfg types.DockerProviderConfig, containerID string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerPause(ctx context.Context) error {
|
func (p *DockerProvider) ContainerPause(ctx context.Context) error {
|
||||||
_, err := p.client.ContainerPause(ctx, p.containerID, client.ContainerPauseOptions{})
|
return p.client.ContainerPause(ctx, p.containerID)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerUnpause(ctx context.Context) error {
|
func (p *DockerProvider) ContainerUnpause(ctx context.Context) error {
|
||||||
_, err := p.client.ContainerUnpause(ctx, p.containerID, client.ContainerUnpauseOptions{})
|
return p.client.ContainerUnpause(ctx, p.containerID)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerStart(ctx context.Context) error {
|
func (p *DockerProvider) ContainerStart(ctx context.Context) error {
|
||||||
_, err := p.client.ContainerStart(ctx, p.containerID, startOptions)
|
return p.client.ContainerStart(ctx, p.containerID, startOptions)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerStop(ctx context.Context, signal types.ContainerSignal, timeout int) error {
|
func (p *DockerProvider) ContainerStop(ctx context.Context, signal types.ContainerSignal, timeout int) error {
|
||||||
_, err := p.client.ContainerStop(ctx, p.containerID, client.ContainerStopOptions{
|
return p.client.ContainerStop(ctx, p.containerID, container.StopOptions{
|
||||||
Signal: string(signal),
|
Signal: string(signal),
|
||||||
Timeout: &timeout,
|
Timeout: &timeout,
|
||||||
})
|
})
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerKill(ctx context.Context, signal types.ContainerSignal) error {
|
func (p *DockerProvider) ContainerKill(ctx context.Context, signal types.ContainerSignal) error {
|
||||||
_, err := p.client.ContainerKill(ctx, p.containerID, client.ContainerKillOptions{
|
return p.client.ContainerKill(ctx, p.containerID, string(signal))
|
||||||
Signal: string(signal),
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) ContainerStatus(ctx context.Context) (idlewatcher.ContainerStatus, error) {
|
func (p *DockerProvider) ContainerStatus(ctx context.Context) (idlewatcher.ContainerStatus, error) {
|
||||||
status, err := p.client.ContainerInspect(ctx, p.containerID, client.ContainerInspectOptions{})
|
status, err := p.client.ContainerInspect(ctx, p.containerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return idlewatcher.ContainerStatusError, err
|
return idlewatcher.ContainerStatusError, err
|
||||||
}
|
}
|
||||||
switch status.Container.State.Status {
|
switch status.State.Status {
|
||||||
case container.StateRunning:
|
case container.StateRunning:
|
||||||
return idlewatcher.ContainerStatusRunning, nil
|
return idlewatcher.ContainerStatusRunning, nil
|
||||||
case container.StateExited, container.StateDead, container.StateRestarting:
|
case container.StateExited, container.StateDead, container.StateRestarting:
|
||||||
@@ -75,12 +67,12 @@ func (p *DockerProvider) ContainerStatus(ctx context.Context) (idlewatcher.Conta
|
|||||||
case container.StatePaused:
|
case container.StatePaused:
|
||||||
return idlewatcher.ContainerStatusPaused, nil
|
return idlewatcher.ContainerStatusPaused, nil
|
||||||
}
|
}
|
||||||
return idlewatcher.ContainerStatusError, fmt.Errorf("%w: %s", idlewatcher.ErrUnexpectedContainerStatus, status.Container.State.Status)
|
return idlewatcher.ContainerStatusError, fmt.Errorf("%w: %s", idlewatcher.ErrUnexpectedContainerStatus, status.State.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *DockerProvider) Watch(ctx context.Context) (eventCh <-chan watcher.Event, errCh <-chan error) {
|
func (p *DockerProvider) Watch(ctx context.Context) (eventCh <-chan watcher.Event, errCh <-chan error) {
|
||||||
return p.watcher.EventsWithOptions(ctx, watcher.DockerListOptions{
|
return p.watcher.EventsWithOptions(ctx, watcher.DockerListOptions{
|
||||||
Filters: watcher.NewDockerFilters(
|
Filters: watcher.NewDockerFilter(
|
||||||
watcher.DockerFilterContainer,
|
watcher.DockerFilterContainer,
|
||||||
watcher.DockerFilterContainerNameID(p.containerID),
|
watcher.DockerFilterContainerNameID(p.containerID),
|
||||||
watcher.DockerFilterStart,
|
watcher.DockerFilterStart,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/puzpuzpuz/xsync/v4"
|
"github.com/puzpuzpuz/xsync/v4"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
@@ -66,7 +65,7 @@ func loadNS[T store](ns namespace) T {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err := sonic.ConfigDefault.NewDecoder(file).Decode(&store); err != nil {
|
if err := json.NewDecoder(file).Decode(&store); err != nil {
|
||||||
log.Err(err).
|
log.Err(err).
|
||||||
Str("path", path).
|
Str("path", path).
|
||||||
Msg("failed to load store")
|
Msg("failed to load store")
|
||||||
@@ -84,7 +83,7 @@ func save() error {
|
|||||||
errs := gperr.NewBuilder("failed to save data stores")
|
errs := gperr.NewBuilder("failed to save data stores")
|
||||||
for ns, store := range stores {
|
for ns, store := range stores {
|
||||||
path := filepath.Join(storesPath, string(ns)+".json")
|
path := filepath.Join(storesPath, string(ns)+".json")
|
||||||
if err := serialization.SaveFile(path, &store, 0o644, sonic.Marshal); err != nil {
|
if err := serialization.SaveFile(path, &store, 0o644, json.Marshal); err != nil {
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,12 +113,12 @@ func (s *MapStore[VT]) Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s MapStore[VT]) MarshalJSON() ([]byte, error) {
|
func (s MapStore[VT]) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(xsync.ToPlainMap(s.Map))
|
return json.Marshal(xsync.ToPlainMap(s.Map))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MapStore[VT]) UnmarshalJSON(data []byte) error {
|
func (s *MapStore[VT]) UnmarshalJSON(data []byte) error {
|
||||||
tmp := make(map[string]VT)
|
tmp := make(map[string]VT)
|
||||||
if err := sonic.Unmarshal(data, &tmp); err != nil {
|
if err := json.Unmarshal(data, &tmp); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Map = xsync.NewMap[string, VT](xsync.WithPresize(len(tmp)))
|
s.Map = xsync.NewMap[string, VT](xsync.WithPresize(len(tmp)))
|
||||||
@@ -135,10 +134,10 @@ func (obj *ObjectStore[Ptr]) Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (obj ObjectStore[Ptr]) MarshalJSON() ([]byte, error) {
|
func (obj ObjectStore[Ptr]) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(obj.ptr)
|
return json.Marshal(obj.ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *ObjectStore[Ptr]) UnmarshalJSON(data []byte) error {
|
func (obj *ObjectStore[Ptr]) UnmarshalJSON(data []byte) error {
|
||||||
obj.Initialize()
|
obj.Initialize()
|
||||||
return sonic.Unmarshal(data, obj.ptr)
|
return json.Unmarshal(data, obj.ptr)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package period
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Entries[T any] struct {
|
type Entries[T any] struct {
|
||||||
@@ -75,7 +73,7 @@ type entriesJSON[T any] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *Entries[T]) MarshalJSON() ([]byte, error) {
|
func (e *Entries[T]) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(entriesJSON[T]{
|
return json.Marshal(entriesJSON[T]{
|
||||||
Entries: e.Get(),
|
Entries: e.Get(),
|
||||||
Interval: e.interval,
|
Interval: e.interval,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/goutils/synk"
|
"github.com/yusing/goutils/synk"
|
||||||
@@ -97,7 +96,7 @@ func (p *Poller[T, AggregateT]) save() error {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
err = sonic.ConfigDefault.NewEncoder(f).Encode(p.period)
|
err = json.NewEncoder(f).Encode(p.period)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -153,24 +152,19 @@ func (s *SystemInfo) collectDisksInfo(ctx context.Context, lastResult *SystemInf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partitions, err := disk.PartitionsWithContext(ctx, true)
|
partitions, err := disk.PartitionsWithContext(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Disks = make(map[string]disk.UsageStat, len(partitions))
|
s.Disks = make(map[string]disk.UsageStat, len(partitions))
|
||||||
errs := gperr.NewBuilder("failed to get disks info")
|
errs := gperr.NewBuilder("failed to get disks info")
|
||||||
for _, partition := range partitions {
|
for _, partition := range partitions {
|
||||||
if !shouldCollectPartition(partition) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
diskInfo, err := disk.UsageWithContext(ctx, partition.Mountpoint)
|
diskInfo, err := disk.UsageWithContext(ctx, partition.Mountpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Add(err)
|
errs.Add(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key := diskKey(partition)
|
s.Disks[partition.Device] = diskInfo
|
||||||
s.Disks[key] = diskInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs.HasError() {
|
if errs.HasError() {
|
||||||
@@ -182,41 +176,6 @@ func (s *SystemInfo) collectDisksInfo(ctx context.Context, lastResult *SystemInf
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldCollectPartition(partition disk.PartitionStat) bool {
|
|
||||||
if partition.Mountpoint == "/" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if partition.Mountpoint == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// includes WSL mounts like /mnt/c, but exclude /mnt/ itself and /mnt/wsl*
|
|
||||||
if len(partition.Mountpoint) >= len("/mnt/") &&
|
|
||||||
strings.HasPrefix(partition.Mountpoint, "/mnt/") &&
|
|
||||||
!strings.HasPrefix(partition.Mountpoint, "/mnt/wsl") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(partition.Device, "/dev/") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func diskKey(partition disk.PartitionStat) string {
|
|
||||||
if partition.Device == "" || partition.Device == "none" {
|
|
||||||
return partition.Mountpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
if partition.Device == "/dev/root" {
|
|
||||||
return partition.Mountpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
return partition.Device
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SystemInfo) collectNetworkInfo(ctx context.Context, lastResult *SystemInfo) error {
|
func (s *SystemInfo) collectNetworkInfo(ctx context.Context, lastResult *SystemInfo) error {
|
||||||
networkIO, err := net.IOCountersWithContext(ctx, false)
|
networkIO, err := net.IOCountersWithContext(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/shirou/gopsutil/v4/disk"
|
"github.com/shirou/gopsutil/v4/disk"
|
||||||
"github.com/shirou/gopsutil/v4/mem"
|
"github.com/shirou/gopsutil/v4/mem"
|
||||||
"github.com/shirou/gopsutil/v4/net"
|
"github.com/shirou/gopsutil/v4/net"
|
||||||
@@ -81,12 +80,12 @@ var (
|
|||||||
|
|
||||||
func TestSystemInfo(t *testing.T) {
|
func TestSystemInfo(t *testing.T) {
|
||||||
// Test marshaling
|
// Test marshaling
|
||||||
data, err := sonic.Marshal(testInfo)
|
data, err := json.Marshal(testInfo)
|
||||||
expect.NoError(t, err)
|
expect.NoError(t, err)
|
||||||
|
|
||||||
// Test unmarshaling back
|
// Test unmarshaling back
|
||||||
var decoded SystemInfo
|
var decoded SystemInfo
|
||||||
err = sonic.Unmarshal(data, &decoded)
|
err = json.Unmarshal(data, &decoded)
|
||||||
expect.NoError(t, err)
|
expect.NoError(t, err)
|
||||||
|
|
||||||
// Compare original and decoded
|
// Compare original and decoded
|
||||||
@@ -138,7 +137,7 @@ func TestSerialize(t *testing.T) {
|
|||||||
for _, query := range allQueries {
|
for _, query := range allQueries {
|
||||||
t.Run(string(query), func(t *testing.T) {
|
t.Run(string(query), func(t *testing.T) {
|
||||||
_, result := aggregate(entries, url.Values{"aggregate": []string{string(query)}})
|
_, result := aggregate(entries, url.Values{"aggregate": []string{string(query)}})
|
||||||
s, err := sonic.Marshal(result)
|
s, err := json.Marshal(result)
|
||||||
expect.NoError(t, err)
|
expect.NoError(t, err)
|
||||||
var v []map[string]any
|
var v []map[string]any
|
||||||
expect.NoError(t, json.Unmarshal(s, &v))
|
expect.NoError(t, json.Unmarshal(s, &v))
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package uptime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/lithammer/fuzzysearch/fuzzy"
|
"github.com/lithammer/fuzzysearch/fuzzy"
|
||||||
config "github.com/yusing/godoxy/internal/config/types"
|
config "github.com/yusing/godoxy/internal/config/types"
|
||||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
||||||
@@ -54,7 +54,7 @@ func getStatuses(ctx context.Context, _ StatusByAlias) (StatusByAlias, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Status) MarshalJSON() ([]byte, error) {
|
func (s *Status) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
"status": s.Status.String(),
|
"status": s.Status.String(),
|
||||||
"latency": s.Latency,
|
"latency": s.Latency,
|
||||||
"timestamp": s.Timestamp,
|
"timestamp": s.Timestamp,
|
||||||
@@ -158,5 +158,5 @@ func (rs RouteStatuses) aggregate(limit int, offset int) Aggregated {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (result Aggregated) MarshalJSON() ([]byte, error) {
|
func (result Aggregated) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal([]RouteAggregate(result))
|
return json.Marshal([]RouteAggregate(result))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package captcha
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -11,7 +12,6 @@ import (
|
|||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
strutils "github.com/yusing/goutils/strings"
|
strutils "github.com/yusing/goutils/strings"
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ func (p *HcaptchaProvider) Verify(r *http.Request) error {
|
|||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
Error []string `json:"error-codes"`
|
Error []string `json:"error-codes"`
|
||||||
}
|
}
|
||||||
if err := sonic.ConfigDefault.NewDecoder(resp.Body).Decode(&respData); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&respData); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"mime"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/serialization"
|
"github.com/yusing/godoxy/internal/serialization"
|
||||||
@@ -19,12 +17,6 @@ import (
|
|||||||
"github.com/yusing/goutils/http/reverseproxy"
|
"github.com/yusing/goutils/http/reverseproxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
mimeEventStream = "text/event-stream"
|
|
||||||
headerContentType = "Content-Type"
|
|
||||||
maxModifiableBody = 4 * 1024 * 1024 // 4MB
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
ReverseProxy = reverseproxy.ReverseProxy
|
ReverseProxy = reverseproxy.ReverseProxy
|
||||||
ProxyRequest = reverseproxy.ProxyRequest
|
ProxyRequest = reverseproxy.ProxyRequest
|
||||||
@@ -159,7 +151,7 @@ func (m *Middleware) MarshalJSON() ([]byte, error) {
|
|||||||
commonOptions
|
commonOptions
|
||||||
any
|
any
|
||||||
}
|
}
|
||||||
return sonic.MarshalIndent(map[string]any{
|
return json.MarshalIndent(map[string]any{
|
||||||
"name": m.name,
|
"name": m.name,
|
||||||
"options": allOptions{
|
"options": allOptions{
|
||||||
commonOptions: m.commonOptions,
|
commonOptions: m.commonOptions,
|
||||||
@@ -198,112 +190,78 @@ func (m *Middleware) ServeHTTP(next http.HandlerFunc, w http.ResponseWriter, r *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if httpheaders.IsWebsocket(r.Header) || strings.Contains(strings.ToLower(r.Header.Get("Accept")), mimeEventStream) {
|
if httpheaders.IsWebsocket(r.Header) || r.Header.Get("Accept") == "text/event-stream" {
|
||||||
next(w, r)
|
next(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
exec, ok := m.impl.(ResponseModifier)
|
if exec, ok := m.impl.(ResponseModifier); ok {
|
||||||
if !ok {
|
rm := httputils.NewResponseModifier(w)
|
||||||
|
defer func() {
|
||||||
|
_, err := rm.FlushRelease()
|
||||||
|
if err != nil {
|
||||||
|
m.LogError(r).Err(err).Msg("failed to flush response")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
next(rm, r)
|
||||||
|
|
||||||
|
currentBody := rm.BodyReader()
|
||||||
|
currentResp := &http.Response{
|
||||||
|
StatusCode: rm.StatusCode(),
|
||||||
|
Header: rm.Header(),
|
||||||
|
ContentLength: int64(rm.ContentLength()),
|
||||||
|
Body: currentBody,
|
||||||
|
Request: r,
|
||||||
|
}
|
||||||
|
allowBodyModification := canModifyResponseBody(currentResp)
|
||||||
|
respToModify := currentResp
|
||||||
|
if !allowBodyModification {
|
||||||
|
shadow := *currentResp
|
||||||
|
shadow.Body = eofReader{}
|
||||||
|
respToModify = &shadow
|
||||||
|
}
|
||||||
|
if err := exec.modifyResponse(respToModify); err != nil {
|
||||||
|
log.Err(err).Str("middleware", m.Name()).Str("url", fullURL(r)).Msg("failed to modify response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// override the response status code
|
||||||
|
rm.WriteHeader(respToModify.StatusCode)
|
||||||
|
|
||||||
|
// overriding the response header
|
||||||
|
maps.Copy(rm.Header(), respToModify.Header)
|
||||||
|
|
||||||
|
// override the content length and body if changed
|
||||||
|
if respToModify.Body != currentBody {
|
||||||
|
if allowBodyModification {
|
||||||
|
if err := rm.SetBody(respToModify.Body); err != nil {
|
||||||
|
m.LogError(r).Err(err).Msg("failed to set response body")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
respToModify.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
next(w, r)
|
next(w, r)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lrm := httputils.NewLazyResponseModifier(w, canBufferAndModifyResponseBody)
|
|
||||||
lrm.SetMaxBufferedBytes(maxModifiableBody)
|
|
||||||
defer func() {
|
|
||||||
_, err := lrm.FlushRelease()
|
|
||||||
if err != nil {
|
|
||||||
m.LogError(r).Err(err).Msg("failed to flush response")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
next(lrm, r)
|
|
||||||
|
|
||||||
// Skip modification if response wasn't buffered
|
|
||||||
if !lrm.IsBuffered() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rm := lrm.ResponseModifier()
|
|
||||||
currentBody := rm.BodyReader()
|
|
||||||
currentResp := &http.Response{
|
|
||||||
StatusCode: rm.StatusCode(),
|
|
||||||
Header: rm.Header(),
|
|
||||||
ContentLength: int64(rm.ContentLength()),
|
|
||||||
Body: currentBody,
|
|
||||||
Request: r,
|
|
||||||
}
|
|
||||||
respToModify := currentResp
|
|
||||||
if err := exec.modifyResponse(respToModify); err != nil {
|
|
||||||
log.Err(err).Str("middleware", m.Name()).Str("url", fullURL(r)).Msg("failed to modify response")
|
|
||||||
return // skip modification if failed
|
|
||||||
}
|
|
||||||
|
|
||||||
// override the response status code
|
|
||||||
rm.WriteHeader(respToModify.StatusCode)
|
|
||||||
|
|
||||||
// overriding the response header
|
|
||||||
maps.Copy(rm.Header(), respToModify.Header)
|
|
||||||
|
|
||||||
// override the body if changed
|
|
||||||
if respToModify.Body != currentBody {
|
|
||||||
err := rm.SetBody(respToModify.Body)
|
|
||||||
if err != nil {
|
|
||||||
m.LogError(r).Err(err).Msg("failed to set response body")
|
|
||||||
return // skip modification if failed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// canBufferAndModifyResponseBody checks if the response body can be buffered and modified.
|
func canModifyResponseBody(resp *http.Response) bool {
|
||||||
//
|
if hasNonIdentityEncoding(resp.TransferEncoding) {
|
||||||
// A body can be buffered and modified if:
|
|
||||||
// - The response is not a websocket and is not an event stream
|
|
||||||
// - The response has identity transfer encoding
|
|
||||||
// - The response has identity content encoding
|
|
||||||
// - The response has a content length
|
|
||||||
// - The content length is less than 4MB
|
|
||||||
// - The content type is text-like
|
|
||||||
func canBufferAndModifyResponseBody(respHeader http.Header) bool {
|
|
||||||
if httpheaders.IsWebsocket(respHeader) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
contentType := respHeader.Get("Content-Type")
|
if hasNonIdentityEncoding(resp.Header.Values("Transfer-Encoding")) {
|
||||||
if contentType == "" { // safe default: skip if no content type
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
contentType = strings.ToLower(contentType)
|
if hasNonIdentityEncoding(resp.Header.Values("Content-Encoding")) {
|
||||||
if strings.Contains(contentType, mimeEventStream) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// strip charset or any other parameters
|
return isTextLikeMediaType(string(httputils.GetContentType(resp.Header)))
|
||||||
contentType, _, err := mime.ParseMediaType(contentType)
|
|
||||||
if err != nil { // skip if invalid content type
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if hasNonIdentityEncoding(respHeader.Values("Transfer-Encoding")) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if hasNonIdentityEncoding(respHeader.Values("Content-Encoding")) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if contentLengthRaw := respHeader.Get("Content-Length"); contentLengthRaw != "" {
|
|
||||||
contentLength, err := strconv.ParseInt(contentLengthRaw, 10, 64)
|
|
||||||
if err != nil || contentLength >= maxModifiableBody {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !isTextLikeMediaType(contentType) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasNonIdentityEncoding(values []string) bool {
|
func hasNonIdentityEncoding(values []string) bool {
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
for token := range strings.SplitSeq(value, ",") {
|
for _, token := range strings.Split(value, ",") {
|
||||||
token = strings.TrimSpace(token)
|
if strings.TrimSpace(token) == "" || strings.EqualFold(strings.TrimSpace(token), "identity") {
|
||||||
if token == "" || strings.EqualFold(token, "identity") {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -47,53 +47,23 @@ func (m *middlewareChain) modifyResponse(resp *http.Response) error {
|
|||||||
if len(m.modResps) == 0 {
|
if len(m.modResps) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
allowBodyModification := canModifyResponseBody(resp)
|
||||||
for i, mr := range m.modResps {
|
for i, mr := range m.modResps {
|
||||||
if err := modifyResponseWithBodyRewriteGate(mr, resp); err != nil {
|
respToModify := resp
|
||||||
|
if !allowBodyModification {
|
||||||
|
shadow := *resp
|
||||||
|
shadow.Body = eofReader{}
|
||||||
|
respToModify = &shadow
|
||||||
|
}
|
||||||
|
if err := mr.modifyResponse(respToModify); err != nil {
|
||||||
return gperr.PrependSubject(err, strconv.Itoa(i))
|
return gperr.PrependSubject(err, strconv.Itoa(i))
|
||||||
}
|
}
|
||||||
}
|
if !allowBodyModification {
|
||||||
return nil
|
resp.StatusCode = respToModify.StatusCode
|
||||||
}
|
if respToModify.Header != nil {
|
||||||
|
maps.Copy(resp.Header, respToModify.Header)
|
||||||
func modifyResponseWithBodyRewriteGate(mr ResponseModifier, resp *http.Response) error {
|
}
|
||||||
originalBody := resp.Body
|
|
||||||
originalContentLength := resp.ContentLength
|
|
||||||
allowBodyRewrite := canBufferAndModifyResponseBody(responseHeaderForBodyRewriteGate(resp))
|
|
||||||
|
|
||||||
if err := mr.modifyResponse(resp); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if allowBodyRewrite || resp.Body == originalBody {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Body != nil {
|
|
||||||
if err := resp.Body.Close(); err != nil {
|
|
||||||
return fmt.Errorf("close rewritten body: %w", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if originalBody == nil || originalBody == http.NoBody {
|
|
||||||
resp.Body = http.NoBody
|
|
||||||
} else {
|
|
||||||
resp.Body = originalBody
|
|
||||||
}
|
|
||||||
resp.ContentLength = originalContentLength
|
|
||||||
if originalContentLength >= 0 {
|
|
||||||
resp.Header.Set("Content-Length", strconv.FormatInt(originalContentLength, 10))
|
|
||||||
} else {
|
|
||||||
resp.Header.Del("Content-Length")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func responseHeaderForBodyRewriteGate(resp *http.Response) http.Header {
|
|
||||||
h := resp.Header.Clone()
|
|
||||||
if len(resp.TransferEncoding) > 0 && len(h.Values("Transfer-Encoding")) == 0 {
|
|
||||||
h["Transfer-Encoding"] = append([]string(nil), resp.TransferEncoding...)
|
|
||||||
}
|
|
||||||
if resp.ContentLength >= 0 && h.Get("Content-Length") == "" {
|
|
||||||
h.Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10))
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -128,101 +127,9 @@ func TestMiddlewareResponseRewriteGate(t *testing.T) {
|
|||||||
respStatus: http.StatusOK,
|
respStatus: http.StatusOK,
|
||||||
})
|
})
|
||||||
expect.NoError(t, err)
|
expect.NoError(t, err)
|
||||||
expect.Equal(t, result.ResponseStatus, http.StatusTeapot)
|
expect.Equal(t, result.ResponseStatus, 418)
|
||||||
expect.Equal(t, result.ResponseHeaders.Get("X-Rewrite"), "1")
|
expect.Equal(t, result.ResponseHeaders.Get("X-Rewrite"), "1")
|
||||||
expect.Equal(t, string(result.Data), tc.expectBody)
|
expect.Equal(t, string(result.Data), tc.expectBody)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMiddlewareResponseRewriteGateServeHTTP(t *testing.T) {
|
|
||||||
opts := OptionsRaw{
|
|
||||||
"status_code": 418,
|
|
||||||
"header_key": "X-Rewrite",
|
|
||||||
"header_val": "1",
|
|
||||||
"body": "rewritten-body",
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
respHeaders http.Header
|
|
||||||
respBody string
|
|
||||||
expectStatusCode int
|
|
||||||
expectHeader string
|
|
||||||
expectBody string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "allow_body_rewrite_for_html",
|
|
||||||
respHeaders: http.Header{
|
|
||||||
"Content-Type": []string{"text/html; charset=utf-8"},
|
|
||||||
},
|
|
||||||
respBody: "<html><body>original</body></html>",
|
|
||||||
expectStatusCode: http.StatusTeapot,
|
|
||||||
expectHeader: "1",
|
|
||||||
expectBody: "rewritten-body",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "block_body_rewrite_for_binary_content",
|
|
||||||
respHeaders: http.Header{
|
|
||||||
"Content-Type": []string{"application/octet-stream"},
|
|
||||||
},
|
|
||||||
respBody: "binary",
|
|
||||||
expectStatusCode: http.StatusOK,
|
|
||||||
expectHeader: "",
|
|
||||||
expectBody: "binary",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "block_body_rewrite_for_transfer_encoded_html",
|
|
||||||
respHeaders: http.Header{
|
|
||||||
"Content-Type": []string{"text/html"},
|
|
||||||
"Transfer-Encoding": []string{"chunked"},
|
|
||||||
},
|
|
||||||
respBody: "<html><body>original</body></html>",
|
|
||||||
expectStatusCode: http.StatusOK,
|
|
||||||
expectHeader: "",
|
|
||||||
expectBody: "<html><body>original</body></html>",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "block_body_rewrite_for_content_encoded_html",
|
|
||||||
respHeaders: http.Header{
|
|
||||||
"Content-Type": []string{"text/html"},
|
|
||||||
"Content-Encoding": []string{"gzip"},
|
|
||||||
},
|
|
||||||
respBody: "<html><body>original</body></html>",
|
|
||||||
expectStatusCode: http.StatusOK,
|
|
||||||
expectHeader: "",
|
|
||||||
expectBody: "<html><body>original</body></html>",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
mid, err := responseRewrite.New(opts)
|
|
||||||
expect.NoError(t, err)
|
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://example.com", nil)
|
|
||||||
rw := httptest.NewRecorder()
|
|
||||||
|
|
||||||
next := func(w http.ResponseWriter, _ *http.Request) {
|
|
||||||
for key, values := range tc.respHeaders {
|
|
||||||
for _, value := range values {
|
|
||||||
w.Header().Add(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
_, _ = w.Write([]byte(tc.respBody))
|
|
||||||
}
|
|
||||||
|
|
||||||
mid.ServeHTTP(next, rw, req)
|
|
||||||
|
|
||||||
resp := rw.Result()
|
|
||||||
defer resp.Body.Close()
|
|
||||||
data, readErr := io.ReadAll(resp.Body)
|
|
||||||
expect.NoError(t, readErr)
|
|
||||||
|
|
||||||
expect.Equal(t, resp.StatusCode, tc.expectStatusCode)
|
|
||||||
expect.Equal(t, resp.Header.Get("X-Rewrite"), tc.expectHeader)
|
|
||||||
expect.Equal(t, string(data), tc.expectBody)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"maps"
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/yusing/godoxy/internal/common"
|
"github.com/yusing/godoxy/internal/common"
|
||||||
nettypes "github.com/yusing/godoxy/internal/net/types"
|
nettypes "github.com/yusing/godoxy/internal/net/types"
|
||||||
"github.com/yusing/goutils/http/reverseproxy"
|
"github.com/yusing/goutils/http/reverseproxy"
|
||||||
@@ -24,7 +24,7 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
tmp := map[string]string{}
|
tmp := map[string]string{}
|
||||||
err := sonic.Unmarshal(testHeadersRaw, &tmp)
|
err := json.Unmarshal(testHeadersRaw, &tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package nettypes
|
package nettypes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
urlPkg "net/url"
|
urlPkg "net/url"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type URL struct {
|
type URL struct {
|
||||||
@@ -47,7 +46,7 @@ func (u *URL) MarshalJSON() (text []byte, err error) {
|
|||||||
if u == nil {
|
if u == nil {
|
||||||
return []byte("null"), nil
|
return []byte("null"), nil
|
||||||
}
|
}
|
||||||
return sonic.Marshal(u.URL.String())
|
return json.Marshal(u.URL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *URL) Equals(other *URL) bool {
|
func (u *URL) Equals(other *URL) bool {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package notif
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ func (f FieldsBody) Format(format LogFormat) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return msg.Bytes(), nil
|
return msg.Bytes(), nil
|
||||||
case LogFormatRawJSON:
|
case LogFormatRawJSON:
|
||||||
return sonic.Marshal(f)
|
return json.Marshal(f)
|
||||||
}
|
}
|
||||||
return f.Format(LogFormatMarkdown)
|
return f.Format(LogFormatMarkdown)
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ func (l ListBody) Format(format LogFormat) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return msg.Bytes(), nil
|
return msg.Bytes(), nil
|
||||||
case LogFormatRawJSON:
|
case LogFormatRawJSON:
|
||||||
return sonic.Marshal(l)
|
return json.Marshal(l)
|
||||||
}
|
}
|
||||||
return l.Format(LogFormatMarkdown)
|
return l.Format(LogFormatMarkdown)
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,7 @@ func (m MessageBody) Format(format LogFormat) ([]byte, error) {
|
|||||||
case LogFormatPlain, LogFormatMarkdown:
|
case LogFormatPlain, LogFormatMarkdown:
|
||||||
return []byte(m), nil
|
return []byte(m), nil
|
||||||
case LogFormatRawJSON:
|
case LogFormatRawJSON:
|
||||||
return sonic.Marshal(m)
|
return json.Marshal(m)
|
||||||
}
|
}
|
||||||
return []byte(m), nil
|
return []byte(m), nil
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ func (m MessageBody) Format(format LogFormat) ([]byte, error) {
|
|||||||
func (m MessageBodyBytes) Format(format LogFormat) ([]byte, error) {
|
func (m MessageBodyBytes) Format(format LogFormat) ([]byte, error) {
|
||||||
switch format {
|
switch format {
|
||||||
case LogFormatRawJSON:
|
case LogFormatRawJSON:
|
||||||
return sonic.Marshal(string(m))
|
return json.Marshal(string(m))
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
@@ -115,7 +115,7 @@ func (m MessageBodyBytes) Format(format LogFormat) ([]byte, error) {
|
|||||||
func (e errorBody) Format(format LogFormat) ([]byte, error) {
|
func (e errorBody) Format(format LogFormat) ([]byte, error) {
|
||||||
switch format {
|
switch format {
|
||||||
case LogFormatRawJSON:
|
case LogFormatRawJSON:
|
||||||
return sonic.Marshal(e.Error)
|
return json.Marshal(e.Error)
|
||||||
case LogFormatPlain:
|
case LogFormatPlain:
|
||||||
return gperr.Plain(e.Error), nil
|
return gperr.Plain(e.Error), nil
|
||||||
case LogFormatMarkdown:
|
case LogFormatMarkdown:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package notif
|
package notif
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/gotify/server/v2/model"
|
"github.com/gotify/server/v2/model"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
@@ -66,7 +66,7 @@ func (client *GotifyClient) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := sonic.Marshal(msg)
|
data, err := json.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ func (client *GotifyClient) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
|
|||||||
// fmtError implements Provider.
|
// fmtError implements Provider.
|
||||||
func (client *GotifyClient) fmtError(respBody io.Reader) error {
|
func (client *GotifyClient) fmtError(respBody io.Reader) error {
|
||||||
var errm model.Error
|
var errm model.Error
|
||||||
err := sonic.ConfigDefault.NewDecoder(respBody).Decode(&errm)
|
err := json.NewDecoder(respBody).Decode(&errm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to decode err response: %w", err)
|
return fmt.Errorf("failed to decode err response: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package notif
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func (webhook *Webhook) fmtError(respBody io.Reader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (webhook *Webhook) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
|
func (webhook *Webhook) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
|
||||||
title, err := sonic.Marshal(logMsg.Title)
|
title, err := json.Marshal(logMsg.Title)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ func (webhook *Webhook) MarshalMessage(logMsg *LogMessage) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if webhook.MIMEType == MimeTypeJSON {
|
if webhook.MIMEType == MimeTypeJSON {
|
||||||
message, err = sonic.Marshal(string(message))
|
message, err = json.Marshal(string(message))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -149,5 +149,5 @@ func validateJSONPayload(payload string) bool {
|
|||||||
"$color", "",
|
"$color", "",
|
||||||
)
|
)
|
||||||
payload = replacer.Replace(payload)
|
payload = replacer.Replace(payload)
|
||||||
return sonic.Valid([]byte(payload))
|
return json.Valid([]byte(payload))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package proxmox
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/luthermonson/go-proxmox"
|
"github.com/luthermonson/go-proxmox"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
@@ -203,7 +203,7 @@ func (c *Client) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) MarshalJSON() ([]byte, error) {
|
func (c *Client) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
"version": c.Version,
|
"version": c.Version,
|
||||||
"cluster": map[string]any{
|
"cluster": map[string]any{
|
||||||
"name": c.Cluster.Name,
|
"name": c.Cluster.Name,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package proxmox
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
"github.com/yusing/goutils/pool"
|
"github.com/yusing/goutils/pool"
|
||||||
)
|
)
|
||||||
@@ -82,7 +82,7 @@ func (n *Node) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) MarshalJSON() ([]byte, error) {
|
func (n *Node) MarshalJSON() ([]byte, error) {
|
||||||
return sonic.Marshal(map[string]any{
|
return json.Marshal(map[string]any{
|
||||||
"name": n.name,
|
"name": n.name,
|
||||||
"id": n.id,
|
"id": n.id,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package provider
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/moby/moby/api/types/container"
|
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
expect "github.com/yusing/goutils/testing"
|
expect "github.com/yusing/goutils/testing"
|
||||||
@@ -26,7 +26,7 @@ func TestParseDockerLabels(t *testing.T) {
|
|||||||
Names: []string{"container"},
|
Names: []string{"container"},
|
||||||
Labels: labels,
|
Labels: labels,
|
||||||
State: "running",
|
State: "running",
|
||||||
Ports: []container.PortSummary{
|
Ports: []container.Port{
|
||||||
{Type: "tcp", PrivatePort: 1234, PublicPort: 1234},
|
{Type: "tcp", PrivatePort: 1234, PublicPort: 1234},
|
||||||
},
|
},
|
||||||
}, types.DockerProviderConfig{URL: "unix:///var/run/docker.sock"}),
|
}, types.DockerProviderConfig{URL: "unix:///var/run/docker.sock"}),
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package provider
|
package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/moby/moby/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/moby/moby/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/moby/moby/client"
|
"github.com/docker/docker/client"
|
||||||
D "github.com/yusing/godoxy/internal/docker"
|
D "github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/godoxy/internal/route"
|
"github.com/yusing/godoxy/internal/route"
|
||||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||||
@@ -276,7 +275,7 @@ func TestPrivateIPLocalhost(t *testing.T) {
|
|||||||
NetworkSettings: &container.NetworkSettingsSummary{
|
NetworkSettings: &container.NetworkSettingsSummary{
|
||||||
Networks: map[string]*network.EndpointSettings{
|
Networks: map[string]*network.EndpointSettings{
|
||||||
"network": {
|
"network": {
|
||||||
IPAddress: netip.MustParseAddr(testDockerIP),
|
IPAddress: testDockerIP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -294,7 +293,7 @@ func TestPrivateIPRemote(t *testing.T) {
|
|||||||
NetworkSettings: &container.NetworkSettingsSummary{
|
NetworkSettings: &container.NetworkSettingsSummary{
|
||||||
Networks: map[string]*network.EndpointSettings{
|
Networks: map[string]*network.EndpointSettings{
|
||||||
"network": {
|
"network": {
|
||||||
IPAddress: netip.MustParseAddr(testDockerIP),
|
IPAddress: testDockerIP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -316,11 +315,11 @@ func TestStreamDefaultValues(t *testing.T) {
|
|||||||
NetworkSettings: &container.NetworkSettingsSummary{
|
NetworkSettings: &container.NetworkSettingsSummary{
|
||||||
Networks: map[string]*network.EndpointSettings{
|
Networks: map[string]*network.EndpointSettings{
|
||||||
"network": {
|
"network": {
|
||||||
IPAddress: netip.MustParseAddr(privIP),
|
IPAddress: privIP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Ports: []container.PortSummary{
|
Ports: []container.Port{
|
||||||
{Type: "udp", PrivatePort: privPort, PublicPort: pubPort},
|
{Type: "udp", PrivatePort: privPort, PublicPort: pubPort},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -373,7 +372,7 @@ func TestImplicitExcludeDatabase(t *testing.T) {
|
|||||||
t.Run("exposed port detection", func(t *testing.T) {
|
t.Run("exposed port detection", func(t *testing.T) {
|
||||||
r, ok := makeRoutes(&container.Summary{
|
r, ok := makeRoutes(&container.Summary{
|
||||||
Names: dummyNames,
|
Names: dummyNames,
|
||||||
Ports: []container.PortSummary{
|
Ports: []container.Port{
|
||||||
{Type: "tcp", PrivatePort: 5432, PublicPort: 5432},
|
{Type: "tcp", PrivatePort: 5432, PublicPort: 5432},
|
||||||
},
|
},
|
||||||
})["a"]
|
})["a"]
|
||||||
|
|||||||
@@ -292,20 +292,6 @@ func parseAtBlockChain(src string, blockPos int) (CommandHandler, int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lineEndsWithUnquotedOpenBrace(src string, lineStart int, lineEnd int) bool {
|
func lineEndsWithUnquotedOpenBrace(src string, lineStart int, lineEnd int) bool {
|
||||||
return lineEndsWithUnquotedToken(src, lineStart, lineEnd) == '{'
|
|
||||||
}
|
|
||||||
|
|
||||||
func lineContinuationOperator(src string, lineStart int, lineEnd int) byte {
|
|
||||||
token := lineEndsWithUnquotedToken(src, lineStart, lineEnd)
|
|
||||||
switch token {
|
|
||||||
case '|', '&':
|
|
||||||
return token
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func lineEndsWithUnquotedToken(src string, lineStart int, lineEnd int) byte {
|
|
||||||
quote := byte(0)
|
quote := byte(0)
|
||||||
lastSignificant := byte(0)
|
lastSignificant := byte(0)
|
||||||
atLineStart := true
|
atLineStart := true
|
||||||
@@ -348,22 +334,13 @@ func lineEndsWithUnquotedToken(src string, lineStart int, lineEnd int) byte {
|
|||||||
atLineStart = false
|
atLineStart = false
|
||||||
prevIsSpace = false
|
prevIsSpace = false
|
||||||
}
|
}
|
||||||
if quote != 0 {
|
return quote == 0 && lastSignificant == '{'
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return lastSignificant
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseDoWithBlocks parses a do-body containing plain command lines and nested blocks.
|
// parseDoWithBlocks parses a do-body containing plain command lines and nested blocks.
|
||||||
// It returns the outer command handlers and the require phase.
|
// It returns the outer command handlers and the require phase.
|
||||||
//
|
//
|
||||||
// A nested block is recognized when a logical header ends with an unquoted '{'.
|
// A nested block is recognized when a line ends with an unquoted '{' (ignoring trailing whitespace).
|
||||||
// Logical headers may span lines using trailing '|' or '&', for example:
|
|
||||||
//
|
|
||||||
// remote 127.0.0.1 |
|
|
||||||
// remote 192.168.0.0/16 {
|
|
||||||
// set header X-Remote-Type private
|
|
||||||
// }
|
|
||||||
func parseDoWithBlocks(src string) (handlers []CommandHandler, err error) {
|
func parseDoWithBlocks(src string) (handlers []CommandHandler, err error) {
|
||||||
pos := 0
|
pos := 0
|
||||||
length := len(src)
|
length := len(src)
|
||||||
@@ -423,38 +400,12 @@ func parseDoWithBlocks(src string) (handlers []CommandHandler, err error) {
|
|||||||
linePos++
|
linePos++
|
||||||
}
|
}
|
||||||
|
|
||||||
logicalEnd := linePos
|
lineEnd := linePos
|
||||||
for logicalEnd < length && src[logicalEnd] != '\n' {
|
for lineEnd < length && src[lineEnd] != '\n' {
|
||||||
logicalEnd++
|
lineEnd++
|
||||||
}
|
}
|
||||||
|
|
||||||
for linePos < length && lineContinuationOperator(src, linePos, logicalEnd) != 0 {
|
if linePos < length && lineEndsWithUnquotedOpenBrace(src, linePos, lineEnd) {
|
||||||
nextPos := logicalEnd
|
|
||||||
if nextPos < length && src[nextPos] == '\n' {
|
|
||||||
nextPos++
|
|
||||||
}
|
|
||||||
for nextPos < length {
|
|
||||||
c := rune(src[nextPos])
|
|
||||||
if c == '\n' {
|
|
||||||
nextPos++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if c == '\r' || unicode.IsSpace(c) {
|
|
||||||
nextPos++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nextPos >= length {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
logicalEnd = nextPos
|
|
||||||
for logicalEnd < length && src[logicalEnd] != '\n' {
|
|
||||||
logicalEnd++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if linePos < length && lineEndsWithUnquotedOpenBrace(src, linePos, logicalEnd) {
|
|
||||||
h, next, err := parseAtBlockChain(src, linePos)
|
h, next, err := parseAtBlockChain(src, linePos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -466,10 +417,10 @@ func parseDoWithBlocks(src string) (handlers []CommandHandler, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Not a nested block; parse the rest of this line as a command.
|
// Not a nested block; parse the rest of this line as a command.
|
||||||
if lerr := appendLineCommand(src[pos:logicalEnd]); lerr != nil {
|
if lerr := appendLineCommand(src[pos:lineEnd]); lerr != nil {
|
||||||
return nil, lerr
|
return nil, lerr
|
||||||
}
|
}
|
||||||
pos = logicalEnd
|
pos = lineEnd
|
||||||
lineStart = true
|
lineStart = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,38 +71,3 @@ func TestIfElseBlockCommandServeHTTP_ConditionalMatchedNilDoNotFallsThrough(t *t
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.False(t, elseCalled)
|
assert.False(t, elseCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseDoWithBlocks_MultilineBlockHeaderContinuation(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
src string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "or continuation",
|
|
||||||
src: `
|
|
||||||
remote 127.0.0.1 |
|
|
||||||
remote 192.168.0.0/16 {
|
|
||||||
set header X-Remote-Type private
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "and continuation",
|
|
||||||
src: `
|
|
||||||
method GET &
|
|
||||||
remote 127.0.0.1 {
|
|
||||||
set header X-Remote-Type private
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
handlers, err := parseDoWithBlocks(tt.src)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, handlers, 1)
|
|
||||||
require.IsType(t, IfBlockCommand{}, handlers[0])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -456,8 +456,7 @@ func TestHTTPFlow_NestedBlocks_RemoteOverride(t *testing.T) {
|
|||||||
err := parseRules(`
|
err := parseRules(`
|
||||||
header X-Test-Header {
|
header X-Test-Header {
|
||||||
set header X-Remote-Type public
|
set header X-Remote-Type public
|
||||||
remote 127.0.0.1 |
|
remote 127.0.0.1 | remote 192.168.0.0/16 {
|
||||||
remote 192.168.0.0/16 {
|
|
||||||
set header X-Remote-Type private
|
set header X-Remote-Type private
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -505,70 +505,62 @@ var (
|
|||||||
andSeps = [256]uint8{'&': 1, '\n': 1}
|
andSeps = [256]uint8{'&': 1, '\n': 1}
|
||||||
)
|
)
|
||||||
|
|
||||||
// splitAnd splits a condition string into AND parts.
|
func indexAnd(s string) int {
|
||||||
// It treats '&' and newline as AND separators, except when a line ends with
|
for i := range s {
|
||||||
// an unescaped '|' (OR continuation), where the newline stays in the same part.
|
if andSeps[s[i]] != 0 {
|
||||||
// Empty parts are omitted.
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func countAnd(s string) int {
|
||||||
|
n := 0
|
||||||
|
for i := range s {
|
||||||
|
if andSeps[s[i]] != 0 {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// splitAnd splits a string by "&" and "\n" with all spaces removed.
|
||||||
|
// empty strings are not included in the result.
|
||||||
func splitAnd(s string) []string {
|
func splitAnd(s string) []string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
result := []string{}
|
n := countAnd(s)
|
||||||
forEachAndPart(s, func(part string) {
|
a := make([]string, n+1)
|
||||||
result = append(result, part)
|
i := 0
|
||||||
})
|
for i < n {
|
||||||
return result
|
end := indexAnd(s)
|
||||||
}
|
if end == -1 {
|
||||||
|
break
|
||||||
func lineEndsWithUnescapedPipe(s string, start, end int) bool {
|
|
||||||
for i := end - 1; i >= start; i-- {
|
|
||||||
if asciiSpace[s[i]] != 0 {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if s[i] != '|' {
|
beg := 0
|
||||||
return false
|
// trim leading spaces
|
||||||
|
for beg < end && asciiSpace[s[beg]] != 0 {
|
||||||
|
beg++
|
||||||
}
|
}
|
||||||
escapes := 0
|
// trim trailing spaces
|
||||||
for j := i - 1; j >= start && s[j] == '\\'; j-- {
|
next := end + 1
|
||||||
escapes++
|
for end-1 > beg && asciiSpace[s[end-1]] != 0 {
|
||||||
|
end--
|
||||||
}
|
}
|
||||||
return escapes%2 == 0
|
// skip empty segments
|
||||||
|
if end > beg {
|
||||||
|
a[i] = s[beg:end]
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
s = s[next:]
|
||||||
}
|
}
|
||||||
return false
|
s = strings.TrimSpace(s)
|
||||||
}
|
if s != "" {
|
||||||
|
a[i] = s
|
||||||
func advanceSplitState(s string, i *int, quote *byte, brackets *int) bool {
|
i++
|
||||||
c := s[*i]
|
|
||||||
if *quote != 0 {
|
|
||||||
if c == '\\' && *i+1 < len(s) {
|
|
||||||
*i++
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if c == *quote {
|
|
||||||
*quote = 0
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
return a[:i]
|
||||||
switch c {
|
|
||||||
case '\\':
|
|
||||||
if *i+1 < len(s) {
|
|
||||||
*i++
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case '"', '\'', '`':
|
|
||||||
*quote = c
|
|
||||||
return true
|
|
||||||
case '(':
|
|
||||||
*brackets++
|
|
||||||
return true
|
|
||||||
case ')':
|
|
||||||
if *brackets > 0 {
|
|
||||||
*brackets--
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitPipe splits a string by "|" but respects quotes, brackets, and escaped characters.
|
// splitPipe splits a string by "|" but respects quotes, brackets, and escaped characters.
|
||||||
@@ -586,26 +578,8 @@ func splitPipe(s string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func forEachAndPart(s string, fn func(part string)) {
|
func forEachAndPart(s string, fn func(part string)) {
|
||||||
quote := byte(0)
|
|
||||||
brackets := 0
|
|
||||||
start := 0
|
start := 0
|
||||||
|
|
||||||
for i := 0; i <= len(s); i++ {
|
for i := 0; i <= len(s); i++ {
|
||||||
if i < len(s) {
|
|
||||||
c := s[i]
|
|
||||||
if advanceSplitState(s, &i, "e, &brackets) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if c == '\n' {
|
|
||||||
if brackets > 0 || lineEndsWithUnescapedPipe(s, start, i) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else if c != '&' || brackets > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if i < len(s) && andSeps[s[i]] == 0 {
|
if i < len(s) && andSeps[s[i]] == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -623,14 +597,30 @@ func forEachPipePart(s string, fn func(part string)) {
|
|||||||
start := 0
|
start := 0
|
||||||
|
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
if advanceSplitState(s, &i, "e, &brackets) {
|
switch s[i] {
|
||||||
continue
|
case '\\':
|
||||||
}
|
if i+1 < len(s) {
|
||||||
if s[i] == '|' && brackets == 0 {
|
i++
|
||||||
if part := strings.TrimSpace(s[start:i]); part != "" {
|
}
|
||||||
fn(part)
|
case '"', '\'', '`':
|
||||||
|
if quote == 0 && brackets == 0 {
|
||||||
|
quote = s[i]
|
||||||
|
} else if s[i] == quote {
|
||||||
|
quote = 0
|
||||||
|
}
|
||||||
|
case '(':
|
||||||
|
brackets++
|
||||||
|
case ')':
|
||||||
|
if brackets > 0 {
|
||||||
|
brackets--
|
||||||
|
}
|
||||||
|
case '|':
|
||||||
|
if quote == 0 && brackets == 0 {
|
||||||
|
if part := strings.TrimSpace(s[start:i]); part != "" {
|
||||||
|
fn(part)
|
||||||
|
}
|
||||||
|
start = i + 1
|
||||||
}
|
}
|
||||||
start = i + 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if start < len(s) {
|
if start < len(s) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package rules
|
package rules
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
@@ -135,16 +133,6 @@ func TestSplitAnd(t *testing.T) {
|
|||||||
input: " rule1\nrule2 & rule3 ",
|
input: " rule1\nrule2 & rule3 ",
|
||||||
want: []string{"rule1", "rule2", "rule3"},
|
want: []string{"rule1", "rule2", "rule3"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "newline_after_pipe_is_or_continuation",
|
|
||||||
input: "path /abc |\npath /bcd",
|
|
||||||
want: []string{"path /abc |\npath /bcd"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "newline_after_pipe_with_spaces_is_or_continuation",
|
|
||||||
input: "path /abc | \n path /bcd",
|
|
||||||
want: []string{"path /abc | \n path /bcd"},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
@@ -292,11 +280,6 @@ func TestParseOn(t *testing.T) {
|
|||||||
input: `method GET | path regex("^(_next/static|_next/image|favicon.ico).*$") | header Authorization`,
|
input: `method GET | path regex("^(_next/static|_next/image|favicon.ico).*$") | header Authorization`,
|
||||||
wantErr: nil,
|
wantErr: nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "pipe_multiline_continuation",
|
|
||||||
input: "path /abc |\npath /bcd |",
|
|
||||||
wantErr: nil,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -311,18 +294,3 @@ func TestParseOn(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRuleOnParse_MultilineOrContinuation(t *testing.T) {
|
|
||||||
var on RuleOn
|
|
||||||
err := on.Parse("path /abc |\npath /bcd |")
|
|
||||||
expect.NoError(t, err)
|
|
||||||
|
|
||||||
w := http.ResponseWriter(nil)
|
|
||||||
reqABC := &http.Request{URL: &url.URL{Path: "/abc"}}
|
|
||||||
reqBCD := &http.Request{URL: &url.URL{Path: "/bcd"}}
|
|
||||||
reqXYZ := &http.Request{URL: &url.URL{Path: "/xyz"}}
|
|
||||||
|
|
||||||
expect.Equal(t, on.Check(w, reqABC), true)
|
|
||||||
expect.Equal(t, on.Check(w, reqBCD), true)
|
|
||||||
expect.Equal(t, on.Check(w, reqXYZ), false)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -27,21 +27,22 @@ type (
|
|||||||
Example:
|
Example:
|
||||||
|
|
||||||
proxy.app1.rules: |
|
proxy.app1.rules: |
|
||||||
default {
|
- name: default
|
||||||
rewrite / /index.html
|
do: |
|
||||||
serve /var/www/goaccess
|
rewrite / /index.html
|
||||||
}
|
serve /var/www/goaccess
|
||||||
header Connection Upgrade & header Upgrade websocket {
|
- name: ws
|
||||||
bypass
|
on: |
|
||||||
}
|
header Connection Upgrade
|
||||||
|
header Upgrade websocket
|
||||||
|
do: bypass
|
||||||
|
|
||||||
proxy.app2.rules: |
|
proxy.app2.rules: |
|
||||||
default {
|
- name: default
|
||||||
bypass
|
do: bypass
|
||||||
}
|
- name: block POST and PUT
|
||||||
method POST | method PUT {
|
on: method POST | method PUT
|
||||||
error 403 Forbidden
|
do: error 403 Forbidden
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
//nolint:recvcheck
|
//nolint:recvcheck
|
||||||
Rules []Rule
|
Rules []Rule
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package route
|
package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func (s Scheme) MarshalJSON() ([]byte, error) {
|
|||||||
|
|
||||||
func (s *Scheme) UnmarshalJSON(data []byte) error {
|
func (s *Scheme) UnmarshalJSON(data []byte) error {
|
||||||
var v string
|
var v string
|
||||||
if err := sonic.Unmarshal(data, &v); err != nil {
|
if err := json.Unmarshal(data, &v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return s.Parse(v)
|
return s.Parse(v)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ func (b GinJSONBinding) Name() string {
|
|||||||
|
|
||||||
func (b GinJSONBinding) Bind(req *http.Request, obj any) error {
|
func (b GinJSONBinding) Bind(req *http.Request, obj any) error {
|
||||||
m := make(map[string]any)
|
m := make(map[string]any)
|
||||||
if err := sonic.ConfigDefault.NewDecoder(NewSubstituteEnvReader(req.Body)).Decode(&m); err != nil {
|
if err := json.NewDecoder(NewSubstituteEnvReader(req.Body)).Decode(&m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return MapUnmarshalValidate(m, obj)
|
return MapUnmarshalValidate(m, obj)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package serialization
|
package serialization
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/puzpuzpuz/xsync/v4"
|
"github.com/puzpuzpuz/xsync/v4"
|
||||||
@@ -34,8 +34,8 @@ func ToSerializedObject[VT any](m map[string]VT) SerializedObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
strutils.SetJSONMarshaler(sonic.Marshal)
|
strutils.SetJSONMarshaler(json.Marshal)
|
||||||
strutils.SetJSONUnmarshaler(sonic.Unmarshal)
|
strutils.SetJSONUnmarshaler(json.Unmarshal)
|
||||||
strutils.SetYAMLMarshaler(yaml.Marshal)
|
strutils.SetYAMLMarshaler(yaml.Marshal)
|
||||||
strutils.SetYAMLUnmarshaler(yaml.Unmarshal)
|
strutils.SetYAMLUnmarshaler(yaml.Unmarshal)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bytedance/sonic"
|
"encoding/json"
|
||||||
"github.com/moby/moby/api/types/container"
|
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/yusing/ds/ordered"
|
"github.com/yusing/ds/ordered"
|
||||||
"github.com/yusing/godoxy/internal/agentpool"
|
"github.com/yusing/godoxy/internal/agentpool"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
@@ -11,7 +12,7 @@ import (
|
|||||||
type (
|
type (
|
||||||
LabelMap = map[string]any
|
LabelMap = map[string]any
|
||||||
|
|
||||||
PortMapping = map[int]container.PortSummary
|
PortMapping = map[int]container.Port
|
||||||
Container struct {
|
Container struct {
|
||||||
DockerCfg DockerProviderConfig `json:"docker_cfg"`
|
DockerCfg DockerProviderConfig `json:"docker_cfg"`
|
||||||
Image *ContainerImage `json:"image"`
|
Image *ContainerImage `json:"image"`
|
||||||
@@ -69,5 +70,5 @@ func (e *ContainerError) Unwrap() error {
|
|||||||
|
|
||||||
func (e *ContainerError) MarshalJSON() ([]byte, error) {
|
func (e *ContainerError) MarshalJSON() ([]byte, error) {
|
||||||
err := e.errs.Error().(gperr.PlainError)
|
err := e.errs.Error().(gperr.PlainError)
|
||||||
return sonic.Marshal(string(err.Plain()))
|
return json.Marshal(string(err.Plain()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bytedance/sonic"
|
|
||||||
"github.com/yusing/goutils/task"
|
"github.com/yusing/goutils/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -175,7 +174,7 @@ func (s HealthStatus) MarshalJSON() ([]byte, error) {
|
|||||||
|
|
||||||
func (s *HealthStatus) UnmarshalJSON(data []byte) error {
|
func (s *HealthStatus) UnmarshalJSON(data []byte) error {
|
||||||
var v string
|
var v string
|
||||||
if err := sonic.Unmarshal(data, &v); err != nil {
|
if err := json.Unmarshal(data, &v); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal health status: %w", err)
|
return fmt.Errorf("failed to unmarshal health status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +190,7 @@ func (jsonRepr *HealthJSONRepr) MarshalJSON() ([]byte, error) {
|
|||||||
if url == "http://:0" {
|
if url == "http://:0" {
|
||||||
url = ""
|
url = ""
|
||||||
}
|
}
|
||||||
return sonic.Marshal(HealthJSON{
|
return json.Marshal(HealthJSON{
|
||||||
Name: jsonRepr.Name,
|
Name: jsonRepr.Name,
|
||||||
Config: jsonRepr.Config,
|
Config: jsonRepr.Config,
|
||||||
Started: jsonRepr.Started.Unix(),
|
Started: jsonRepr.Started.Unix(),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ type (
|
|||||||
IdlewatcherConfigBase struct {
|
IdlewatcherConfigBase struct {
|
||||||
// 0: no idle watcher.
|
// 0: no idle watcher.
|
||||||
// Positive: idle watcher with idle timeout.
|
// Positive: idle watcher with idle timeout.
|
||||||
// Negative: idle watcher as a dependency.
|
// Negative: idle watcher as a dependency. IdleTimeout time.Duration `json:"idle_timeout" json_ext:"duration"`
|
||||||
IdleTimeout time.Duration `json:"idle_timeout"`
|
IdleTimeout time.Duration `json:"idle_timeout"`
|
||||||
WakeTimeout time.Duration `json:"wake_timeout"`
|
WakeTimeout time.Duration `json:"wake_timeout"`
|
||||||
StopTimeout time.Duration `json:"stop_timeout"`
|
StopTimeout time.Duration `json:"stop_timeout"`
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
dockerEvents "github.com/moby/moby/api/types/events"
|
dockerEvents "github.com/docker/docker/api/types/events"
|
||||||
"github.com/moby/moby/client"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/yusing/godoxy/internal/docker"
|
"github.com/yusing/godoxy/internal/docker"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
@@ -18,42 +19,23 @@ type (
|
|||||||
DockerWatcher struct {
|
DockerWatcher struct {
|
||||||
cfg types.DockerProviderConfig
|
cfg types.DockerProviderConfig
|
||||||
}
|
}
|
||||||
DockerListOptions = client.EventsListOptions
|
DockerListOptions = dockerEvents.ListOptions
|
||||||
DockerFilters = client.Filters
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DockerFilter struct {
|
|
||||||
Term string
|
|
||||||
Values []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDockerFilter(term string, values ...string) DockerFilter {
|
|
||||||
return DockerFilter{
|
|
||||||
Term: term,
|
|
||||||
Values: values,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDockerFilters(filters ...DockerFilter) client.Filters {
|
|
||||||
f := make(client.Filters, len(filters))
|
|
||||||
for _, filter := range filters {
|
|
||||||
f.Add(filter.Term, filter.Values...)
|
|
||||||
}
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://docs.docker.com/reference/api/engine/version/v1.47/#tag/System/operation/SystemPingHead
|
// https://docs.docker.com/reference/api/engine/version/v1.47/#tag/System/operation/SystemPingHead
|
||||||
var (
|
var (
|
||||||
DockerFilterContainer = NewDockerFilter("type", string(dockerEvents.ContainerEventType))
|
DockerFilterContainer = filters.Arg("type", string(dockerEvents.ContainerEventType))
|
||||||
DockerFilterStart = NewDockerFilter("event", string(dockerEvents.ActionStart))
|
DockerFilterStart = filters.Arg("event", string(dockerEvents.ActionStart))
|
||||||
DockerFilterStop = NewDockerFilter("event", string(dockerEvents.ActionStop))
|
DockerFilterStop = filters.Arg("event", string(dockerEvents.ActionStop))
|
||||||
DockerFilterDie = NewDockerFilter("event", string(dockerEvents.ActionDie))
|
DockerFilterDie = filters.Arg("event", string(dockerEvents.ActionDie))
|
||||||
DockerFilterDestroy = NewDockerFilter("event", string(dockerEvents.ActionDestroy))
|
DockerFilterDestroy = filters.Arg("event", string(dockerEvents.ActionDestroy))
|
||||||
DockerFilterKill = NewDockerFilter("event", string(dockerEvents.ActionKill))
|
DockerFilterKill = filters.Arg("event", string(dockerEvents.ActionKill))
|
||||||
DockerFilterPause = NewDockerFilter("event", string(dockerEvents.ActionPause))
|
DockerFilterPause = filters.Arg("event", string(dockerEvents.ActionPause))
|
||||||
DockerFilterUnpause = NewDockerFilter("event", string(dockerEvents.ActionUnPause))
|
DockerFilterUnpause = filters.Arg("event", string(dockerEvents.ActionUnPause))
|
||||||
|
|
||||||
optionsDefault = DockerListOptions{Filters: NewDockerFilters(
|
NewDockerFilter = filters.NewArgs
|
||||||
|
|
||||||
|
optionsDefault = DockerListOptions{Filters: NewDockerFilter(
|
||||||
DockerFilterContainer,
|
DockerFilterContainer,
|
||||||
DockerFilterStart,
|
DockerFilterStart,
|
||||||
// DockerFilterStop,
|
// DockerFilterStop,
|
||||||
@@ -72,8 +54,8 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func DockerFilterContainerNameID(nameOrID string) DockerFilter {
|
func DockerFilterContainerNameID(nameOrID string) filters.KeyValuePair {
|
||||||
return NewDockerFilter("container", nameOrID)
|
return filters.Arg("container", nameOrID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerWatcher(dockerCfg types.DockerProviderConfig) DockerWatcher {
|
func NewDockerWatcher(dockerCfg types.DockerProviderConfig) DockerWatcher {
|
||||||
@@ -106,15 +88,15 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList
|
|||||||
client.Close()
|
client.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
chs := client.Events(ctx, options)
|
cEventCh, cErrCh := client.Events(ctx, options)
|
||||||
defer log.Debug().Str("host", client.DaemonHost()).Msg("docker watcher closed")
|
defer log.Debug().Str("host", client.DaemonHost()).Msg("docker watcher closed")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
case msg := <-chs.Messages:
|
case msg := <-cEventCh:
|
||||||
w.handleEvent(msg, eventCh)
|
w.handleEvent(msg, eventCh)
|
||||||
case err := <-chs.Err:
|
case err := <-cErrCh:
|
||||||
if err == nil {
|
if err == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -142,7 +124,7 @@ func (w DockerWatcher) EventsWithOptions(ctx context.Context, options DockerList
|
|||||||
// connection successful, trigger reload (reload routes)
|
// connection successful, trigger reload (reload routes)
|
||||||
eventCh <- reloadTrigger
|
eventCh <- reloadTrigger
|
||||||
// reopen event channel
|
// reopen event channel
|
||||||
chs = client.Events(ctx, options)
|
cEventCh, cErrCh = client.Events(ctx, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
|
|
||||||
dockerEvents "github.com/moby/moby/api/types/events"
|
dockerEvents "github.com/docker/docker/api/types/events"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
||||||
echo "Working tree is not clean. Commit or stash changes before running refresh-compat.sh." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
git fetch origin main compat
|
git fetch origin main compat
|
||||||
git checkout -B compat origin/compat
|
git checkout -B compat origin/compat
|
||||||
patch_file="$(mktemp)"
|
patch_file="$(mktemp)"
|
||||||
|
|||||||
Reference in New Issue
Block a user