diff --git a/.fleet/run.json b/.fleet/run.json index 73ef180..d2adbfd 100644 --- a/.fleet/run.json +++ b/.fleet/run.json @@ -3,9 +3,8 @@ { "type": "go", "name": "Run RoadSign", - "goExecPath": "C:\\Tools\\Scoop\\shims\\go.exe", - "buildParams": ["code.smartsheep.studio/goatworks/roadsign/pkg/cmd"], + "goExecPath": "/opt/homebrew/bin/go", + "buildParams": ["code.smartsheep.studio/goatworks/roadsign/pkg/cmd/server"], }, - ] } \ No newline at end of file diff --git a/.gitignore b/.gitignore index e5f2b59..71983f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -/config -/letsencrypt \ No newline at end of file +/letsencrypt + +.DS_Store \ No newline at end of file diff --git a/.idea/RoadSign.iml b/.idea/RoadSign.iml index 5e764c4..9dda0dd 100644 --- a/.idea/RoadSign.iml +++ b/.idea/RoadSign.iml @@ -1,9 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..53e6b55 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 4b16287..4fdcfbd 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,19 @@ A blazing fast reverse proxy with a lot of shining features. ## Features 1. Reverse proxy -2. Static file hosting -3. ~~Analytics and Metrics~~ -4. Integrate with CI/CD -5. Webhook integration -6. ~~Web management panel~~ -7. One-liner CLI -8. **Blazing fast ⚡** +2. HTTP2 Support +3. WebSocket Support +4. Static File Hosting +5. Low Configuration +6. Analytics and Metrics +7. Integrate with CI/CD +8. Web management panel (Work in progres for v2, available in v1) +9. One-liner CLI +10. Open-source and free +11. **Blazing fast ⚡** -> Deleted item means under construction, check out our roadmap! +> [!IMPORTANT] +> Currently roadsign haven't supported for server-side events. We are working on it. ### How fast is it? @@ -42,7 +46,7 @@ We strongly recommend you install RoadSign via docker compose. version: "3" services: roadsign: - image: code.smartsheep.studio/goatworks/roadsign:nightly + image: xsheep2010/roadsign:nightly restart: always volumes: - "./certs:/certs" # Optional, use for storage certificates @@ -55,12 +59,11 @@ services: - "81:81" ``` -After that, you can manage your roadsign instance with RoadSign CLI aka. RDS CLI. +After that, you can manage your roadsign instance with RoadSign CLI aka. RDC. To install it, run this command. (Make sure you have golang toolchain on your computer) ```shell -go install -buildvcs code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds@latest -# Tips: Add `buildvsc` flag to provide more detail compatibility check. +go install code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rdc@latest ``` ## Usage @@ -73,7 +76,7 @@ After configure, you need sync your config to remote server. Before that, add a rds cli with this command. ```shell -rds connect +rdc connect # ID will allow you find this server in after commands. # URL is to your roadsign server sideload api. # Password is your roadsign server credential. @@ -85,7 +88,7 @@ rds connect Then, sync your local config to remote. ```shell -rds sync +rdc sync # Server ID is your server added by last command. # Site ID is your new site id or old site id if you need update it. # Config File is your local config file path. diff --git a/config/example.toml b/config/example.toml new file mode 100644 index 0000000..6a1957d --- /dev/null +++ b/config/example.toml @@ -0,0 +1,31 @@ +id = "example-region" + +[[locations]] +id = "example-websocket" +host = ["localhost:8000"] +path = ["/ws"] +[[locations.destinations]] +id = "example-websocket-destination" +uri = "http://localhost:8765" + +[[locations]] +id = "example-warden" +host = ["localhost:4321"] +path = ["/"] +[[locations.destinations]] +id = "example-warden-destination" +uri = "http://localhost:4321" + +[[applications]] +id = "example-warden-app" +workdir = "test/data/warden" +command = ["node", "dist/server/entry.mjs"] +environment = ["PUBLIC_CMS=https://smartsheep.studio"] + +[[locations]] +id = "example-static" +host = ["localhost:8000"] +path = ["/roadsign"] +[[locations.destinations]] +id = "example-static-destination" +uri = "files://test/data" \ No newline at end of file diff --git a/go.mod b/go.mod index 3f5d04c..0aada8f 100644 --- a/go.mod +++ b/go.mod @@ -3,29 +3,32 @@ module code.smartsheep.studio/goatworks/roadsign go 1.21.4 require ( - github.com/gofiber/fiber/v2 v2.51.0 - github.com/google/uuid v1.4.0 + github.com/fasthttp/websocket v1.5.7 + github.com/gofiber/fiber/v2 v2.52.0 + github.com/google/uuid v1.6.0 + github.com/json-iterator/go v1.1.12 github.com/rs/zerolog v1.31.0 github.com/samber/lo v1.38.1 github.com/saracen/fastzip v0.1.11 github.com/spf13/viper v1.17.0 github.com/urfave/cli/v2 v2.26.0 - github.com/valyala/fasthttp v1.50.0 + github.com/valyala/fasthttp v1.51.0 ) require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/saracen/zipextra v0.0.0-20220303013732-0187cb0159ea // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.5.0 // indirect ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/klauspost/compress v1.17.4 // indirect @@ -34,13 +37,13 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.1 github.com/philhofer/fwd v1.1.2 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.4 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.10.0 // indirect + github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -50,9 +53,8 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 393aba1..e834ea5 100644 --- a/go.sum +++ b/go.sum @@ -1,53 +1,5 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -55,100 +7,28 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4= +github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= -github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= +github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -168,19 +48,17 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w 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/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -198,10 +76,12 @@ github.com/saracen/fastzip v0.1.11 h1:NnExbTEJbya7148cov09BCxwfur9tQ5BQ1QyQH6Xle github.com/saracen/fastzip v0.1.11/go.mod h1:/lN5BiU451/OZMS+hfhVsSDj/RNrxYmO9EYxCtMrFrY= github.com/saracen/zipextra v0.0.0-20220303013732-0187cb0159ea h1:8czYLkvzZRE+AElIQeDffQdgR+CC3wKEFILYU/1PeX4= github.com/saracen/zipextra v0.0.0-20220303013732-0187cb0159ea/go.mod h1:hnzuad9d2wdd3z8fC6UouHQK5qZxqv3F/E6MMzXc7q0= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -212,9 +92,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= @@ -227,163 +104,36 @@ github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -392,186 +142,27 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/cmd/rds/conn/commands.go b/pkg/cmd/rdc/conn/commands.go similarity index 100% rename from pkg/cmd/rds/conn/commands.go rename to pkg/cmd/rdc/conn/commands.go diff --git a/pkg/cmd/rds/conn/connect.go b/pkg/cmd/rdc/conn/connect.go similarity index 96% rename from pkg/cmd/rds/conn/connect.go rename to pkg/cmd/rdc/conn/connect.go index abd48a3..7c9ddc2 100644 --- a/pkg/cmd/rds/conn/connect.go +++ b/pkg/cmd/rdc/conn/connect.go @@ -17,7 +17,7 @@ type CliConnection struct { } func (v CliConnection) CheckConnectivity() error { - client := fiber.Get(v.Url + "/cgi/connectivity") + client := fiber.Get(v.Url + "/cgi/metadata") client.BasicAuth("RoadSign CLI", v.Credential) if status, data, err := client.Bytes(); len(err) > 0 { diff --git a/pkg/cmd/rds/conn/directory.go b/pkg/cmd/rdc/conn/directory.go similarity index 100% rename from pkg/cmd/rds/conn/directory.go rename to pkg/cmd/rdc/conn/directory.go diff --git a/pkg/cmd/rds/deploy/commands.go b/pkg/cmd/rdc/deploy/commands.go similarity index 91% rename from pkg/cmd/rds/deploy/commands.go rename to pkg/cmd/rdc/deploy/commands.go index 4770dae..cabf2a7 100644 --- a/pkg/cmd/rds/deploy/commands.go +++ b/pkg/cmd/rdc/deploy/commands.go @@ -2,17 +2,16 @@ package deploy import ( "fmt" - jsoniter "github.com/json-iterator/go" "io" "os" "strings" - "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds/conn" - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" + jsoniter "github.com/json-iterator/go" + + "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rdc/conn" "github.com/gofiber/fiber/v2" "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" - "gopkg.in/yaml.v2" ) var DeployCommands = []*cli.Command{ @@ -58,7 +57,6 @@ var DeployCommands = []*cli.Command{ }, { Name: "sync", - Aliases: []string{"sc"}, ArgsUsage: " ", Action: func(ctx *cli.Context) error { if ctx.Args().Len() < 3 { @@ -72,19 +70,18 @@ var DeployCommands = []*cli.Command{ return fmt.Errorf("couldn't connect server: %s", err.Error()) } - var site sign.SiteConfig + var raw []byte if file, err := os.Open(ctx.Args().Get(2)); err != nil { return err } else { - raw, _ := io.ReadAll(file) - yaml.Unmarshal(raw, &site) + raw, _ = io.ReadAll(file) } url := fmt.Sprintf("/webhooks/sync/%s", ctx.Args().Get(1)) client := fiber.Put(server.Url+url). JSONEncoder(jsoniter.ConfigCompatibleWithStandardLibrary.Marshal). JSONDecoder(jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal). - JSON(site). + Body(raw). BasicAuth("RoadSign CLI", server.Credential) if status, data, err := client.Bytes(); len(err) > 0 { diff --git a/pkg/cmd/rds/main.go b/pkg/cmd/rdc/main.go similarity index 86% rename from pkg/cmd/rds/main.go rename to pkg/cmd/rdc/main.go index 775315d..9435cf8 100644 --- a/pkg/cmd/rds/main.go +++ b/pkg/cmd/rdc/main.go @@ -4,8 +4,8 @@ import ( "os" roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" - "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds/conn" - "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds/deploy" + "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rdc/conn" + "code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rdc/deploy" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/viper" @@ -21,7 +21,7 @@ func main() { // Configure settings viper.AddConfigPath("$HOME") viper.SetConfigName(".roadsignrc") - viper.SetConfigType("yaml") + viper.SetConfigType("toml") // Load settings if err := viper.ReadInConfig(); err != nil { diff --git a/pkg/cmd/server/main.go b/pkg/cmd/server/main.go index 3d2af03..812aa01 100644 --- a/pkg/cmd/server/main.go +++ b/pkg/cmd/server/main.go @@ -8,8 +8,8 @@ import ( roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" "code.smartsheep.studio/goatworks/roadsign/pkg/hypertext" + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" "code.smartsheep.studio/goatworks/roadsign/pkg/sideload" - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" "github.com/google/uuid" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -26,7 +26,7 @@ func main() { viper.AddConfigPath(".") viper.AddConfigPath("..") viper.SetConfigName("settings") - viper.SetConfigType("yaml") + viper.SetConfigType("toml") // Load settings if err := viper.ReadInConfig(); err != nil { @@ -43,20 +43,15 @@ func main() { log.Warn().Msgf("RoadSign auto generated api credential is %s", credential) } - // Load & init sign - if err := sign.ReadInConfig(viper.GetString("paths.configs")); err != nil { + // Load & init navigator + if err := navi.ReadInConfig(viper.GetString("paths.configs")); err != nil { log.Panic().Err(err).Msg("An error occurred when loading configurations.") } else { - log.Info().Int("count", len(sign.App.Sites)).Msg("All configuration has been loaded.") + log.Info().Int("count", len(navi.R.Regions)).Msg("All configuration has been loaded.") } - // Preheat processes - go func() { - log.Info().Msg("Preheating processes...") - sign.App.PreheatProcesses(func(total int, success int) { - log.Info().Int("requested", total).Int("succeed", success).Msgf("Preheat processes completed!") - }) - }() + // Init warden + navi.InitializeWarden(navi.R.Regions) // Init hypertext server hypertext.RunServer( diff --git a/pkg/hypertext/proxies.go b/pkg/hypertext/proxies.go index 719d377..0825210 100644 --- a/pkg/hypertext/proxies.go +++ b/pkg/hypertext/proxies.go @@ -1,9 +1,11 @@ package hypertext import ( + "github.com/spf13/viper" + "math/rand" "regexp" - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) @@ -16,16 +18,16 @@ func UseProxies(app *fiber.App) { headers := ctx.GetReqHeaders() // Filtering sites - for _, site := range sign.App.Sites { + for _, region := range navi.R.Regions { // Matching rules - for _, rule := range site.Rules { - if !lo.Contains(rule.Host, host) { + for _, location := range region.Locations { + if !lo.Contains(location.Host, host) { continue } if !func() bool { flag := false - for _, pattern := range rule.Path { + for _, pattern := range location.Path { if ok, _ := regexp.MatchString(pattern, path); ok { flag = true break @@ -38,7 +40,7 @@ func UseProxies(app *fiber.App) { // Filter query strings flag := true - for rk, rv := range rule.Queries { + for rk, rv := range location.Queries { for ik, iv := range queries { if rk != ik && rv != iv { flag = false @@ -54,7 +56,7 @@ func UseProxies(app *fiber.App) { } // Filter headers - for rk, rv := range rule.Headers { + for rk, rv := range location.Headers { for ik, iv := range headers { if rk == ik { for _, ov := range iv { @@ -76,9 +78,12 @@ func UseProxies(app *fiber.App) { continue } + idx := rand.Intn(len(location.Destinations)) + dest := location.Destinations[idx] + // Passing all the rules means the site is what we are looking for. // Let us respond to our client! - return makeResponse(ctx, site) + return makeResponse(ctx, region, &location, &dest) } } @@ -89,23 +94,46 @@ func UseProxies(app *fiber.App) { }) } -func makeResponse(ctx *fiber.Ctx, site *sign.SiteConfig) error { +func makeResponse(ctx *fiber.Ctx, region *navi.Region, location *navi.Location, dest *navi.Destination) error { + uri := ctx.Request().URI().String() + // Modify request - for _, transformer := range site.Transformers { + for _, transformer := range dest.Transformers { if err := transformer.TransformRequest(ctx); err != nil { return err } } // Forward - err := sign.App.Forward(ctx, site) + err := navi.R.Forward(ctx, dest) // Modify response - for _, transformer := range site.Transformers { + for _, transformer := range dest.Transformers { if err := transformer.TransformResponse(ctx); err != nil { return err } } + // Collect trace + if viper.GetBool("telemetry.capture_traces") { + var message string + if err != nil { + message = err.Error() + } + + go navi.R.AddTrace(navi.RoadTrace{ + Region: region.ID, + Location: location.ID, + Destination: dest.ID, + Uri: uri, + IpAddress: ctx.IP(), + UserAgent: ctx.Get(fiber.HeaderUserAgent), + Error: navi.RoadTraceError{ + IsNull: err == nil, + Message: message, + }, + }) + } + return err } diff --git a/pkg/meta.go b/pkg/meta.go index 0aa016b..7b661f6 100644 --- a/pkg/meta.go +++ b/pkg/meta.go @@ -14,4 +14,4 @@ func init() { } } -var AppVersion = "1.2.1" +var AppVersion = "2.0.0-delta1" diff --git a/pkg/sign/configurator.go b/pkg/navi/config.go similarity index 50% rename from pkg/sign/configurator.go rename to pkg/navi/config.go index 250a347..f165901 100644 --- a/pkg/sign/configurator.go +++ b/pkg/navi/config.go @@ -1,4 +1,4 @@ -package sign +package navi import ( "io" @@ -6,32 +6,39 @@ import ( "path/filepath" "strings" - "gopkg.in/yaml.v2" + "github.com/spf13/viper" + + "github.com/pelletier/go-toml/v2" ) -var App *RoadApp +var R *RoadApp func ReadInConfig(root string) error { instance := &RoadApp{ - Sites: []*SiteConfig{}, + Regions: make([]*Region, 0), + Traces: make([]RoadTrace, 0, viper.GetInt("performance.traces_limit")), } - if err := filepath.Walk(root, func(fp string, info os.FileInfo, err error) error { - var site SiteConfig + if err := filepath.Walk(root, func(fp string, info os.FileInfo, _ error) error { + var region Region if info.IsDir() { return nil + } else if !strings.HasSuffix(info.Name(), ".toml") { + return nil } else if file, err := os.OpenFile(fp, os.O_RDONLY, 0755); err != nil { return err } else if data, err := io.ReadAll(file); err != nil { return err - } else if err := yaml.Unmarshal(data, &site); err != nil { + } else if err := toml.Unmarshal(data, ®ion); err != nil { return err } else { defer file.Close() - // Extract file name as site id - site.ID = strings.SplitN(filepath.Base(fp), ".", 2)[0] - instance.Sites = append(instance.Sites, &site) + if region.Disabled { + return nil + } + + instance.Regions = append(instance.Regions, ®ion) } return nil @@ -39,7 +46,7 @@ func ReadInConfig(root string) error { return err } - App = instance + R = instance return nil } diff --git a/pkg/navi/metrics.go b/pkg/navi/metrics.go new file mode 100644 index 0000000..550c2c7 --- /dev/null +++ b/pkg/navi/metrics.go @@ -0,0 +1,25 @@ +package navi + +import "github.com/spf13/viper" + +type RoadTrace struct { + Region string `json:"region"` + Location string `json:"location"` + Destination string `json:"destination"` + Uri string `json:"uri"` + IpAddress string `json:"ip_address"` + UserAgent string `json:"user_agent"` + Error RoadTraceError `json:"error"` +} + +type RoadTraceError struct { + IsNull bool `json:"is_null"` + Message string `json:"message"` +} + +func (v *RoadApp) AddTrace(trace RoadTrace) { + v.Traces = append(v.Traces, trace) + if len(v.Traces) > viper.GetInt("performance.traces_limit") { + v.Traces = v.Traces[1:] + } +} diff --git a/pkg/sign/responder.go b/pkg/navi/responder.go similarity index 55% rename from pkg/sign/responder.go rename to pkg/navi/responder.go index 5f53d9e..7cb2932 100644 --- a/pkg/sign/responder.go +++ b/pkg/navi/responder.go @@ -1,33 +1,110 @@ -package sign +package navi import ( "errors" "fmt" + "github.com/fasthttp/websocket" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/proxy" + "github.com/gofiber/fiber/v2/utils" + "github.com/rs/zerolog/log" + "github.com/samber/lo" + "github.com/spf13/viper" + "github.com/valyala/fasthttp" "io/fs" "net/http" "path/filepath" "strconv" "strings" "time" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/proxy" - "github.com/gofiber/fiber/v2/utils" - "github.com/samber/lo" - "github.com/spf13/viper" - "github.com/valyala/fasthttp" ) -func makeHypertextResponse(c *fiber.Ctx, upstream *UpstreamInstance) error { +func makeUnifiedResponse(c *fiber.Ctx, dest *Destination) error { + if websocket.FastHTTPIsWebSocketUpgrade(c.Context()) { + // Handle websocket + return makeWebsocketResponse(c, dest) + } else { + _, queries := dest.GetRawUri() + if len(queries.Get("sse")) > 0 { + // Handle server-side event + return makeSeverSideEventResponse(c, dest) + } else { + // Handle normal http request + return makeHypertextResponse(c, dest) + } + } +} + +func makeHypertextResponse(c *fiber.Ctx, dest *Destination) error { timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond - return proxy.Do(c, upstream.MakeURI(c), &fasthttp.Client{ + return proxy.Do(c, dest.MakeUri(c), &fasthttp.Client{ ReadTimeout: timeout, WriteTimeout: timeout, }) } -func makeFileResponse(c *fiber.Ctx, upstream *UpstreamInstance) error { - uri, queries := upstream.GetRawURI() +var wsUpgrader = websocket.FastHTTPUpgrader{} + +func makeWebsocketResponse(c *fiber.Ctx, dest *Destination) error { + uri := dest.MakeWebsocketUri(c) + + // Upgrade connection + return wsUpgrader.Upgrade(c.Context(), func(conn *websocket.Conn) { + // Dial the destination + remote, _, err := websocket.DefaultDialer.Dial(uri, nil) + if err != nil { + return + } + defer remote.Close() + + // Read messages from remote + disconnect := make(chan struct{}) + signal := make(chan struct { + head int + data []byte + }) + go func() { + defer close(disconnect) + for { + mode, message, err := remote.ReadMessage() + if err != nil { + log.Warn().Err(err).Msg("An error occurred during the websocket proxying...") + return + } else { + signal <- struct { + head int + data []byte + }{head: mode, data: message} + } + } + }() + + // Relay the destination websocket to client + for { + select { + case <-disconnect: + case val := <-signal: + if err := conn.WriteMessage(val.head, val.data); err != nil { + return + } + default: + if head, data, err := conn.ReadMessage(); err != nil { + return + } else { + remote.WriteMessage(head, data) + } + } + } + }) +} + +func makeSeverSideEventResponse(c *fiber.Ctx, dest *Destination) error { + // TODO Impl SSE with https://github.com/gofiber/recipes/blob/master/sse/main.go + return fiber.NewError(fiber.StatusNotImplemented, "Server-side-events was not available now.") +} + +func makeFileResponse(c *fiber.Ctx, dest *Destination) error { + uri, queries := dest.GetRawUri() root := http.Dir(uri) method := c.Method() diff --git a/pkg/navi/route.go b/pkg/navi/route.go new file mode 100644 index 0000000..fd4bd03 --- /dev/null +++ b/pkg/navi/route.go @@ -0,0 +1,25 @@ +package navi + +import ( + "code.smartsheep.studio/goatworks/roadsign/pkg/navi/transformers" + + "github.com/gofiber/fiber/v2" +) + +type RoadApp struct { + Regions []*Region `json:"regions"` + Traces []RoadTrace `json:"traces"` +} + +func (v *RoadApp) Forward(ctx *fiber.Ctx, dest *Destination) error { + switch dest.GetType() { + case DestinationHypertext: + return makeUnifiedResponse(ctx, dest) + case DestinationStaticFile: + return makeFileResponse(ctx, dest) + default: + return fiber.ErrBadGateway + } +} + +type RequestTransformerConfig = transformers.TransformerConfig diff --git a/pkg/navi/struct.go b/pkg/navi/struct.go new file mode 100644 index 0000000..3926470 --- /dev/null +++ b/pkg/navi/struct.go @@ -0,0 +1,87 @@ +package navi + +import ( + "fmt" + "net/url" + "strings" + + "code.smartsheep.studio/goatworks/roadsign/pkg/navi/transformers" + "code.smartsheep.studio/goatworks/roadsign/pkg/warden" + "github.com/gofiber/fiber/v2" + "github.com/samber/lo" +) + +type Region struct { + ID string `json:"id" toml:"id"` + Disabled bool `json:"disabled" toml:"disabled"` + Locations []Location `json:"locations" toml:"locations"` + Applications []warden.Application `json:"applications" toml:"applications"` +} + +type Location struct { + ID string `json:"id" toml:"id"` + Host []string `json:"host" toml:"host"` + Path []string `json:"path" toml:"path"` + Queries map[string]string `json:"queries" toml:"queries"` + Headers map[string][]string `json:"headers" toml:"headers"` + Destinations []Destination `json:"destinations" toml:"destinations"` +} + +type DestinationType = int8 + +const ( + DestinationHypertext = DestinationType(iota) + DestinationStaticFile + DestinationUnknown +) + +type Destination struct { + ID string `json:"id" toml:"id"` + Uri string `json:"uri" toml:"uri"` + Transformers []transformers.TransformerConfig `json:"transformers" toml:"transformers"` +} + +func (v *Destination) GetProtocol() string { + return strings.SplitN(v.Uri, "://", 2)[0] +} + +func (v *Destination) GetType() DestinationType { + protocol := v.GetProtocol() + switch protocol { + case "http", "https": + return DestinationHypertext + case "file", "files": + return DestinationStaticFile + } + return DestinationUnknown +} + +func (v *Destination) GetRawUri() (string, url.Values) { + uri := strings.SplitN(v.Uri, "://", 2)[1] + data := strings.SplitN(uri, "?", 2) + data = append(data, " ") // Make data array least have two element + qs, _ := url.ParseQuery(data[1]) + + return data[0], qs +} + +func (v *Destination) MakeUri(ctx *fiber.Ctx) string { + var queries []string + for k, v := range ctx.Queries() { + parsed, _ := url.QueryUnescape(v) + value := url.QueryEscape(parsed) + queries = append(queries, fmt.Sprintf("%s=%s", k, value)) + } + + path := string(ctx.Request().URI().Path()) + hash := string(ctx.Request().URI().Hash()) + uri, _ := v.GetRawUri() + + return uri + path + + lo.Ternary(len(queries) > 0, "?"+strings.Join(queries, "&"), "") + + lo.Ternary(len(hash) > 0, "#"+hash, "") +} + +func (v *Destination) MakeWebsocketUri(ctx *fiber.Ctx) string { + return strings.Replace(v.MakeUri(ctx), "http", "ws", 1) +} diff --git a/pkg/sign/transformers/compress.go b/pkg/navi/transformers/compress.go similarity index 86% rename from pkg/sign/transformers/compress.go rename to pkg/navi/transformers/compress.go index 5e8d3b1..5ec91d9 100644 --- a/pkg/sign/transformers/compress.go +++ b/pkg/navi/transformers/compress.go @@ -5,13 +5,13 @@ import ( "github.com/valyala/fasthttp" ) -var CompressResponse = RequestTransformer{ +var CompressResponse = Transformer{ ModifyResponse: func(options any, ctx *fiber.Ctx) error { opts := DeserializeOptions[struct { - Level int `json:"level" yaml:"level"` + Level int `json:"level" toml:"level"` }](options) - var fctx = func(c *fasthttp.RequestCtx) {} + fctx := func(c *fasthttp.RequestCtx) {} var compressor fasthttp.RequestHandler switch opts.Level { // Best Speed Mode diff --git a/pkg/sign/transformers/module.go b/pkg/navi/transformers/module.go similarity index 71% rename from pkg/sign/transformers/module.go rename to pkg/navi/transformers/module.go index 18cfe8a..3dc165a 100644 --- a/pkg/sign/transformers/module.go +++ b/pkg/navi/transformers/module.go @@ -9,17 +9,17 @@ import ( var json = jsoniter.ConfigCompatibleWithStandardLibrary -type RequestTransformer struct { +type Transformer struct { ModifyRequest func(options any, ctx *fiber.Ctx) error ModifyResponse func(options any, ctx *fiber.Ctx) error } -type RequestTransformerConfig struct { - Type string `json:"type" yaml:"type"` - Options any `json:"options" yaml:"options"` +type TransformerConfig struct { + Type string `json:"type" toml:"type"` + Options any `json:"options" toml:"options"` } -func (v *RequestTransformerConfig) TransformRequest(ctx *fiber.Ctx) error { +func (v *TransformerConfig) TransformRequest(ctx *fiber.Ctx) error { for k, f := range Transformers { if k == v.Type { if f.ModifyRequest != nil { @@ -31,7 +31,7 @@ func (v *RequestTransformerConfig) TransformRequest(ctx *fiber.Ctx) error { return nil } -func (v *RequestTransformerConfig) TransformResponse(ctx *fiber.Ctx) error { +func (v *TransformerConfig) TransformResponse(ctx *fiber.Ctx) error { for k, f := range Transformers { if k == v.Type { if f.ModifyResponse != nil { @@ -55,7 +55,7 @@ func DeserializeOptions[T any](data any) T { // Map of Transformers // Every transformer need to be mapped here so that they can get work. -var Transformers = map[string]RequestTransformer{ +var Transformers = map[string]Transformer{ "replacePath": ReplacePath, "compressResponse": CompressResponse, } diff --git a/pkg/sign/transformers/replace_path.go b/pkg/navi/transformers/replace_path.go similarity index 66% rename from pkg/sign/transformers/replace_path.go rename to pkg/navi/transformers/replace_path.go index 8dc4d65..0339d58 100644 --- a/pkg/sign/transformers/replace_path.go +++ b/pkg/navi/transformers/replace_path.go @@ -1,18 +1,19 @@ package transformers import ( - "github.com/gofiber/fiber/v2" "regexp" "strings" + + "github.com/gofiber/fiber/v2" ) -var ReplacePath = RequestTransformer{ +var ReplacePath = Transformer{ ModifyRequest: func(options any, ctx *fiber.Ctx) error { opts := DeserializeOptions[struct { - Pattern string `json:"pattern" yaml:"pattern"` - Value string `json:"value" yaml:"value"` - Repl string `json:"repl" yaml:"repl"` // Use when complex mode(regexp) enabled - Complex bool `json:"complex" yaml:"complex"` + Pattern string `json:"pattern" toml:"pattern"` + Value string `json:"value" toml:"value"` + Repl string `json:"repl" toml:"repl"` // Use when complex mode(regexp) enabled + Complex bool `json:"complex" toml:"complex"` }](options) path := string(ctx.Request().URI().Path()) if !opts.Complex { diff --git a/pkg/navi/warden.go b/pkg/navi/warden.go new file mode 100644 index 0000000..594b781 --- /dev/null +++ b/pkg/navi/warden.go @@ -0,0 +1,17 @@ +package navi + +import "code.smartsheep.studio/goatworks/roadsign/pkg/warden" + +func InitializeWarden(regions []*Region) { + for _, region := range regions { + for _, application := range region.Applications { + warden.InstancePool = append(warden.InstancePool, &warden.AppInstance{ + Manifest: application, + }) + } + } + + for _, instance := range warden.InstancePool { + instance.Wake() + } +} diff --git a/pkg/sideload/applications.go b/pkg/sideload/applications.go new file mode 100644 index 0000000..88c5e2d --- /dev/null +++ b/pkg/sideload/applications.go @@ -0,0 +1,26 @@ +package sideload + +import ( + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" + "code.smartsheep.studio/goatworks/roadsign/pkg/warden" + "github.com/gofiber/fiber/v2" + "github.com/samber/lo" +) + +func getApplications(c *fiber.Ctx) error { + applications := lo.FlatMap(navi.R.Regions, func(item *navi.Region, idx int) []warden.Application { + return item.Applications + }) + + return c.JSON(applications) +} + +func getApplicationLogs(c *fiber.Ctx) error { + if instance, ok := lo.Find(warden.InstancePool, func(item *warden.AppInstance) bool { + return item.Manifest.ID == c.Params("id") + }); !ok { + return fiber.NewError(fiber.StatusNotFound) + } else { + return c.SendString(instance.Logs()) + } +} diff --git a/pkg/sideload/connectivity.go b/pkg/sideload/metadata.go similarity index 82% rename from pkg/sideload/connectivity.go rename to pkg/sideload/metadata.go index 298c449..f1c8b22 100644 --- a/pkg/sideload/connectivity.go +++ b/pkg/sideload/metadata.go @@ -5,7 +5,7 @@ import ( "github.com/gofiber/fiber/v2" ) -func responseConnectivity(c *fiber.Ctx) error { +func getMetadata(c *fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(fiber.Map{ "server": "RoadSign", "version": roadsign.AppVersion, diff --git a/pkg/sideload/metrics.go b/pkg/sideload/metrics.go new file mode 100644 index 0000000..25d42ba --- /dev/null +++ b/pkg/sideload/metrics.go @@ -0,0 +1,10 @@ +package sideload + +import ( + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" + "github.com/gofiber/fiber/v2" +) + +func getTraces(c *fiber.Ctx) error { + return c.JSON(navi.R.Traces) +} \ No newline at end of file diff --git a/pkg/sideload/processes.go b/pkg/sideload/processes.go deleted file mode 100644 index 6d4267e..0000000 --- a/pkg/sideload/processes.go +++ /dev/null @@ -1,29 +0,0 @@ -package sideload - -import ( - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" - "github.com/gofiber/fiber/v2" - "github.com/samber/lo" -) - -func getProcesses(c *fiber.Ctx) error { - processes := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance { - return item.Processes - }) - - return c.JSON(processes) -} - -func getProcessLog(c *fiber.Ctx) error { - processes := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance { - return item.Processes - }) - - if target, ok := lo.Find(processes, func(item *sign.ProcessInstance) bool { - return item.ID == c.Params("id") - }); !ok { - return fiber.NewError(fiber.StatusNotFound) - } else { - return c.SendString(target.GetLogs()) - } -} diff --git a/pkg/sideload/publish.go b/pkg/sideload/publish.go index c27f85a..4fd3b2d 100644 --- a/pkg/sideload/publish.go +++ b/pkg/sideload/publish.go @@ -1,11 +1,12 @@ package sideload import ( + "code.smartsheep.studio/goatworks/roadsign/pkg/warden" "context" "os" "path/filepath" - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" "github.com/gofiber/fiber/v2" "github.com/google/uuid" "github.com/samber/lo" @@ -14,23 +15,23 @@ import ( func doPublish(c *fiber.Ctx) error { var workdir string - var site *sign.SiteConfig - var upstream *sign.UpstreamInstance - var process *sign.ProcessInstance - for _, item := range sign.App.Sites { + var destination *navi.Destination + var application *warden.Application + for _, item := range navi.R.Regions { if item.ID == c.Params("site") { - site = item - for _, stream := range item.Upstreams { - if stream.ID == c.Params("slug") { - upstream = stream - workdir, _ = stream.GetRawURI() - break + for _, location := range item.Locations { + for _, dest := range location.Destinations { + if dest.ID == c.Params("slug") { + destination = &dest + workdir, _ = dest.GetRawUri() + break + } } } - for _, proc := range item.Processes { - if proc.ID == c.Params("slug") { - process = proc - workdir = proc.Workdir + for _, app := range item.Applications { + if app.ID == c.Params("slug") { + application = &app + workdir = app.Workdir break } } @@ -38,14 +39,15 @@ func doPublish(c *fiber.Ctx) error { } } - if upstream == nil && process == nil { - return fiber.ErrNotFound - } else if upstream != nil && upstream.GetType() != sign.UpstreamTypeFile { + var instance *warden.AppInstance + if application != nil { + if instance = warden.GetFromPool(application.ID); instance != nil { + instance.Stop() + } + } else if destination != nil && destination.GetType() != navi.DestinationStaticFile { return fiber.ErrUnprocessableEntity - } - - for _, process := range site.Processes { - process.StopProcess() + } else { + return fiber.ErrNotFound } if c.Query("overwrite", "yes") == "yes" { @@ -81,5 +83,9 @@ func doPublish(c *fiber.Ctx) error { } } + if instance != nil { + instance.Wake() + } + return c.SendStatus(fiber.StatusOK) } diff --git a/pkg/sideload/regions.go b/pkg/sideload/regions.go new file mode 100644 index 0000000..a22167e --- /dev/null +++ b/pkg/sideload/regions.go @@ -0,0 +1,67 @@ +package sideload + +import ( + "fmt" + "os" + "path/filepath" + + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" + "code.smartsheep.studio/goatworks/roadsign/pkg/warden" + "github.com/gofiber/fiber/v2" + "github.com/pelletier/go-toml/v2" + "github.com/samber/lo" + "github.com/spf13/viper" +) + +func getRegions(c *fiber.Ctx) error { + return c.JSON(navi.R.Regions) +} + +func getRegionConfig(c *fiber.Ctx) error { + fp := filepath.Join(viper.GetString("paths.configs"), c.Params("id")) + + var err error + var data []byte + if data, err = os.ReadFile(fp + ".toml"); err != nil { + return fiber.NewError(fiber.StatusNotFound, err.Error()) + } + + return c.Type("toml").SendString(string(data)) +} + +func doSync(c *fiber.Ctx) error { + req := string(c.Body()) + + id := c.Params("slug") + path := filepath.Join(viper.GetString("paths.configs"), fmt.Sprintf("%s.toml", id)) + + if file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755); err != nil { + return fiber.NewError(fiber.ErrInternalServerError.Code, err.Error()) + } else { + raw, _ := toml.Marshal(req) + file.Write(raw) + defer file.Close() + } + + var rebootQueue []*warden.AppInstance + if region, ok := lo.Find(navi.R.Regions, func(item *navi.Region) bool { + return item.ID == id + }); ok { + for _, application := range region.Applications { + if instance := warden.GetFromPool(application.ID); instance != nil { + instance.Stop() + rebootQueue = append(rebootQueue, instance) + } + } + } + + // Reload + navi.ReadInConfig(viper.GetString("paths.configs")) + + // Reboot + for _, instance := range rebootQueue { + instance.Wake() + } + + return c.SendStatus(fiber.StatusOK) +} diff --git a/pkg/sideload/server.go b/pkg/sideload/server.go index ce7bcba..4ac50de 100644 --- a/pkg/sideload/server.go +++ b/pkg/sideload/server.go @@ -1,11 +1,12 @@ package sideload import ( - "code.smartsheep.studio/goatworks/roadsign/pkg/sideload/view" "fmt" + "net/http" + + "code.smartsheep.studio/goatworks/roadsign/pkg/sideload/view" "github.com/gofiber/fiber/v2/middleware/filesystem" jsoniter "github.com/json-iterator/go" - "net/http" roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" "github.com/gofiber/fiber/v2" @@ -51,18 +52,19 @@ func InitSideload() *fiber.App { cgi := app.Group("/cgi").Name("CGI") { - cgi.All("/connectivity", responseConnectivity) - cgi.Get("/statistics", getStatistics) - cgi.Get("/sites", getSites) - cgi.Get("/sites/cfg/:id", getSiteConfig) - cgi.Get("/processes", getProcesses) - cgi.Get("/processes/logs/:id", getProcessLog) + cgi.Get("/metadata", getMetadata) + cgi.Get("/traces", getTraces) + cgi.Get("/stats", getStats) + cgi.Get("/regions", getRegions) + cgi.Get("/regions/cfg/:id", getRegionConfig) + cgi.Get("/applications", getApplications) + cgi.Get("/applications/logs/:id", getApplicationLogs) } webhooks := app.Group("/webhooks").Name("WebHooks") { webhooks.Put("/publish/:site/:slug", doPublish) - webhooks.Put("/sync/:slug", doSyncSite) + webhooks.Put("/sync/:slug", doSync) } return app diff --git a/pkg/sideload/sites.go b/pkg/sideload/sites.go deleted file mode 100644 index 6bb42b9..0000000 --- a/pkg/sideload/sites.go +++ /dev/null @@ -1,63 +0,0 @@ -package sideload - -import ( - "fmt" - "os" - "path/filepath" - - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" - "github.com/gofiber/fiber/v2" - "github.com/samber/lo" - "github.com/spf13/viper" - "gopkg.in/yaml.v2" -) - -func getSites(c *fiber.Ctx) error { - return c.JSON(sign.App.Sites) -} - -func getSiteConfig(c *fiber.Ctx) error { - fp := filepath.Join(viper.GetString("paths.configs"), c.Params("id")) - - var err error - var data []byte - if data, err = os.ReadFile(fp + ".yml"); err != nil { - if data, err = os.ReadFile(fp + ".yaml"); err != nil { - return fiber.NewError(fiber.StatusNotFound, err.Error()) - } - } - - return c.Type("yaml").SendString(string(data)) -} - -func doSyncSite(c *fiber.Ctx) error { - var req sign.SiteConfig - - if err := c.BodyParser(&req); err != nil { - return err - } - - id := c.Params("slug") - path := filepath.Join(viper.GetString("paths.configs"), fmt.Sprintf("%s.yaml", id)) - - if file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755); err != nil { - return fiber.NewError(fiber.ErrInternalServerError.Code, err.Error()) - } else { - raw, _ := yaml.Marshal(req) - file.Write(raw) - defer file.Close() - } - if site, ok := lo.Find(sign.App.Sites, func(item *sign.SiteConfig) bool { - return item.ID == id - }); ok { - for _, process := range site.Processes { - process.StopProcess() - } - } - - // Reload - sign.ReadInConfig(viper.GetString("paths.configs")) - sign.App.PreheatProcesses() - - return c.SendStatus(fiber.StatusOK) -} diff --git a/pkg/sideload/statistics.go b/pkg/sideload/statistics.go index 576e641..6543ae1 100644 --- a/pkg/sideload/statistics.go +++ b/pkg/sideload/statistics.go @@ -1,28 +1,27 @@ package sideload import ( - "code.smartsheep.studio/goatworks/roadsign/pkg/sign" + "code.smartsheep.studio/goatworks/roadsign/pkg/navi" + "code.smartsheep.studio/goatworks/roadsign/pkg/warden" "github.com/gofiber/fiber/v2" "github.com/samber/lo" ) -func getStatistics(c *fiber.Ctx) error { - upstreams := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.UpstreamInstance { - return item.Upstreams +func getStats(c *fiber.Ctx) error { + locations := lo.FlatMap(navi.R.Regions, func(item *navi.Region, idx int) []navi.Location { + return item.Locations }) - processes := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance { - return item.Processes + destinations := lo.FlatMap(locations, func(item navi.Location, idx int) []navi.Destination { + return item.Destinations }) - unhealthy := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance { - return lo.Filter(item.Processes, func(item *sign.ProcessInstance, idx int) bool { - return item.Status != sign.ProcessStarted - }) + applications := lo.FlatMap(navi.R.Regions, func(item *navi.Region, idx int) []warden.Application { + return item.Applications }) return c.JSON(fiber.Map{ - "sites": len(sign.App.Sites), - "upstreams": len(upstreams), - "processes": len(processes), - "status": len(unhealthy) == 0, + "regions": len(navi.R.Regions), + "locations": len(locations), + "destinations": len(destinations), + "applications": len(applications), }) } diff --git a/pkg/sideload/view/.dockerignore b/pkg/sideload/view/.dockerignore deleted file mode 100644 index 0b71a35..0000000 --- a/pkg/sideload/view/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -/dist -/node_modules -/*.lock diff --git a/pkg/sideload/view/.eslintrc.cjs b/pkg/sideload/view/.eslintrc.cjs deleted file mode 100644 index 6f40582..0000000 --- a/pkg/sideload/view/.eslintrc.cjs +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-env node */ -require('@rushstack/eslint-patch/modern-module-resolution') - -module.exports = { - root: true, - 'extends': [ - 'plugin:vue/vue3-essential', - 'eslint:recommended', - '@vue/eslint-config-typescript', - '@vue/eslint-config-prettier/skip-formatting' - ], - parserOptions: { - ecmaVersion: 'latest' - } -} diff --git a/pkg/sideload/view/.gitignore b/pkg/sideload/view/.gitignore index 8ee54e8..b732d3c 100644 --- a/pkg/sideload/view/.gitignore +++ b/pkg/sideload/view/.gitignore @@ -8,23 +8,20 @@ pnpm-debug.log* lerna-debug.log* node_modules -.DS_Store dist dist-ssr -coverage *.local -/cypress/videos/ -/cypress/screenshots/ - # Editor directories and files .vscode/* !.vscode/extensions.json .idea +.DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? -*.tsbuildinfo +*.lock +package-lock.json \ No newline at end of file diff --git a/pkg/sideload/view/.prettierrc.json b/pkg/sideload/view/.prettierrc.json deleted file mode 100644 index dbdb811..0000000 --- a/pkg/sideload/view/.prettierrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/prettierrc", - "semi": false, - "tabWidth": 2, - "singleQuote": false, - "printWidth": 120, - "trailingComma": "none" -} \ No newline at end of file diff --git a/pkg/sideload/view/.vscode/extensions.json b/pkg/sideload/view/.vscode/extensions.json deleted file mode 100644 index 009a534..0000000 --- a/pkg/sideload/view/.vscode/extensions.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "recommendations": [ - "Vue.volar", - "Vue.vscode-typescript-vue-plugin", - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode" - ] -} diff --git a/pkg/sideload/view/README.md b/pkg/sideload/view/README.md deleted file mode 100644 index 61136fc..0000000 --- a/pkg/sideload/view/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# @roadsign/sideload-ui - -This template should help get you started developing with Vue 3 in Vite. - -## Recommended IDE Setup - -[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). - -## Type Support for `.vue` Imports in TS - -TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types. - -If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps: - -1. Disable the built-in TypeScript Extension - 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette - 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)` -2. Reload the VSCode window by running `Developer: Reload Window` from the command palette. - -## Customize configuration - -See [Vite Configuration Reference](https://vitejs.dev/config/). - -## Project Setup - -```sh -yarn -``` - -### Compile and Hot-Reload for Development - -```sh -yarn dev -``` - -### Type-Check, Compile and Minify for Production - -```sh -yarn build -``` - -### Lint with [ESLint](https://eslint.org/) - -```sh -yarn lint -``` diff --git a/pkg/sideload/view/index.html b/pkg/sideload/view/index.html index c800b36..c7d1a70 100644 --- a/pkg/sideload/view/index.html +++ b/pkg/sideload/view/index.html @@ -1,13 +1,13 @@ - + - - - - RoadSign + + + + RoadSign Sideload -
- +
+ diff --git a/pkg/sideload/view/package.json b/pkg/sideload/view/package.json index 3f4be12..92fd4a1 100644 --- a/pkg/sideload/view/package.json +++ b/pkg/sideload/view/package.json @@ -1,44 +1,24 @@ { - "name": "@roadsign/sideload-ui", - "version": "0.0.0", + "name": "roadsign-sideload", "private": true, + "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", - "build": "run-p type-check \"build-only {@}\" --", - "preview": "vite preview", - "build-only": "vite build", - "type-check": "vue-tsc --build --force", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", - "format": "prettier --write src/" + "build": "tsc && vite build", + "preview": "vite preview" }, "dependencies": { - "@guolao/vue-monaco-editor": "^1.4.1", - "highlight.js": "^11.9.0", - "js-yaml": "^4.1.0", - "pinia": "^2.1.7", - "vue": "^3.3.11", - "vue-router": "^4.2.5" + "@solidjs/router": "^0.10.10", + "solid-js": "^1.8.7" }, "devDependencies": { - "@rushstack/eslint-patch": "^1.3.3", - "@tsconfig/node18": "^18.2.2", - "@types/js-yaml": "^4.0.9", - "@types/node": "^18.19.3", - "@vicons/carbon": "^0.12.0", - "@vitejs/plugin-vue": "^4.5.2", - "@vue/eslint-config-prettier": "^8.0.0", - "@vue/eslint-config-typescript": "^12.0.0", - "@vue/tsconfig": "^0.5.0", - "eslint": "^8.49.0", - "eslint-plugin-vue": "^9.17.0", - "naive-ui": "^2.36.0", - "npm-run-all2": "^6.1.1", - "prettier": "^3.0.3", - "typescript": "~5.3.0", - "unocss": "^0.58.2", - "vfonts": "^0.0.3", - "vite": "^5.0.10", - "vue-tsc": "^1.8.25" + "autoprefixer": "^10.4.17", + "daisyui": "^4.6.0", + "postcss": "^8.4.33", + "tailwindcss": "^3.4.1", + "typescript": "^5.2.2", + "vite": "^5.0.8", + "vite-plugin-solid": "^2.8.0" } } diff --git a/pkg/sideload/view/postcss.config.js b/pkg/sideload/view/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/pkg/sideload/view/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/pkg/sideload/view/src/assets/main.css b/pkg/sideload/view/src/assets/main.css deleted file mode 100644 index b60180e..0000000 --- a/pkg/sideload/view/src/assets/main.css +++ /dev/null @@ -1,6 +0,0 @@ -@import "vfonts/IBMPlexSans.css"; -@import "vfonts/IBMPlexMono.css"; - -a { - color: #3f7ee8; -} diff --git a/pkg/sideload/view/src/components/data/sites-table-action.vue b/pkg/sideload/view/src/components/data/sites-table-action.vue deleted file mode 100644 index 2443c9c..0000000 --- a/pkg/sideload/view/src/components/data/sites-table-action.vue +++ /dev/null @@ -1,135 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pkg/sideload/view/src/components/data/sites-table-add.vue b/pkg/sideload/view/src/components/data/sites-table-add.vue deleted file mode 100644 index 459c0b6..0000000 --- a/pkg/sideload/view/src/components/data/sites-table-add.vue +++ /dev/null @@ -1,110 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pkg/sideload/view/src/components/data/sites-table-expand.vue b/pkg/sideload/view/src/components/data/sites-table-expand.vue deleted file mode 100644 index eeafa95..0000000 --- a/pkg/sideload/view/src/components/data/sites-table-expand.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - \ No newline at end of file diff --git a/pkg/sideload/view/src/components/data/sites-table.vue b/pkg/sideload/view/src/components/data/sites-table.vue deleted file mode 100644 index cffd6d2..0000000 --- a/pkg/sideload/view/src/components/data/sites-table.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - \ No newline at end of file diff --git a/pkg/sideload/view/src/index.css b/pkg/sideload/view/src/index.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/pkg/sideload/view/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/pkg/sideload/view/src/index.tsx b/pkg/sideload/view/src/index.tsx new file mode 100644 index 0000000..58644b4 --- /dev/null +++ b/pkg/sideload/view/src/index.tsx @@ -0,0 +1,17 @@ +import "./index.css"; + +/* @refresh reload */ +import { render } from "solid-js/web"; + +import { Route, Router } from "@solidjs/router"; + +import RootLayout from "./layouts/RootLayout"; +import Dashboard from "./pages/dashboard"; + +const root = document.getElementById("root"); + +render(() => ( + + + +), root!); diff --git a/pkg/sideload/view/src/layouts/RootLayout.tsx b/pkg/sideload/view/src/layouts/RootLayout.tsx new file mode 100644 index 0000000..29b697f --- /dev/null +++ b/pkg/sideload/view/src/layouts/RootLayout.tsx @@ -0,0 +1,11 @@ +import Navbar from "./shared/Navbar"; + +export default function RootLayout(props: any) { + return ( +
+ + +
{props.children}
+
+ ); +} diff --git a/pkg/sideload/view/src/layouts/main.vue b/pkg/sideload/view/src/layouts/main.vue deleted file mode 100644 index 88260be..0000000 --- a/pkg/sideload/view/src/layouts/main.vue +++ /dev/null @@ -1,60 +0,0 @@ - - - - - diff --git a/pkg/sideload/view/src/layouts/shared/Navbar.tsx b/pkg/sideload/view/src/layouts/shared/Navbar.tsx new file mode 100644 index 0000000..4adbe89 --- /dev/null +++ b/pkg/sideload/view/src/layouts/shared/Navbar.tsx @@ -0,0 +1,62 @@ +import { For } from "solid-js"; + +interface MenuItem { + label: string; + href: string; +} + +export default function Navbar() { + const nav: MenuItem[] = [{ label: "Dashboard", href: "/" }]; + + return ( + + ); +} diff --git a/pkg/sideload/view/src/main.ts b/pkg/sideload/view/src/main.ts deleted file mode 100644 index d8a2907..0000000 --- a/pkg/sideload/view/src/main.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "./assets/main.css" - -import "virtual:uno.css" - -import { createApp } from "vue" -import { createPinia } from "pinia" - -import root from "./root.vue" -import router from "./router" - -const app = createApp(root) - -app.use(createPinia()) -app.use(router) - -app.mount("#app") diff --git a/pkg/sideload/view/src/pages/dashboard.tsx b/pkg/sideload/view/src/pages/dashboard.tsx new file mode 100644 index 0000000..0f39e8e --- /dev/null +++ b/pkg/sideload/view/src/pages/dashboard.tsx @@ -0,0 +1,10 @@ +export default function Dashboard() { + return ( +
+
+

Hold on

+

Our brand new sideload administration panel is still in progress. For now, you can use sideload api and roadsign cli.

+
+
+ ) +} \ No newline at end of file diff --git a/pkg/sideload/view/src/root.vue b/pkg/sideload/view/src/root.vue deleted file mode 100644 index ad671c5..0000000 --- a/pkg/sideload/view/src/root.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/pkg/sideload/view/src/router/index.ts b/pkg/sideload/view/src/router/index.ts deleted file mode 100644 index a58c1aa..0000000 --- a/pkg/sideload/view/src/router/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createRouter, createWebHistory } from "vue-router" - -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [ - { - path: "/", - name: "layouts.main", - component: () => import("@/layouts/main.vue"), - children: [ - { - path: "/", - name: "dashboard", - component: () => import("@/views/dashboard.vue") - }, - ] - }, - ] -}) - -export default router diff --git a/pkg/sideload/view/src/views/dashboard.vue b/pkg/sideload/view/src/views/dashboard.vue deleted file mode 100644 index 5ed9d3d..0000000 --- a/pkg/sideload/view/src/views/dashboard.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - \ No newline at end of file diff --git a/pkg/sideload/view/env.d.ts b/pkg/sideload/view/src/vite-env.d.ts similarity index 100% rename from pkg/sideload/view/env.d.ts rename to pkg/sideload/view/src/vite-env.d.ts diff --git a/pkg/sideload/view/tailwind.config.js b/pkg/sideload/view/tailwind.config.js new file mode 100644 index 0000000..4ddcaa7 --- /dev/null +++ b/pkg/sideload/view/tailwind.config.js @@ -0,0 +1,44 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./src/**/*.{js,jsx,ts,tsx}"], + theme: { + extend: {}, + }, + daisyui: { + themes: [ + { + light: { + ...require("daisyui/src/theming/themes")["light"], + primary: "#4750a3", + secondary: "#93c5fd", + accent: "#0f766e", + info: "#67e8f9", + success: "#15803d", + warning: "#f97316", + error: "#dc2626", + "--rounded-box": "0", + "--rounded-btn": "0", + "--rounded-badge": "0", + "--tab-radius": "0", + }, + }, + { + dark: { + ...require("daisyui/src/theming/themes")["dark"], + primary: "#4750a3", + secondary: "#93c5fd", + accent: "#0f766e", + info: "#67e8f9", + success: "#15803d", + warning: "#f97316", + error: "#dc2626", + "--rounded-box": "0", + "--rounded-btn": "0", + "--rounded-badge": "0", + "--tab-radius": "0", + }, + }, + ], + }, + plugins: [require("daisyui")], +}; diff --git a/pkg/sideload/view/tsconfig.app.json b/pkg/sideload/view/tsconfig.app.json deleted file mode 100644 index 491e093..0000000 --- a/pkg/sideload/view/tsconfig.app.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], - "exclude": ["src/**/__tests__/*"], - "compilerOptions": { - "composite": true, - "noEmit": true, - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} diff --git a/pkg/sideload/view/tsconfig.json b/pkg/sideload/view/tsconfig.json index 66b5e57..3999958 100644 --- a/pkg/sideload/view/tsconfig.json +++ b/pkg/sideload/view/tsconfig.json @@ -1,11 +1,26 @@ { - "files": [], - "references": [ - { - "path": "./tsconfig.node.json" - }, - { - "path": "./tsconfig.app.json" - } - ] + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/pkg/sideload/view/tsconfig.node.json b/pkg/sideload/view/tsconfig.node.json index 46cf2e1..42872c5 100644 --- a/pkg/sideload/view/tsconfig.node.json +++ b/pkg/sideload/view/tsconfig.node.json @@ -1,17 +1,10 @@ { - "extends": "@tsconfig/node18/tsconfig.json", - "include": [ - "vite.config.*", - "vitest.config.*", - "cypress.config.*", - "nightwatch.conf.*", - "playwright.config.*" - ], "compilerOptions": { "composite": true, - "noEmit": true, + "skipLibCheck": true, "module": "ESNext", - "moduleResolution": "Bundler", - "types": ["node"] - } + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] } diff --git a/pkg/sideload/view/unocss.config.ts b/pkg/sideload/view/unocss.config.ts deleted file mode 100644 index 84a0950..0000000 --- a/pkg/sideload/view/unocss.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig, presetUno } from "unocss" - -export default defineConfig({ - presets: [presetUno({ preflight: false })] -}) \ No newline at end of file diff --git a/pkg/sideload/view/vite.config.ts b/pkg/sideload/view/vite.config.ts index ed77420..4095d9b 100644 --- a/pkg/sideload/view/vite.config.ts +++ b/pkg/sideload/view/vite.config.ts @@ -1,24 +1,6 @@ -import { fileURLToPath, URL } from "node:url" +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' -import { defineConfig } from "vite" -import vue from "@vitejs/plugin-vue" -import unocss from "unocss/vite" - -// https://vitejs.dev/config/ export default defineConfig({ - plugins: [ - vue(), - unocss() - ], - resolve: { - alias: { - "@": fileURLToPath(new URL("./src", import.meta.url)) - } - }, - server: { - proxy: { - "/webhooks": "http://127.0.0.1:81", - "/cgi": "http://127.0.0.1:81" - } - } + plugins: [solid()], }) diff --git a/pkg/sign/pm.go b/pkg/sign/pm.go deleted file mode 100644 index 7ca620d..0000000 --- a/pkg/sign/pm.go +++ /dev/null @@ -1,144 +0,0 @@ -package sign - -import ( - "fmt" - "github.com/samber/lo" - "os" - "os/exec" - "path/filepath" - "strings" - "time" -) - -type ProcessStatus = int8 - -const ( - ProcessCreated = ProcessStatus(iota) - ProcessStarting - ProcessStarted - ProcessExited - ProcessFailure -) - -type ProcessInstance struct { - ID string `json:"id" yaml:"id"` - Workdir string `json:"workdir" yaml:"workdir"` - Command []string `json:"command" yaml:"command"` - Environment []string `json:"environment" yaml:"environment"` - Prepares [][]string `json:"prepares" yaml:"prepares"` - Preheat bool `json:"preheat" yaml:"preheat"` - - Cmd *exec.Cmd `json:"-"` - Logger strings.Builder `json:"-"` - - Status ProcessStatus `json:"status"` -} - -func (v *ProcessInstance) BootProcess() error { - if v.Cmd != nil { - return nil - } - if err := v.PrepareProcess(); err != nil { - return err - } - if v.Cmd == nil { - return v.StartProcess() - } - if v.Cmd.Process == nil || v.Cmd.ProcessState == nil { - return v.StartProcess() - } - if v.Cmd.ProcessState.Exited() { - return v.StartProcess() - } else if v.Cmd.ProcessState.Exited() { - return fmt.Errorf("process already dead") - } - if v.Cmd.ProcessState.Exited() { - return fmt.Errorf("cannot start process") - } else { - return nil - } -} - -func (v *ProcessInstance) PrepareProcess() error { - for _, script := range v.Prepares { - if len(script) <= 0 { - continue - } - cmd := exec.Command(script[0], script[1:]...) - cmd.Dir = filepath.Join(v.Workdir) - if err := cmd.Run(); err != nil { - return err - } - } - return nil -} - -func (v *ProcessInstance) StartProcess() error { - if len(v.Command) <= 0 { - return fmt.Errorf("you need set the command for %s to enable process manager", v.ID) - } - - v.Cmd = exec.Command(v.Command[0], v.Command[1:]...) - v.Cmd.Dir = filepath.Join(v.Workdir) - v.Cmd.Env = append(v.Cmd.Env, v.Environment...) - v.Cmd.Stdout = &v.Logger - v.Cmd.Stderr = &v.Logger - - // Monitor - go func() { - for { - if v.Cmd.Process == nil || v.Cmd.ProcessState == nil { - v.Status = ProcessStarting - } else if !v.Cmd.ProcessState.Exited() { - v.Status = ProcessStarted - } else { - v.Status = lo.Ternary(v.Cmd.ProcessState.Success(), ProcessExited, ProcessFailure) - return - } - time.Sleep(100 * time.Millisecond) - } - }() - - return v.Cmd.Start() -} - -func (v *ProcessInstance) StopProcess() error { - if v.Cmd != nil && v.Cmd.Process != nil { - if err := v.Cmd.Process.Signal(os.Interrupt); err != nil { - v.Cmd.Process.Kill() - return err - } else { - v.Cmd = nil - } - } - - return nil -} - -func (v *ProcessInstance) GetLogs() string { - return v.Logger.String() -} - -func (v *RoadApp) PreheatProcesses(callbacks ...func(total int, success int)) { - var processes []*ProcessInstance - for _, site := range v.Sites { - for _, process := range site.Processes { - if process.Preheat { - processes = append(processes, process) - } - } - } - - success := 0 - for _, process := range processes { - if process.BootProcess() == nil { - success++ - } - } - - if len(callbacks) > 0 { - for _, callback := range callbacks { - callback(len(processes), success) - } - } -} diff --git a/pkg/sign/router.go b/pkg/sign/router.go deleted file mode 100644 index 06d903f..0000000 --- a/pkg/sign/router.go +++ /dev/null @@ -1,58 +0,0 @@ -package sign - -import ( - "code.smartsheep.studio/goatworks/roadsign/pkg/sign/transformers" - "errors" - "math/rand" - - "github.com/gofiber/fiber/v2" - "github.com/rs/zerolog/log" -) - -type RoadApp struct { - Sites []*SiteConfig `json:"sites"` -} - -func (v *RoadApp) Forward(ctx *fiber.Ctx, site *SiteConfig) error { - if len(site.Upstreams) == 0 { - return errors.New("invalid configuration") - } - - // Boot processes - for _, process := range site.Processes { - if err := process.BootProcess(); err != nil { - log.Warn().Err(err).Msgf("An error occurred when booting process (%s) for %s", process.ID, site.ID) - return fiber.ErrBadGateway - } - } - - // Do forward - idx := rand.Intn(len(site.Upstreams)) - upstream := site.Upstreams[idx] - - switch upstream.GetType() { - case UpstreamTypeHypertext: - return makeHypertextResponse(ctx, upstream) - case UpstreamTypeFile: - return makeFileResponse(ctx, upstream) - default: - return fiber.ErrBadGateway - } -} - -type RequestTransformerConfig = transformers.RequestTransformerConfig - -type SiteConfig struct { - ID string `json:"id"` - Rules []*RouterRule `json:"rules" yaml:"rules"` - Transformers []*RequestTransformerConfig `json:"transformers" yaml:"transformers"` - Upstreams []*UpstreamInstance `json:"upstreams" yaml:"upstreams"` - Processes []*ProcessInstance `json:"processes" yaml:"processes"` -} - -type RouterRule struct { - Host []string `json:"host" yaml:"host"` - Path []string `json:"path" yaml:"path"` - Queries map[string]string `json:"queries" yaml:"queries"` - Headers map[string][]string `json:"headers" yaml:"headers"` -} diff --git a/pkg/sign/upstream.go b/pkg/sign/upstream.go deleted file mode 100644 index e4a20d6..0000000 --- a/pkg/sign/upstream.go +++ /dev/null @@ -1,58 +0,0 @@ -package sign - -import ( - "fmt" - "net/url" - "strings" - - "github.com/gofiber/fiber/v2" - "github.com/samber/lo" -) - -const ( - UpstreamTypeFile = "file" - UpstreamTypeHypertext = "hypertext" - UpstreamTypeUnknown = "unknown" -) - -type UpstreamInstance struct { - ID string `json:"id" yaml:"id"` - URI string `json:"uri" yaml:"uri"` -} - -func (v *UpstreamInstance) GetType() string { - protocol := strings.SplitN(v.URI, "://", 2)[0] - switch protocol { - case "file", "files": - return UpstreamTypeFile - case "http", "https": - return UpstreamTypeHypertext - } - - return UpstreamTypeUnknown -} - -func (v *UpstreamInstance) GetRawURI() (string, url.Values) { - uri := strings.SplitN(v.URI, "://", 2)[1] - data := strings.SplitN(uri, "?", 2) - data = append(data, " ") // Make data array least have two element - qs, _ := url.ParseQuery(data[0]) - - return data[0], qs -} - -func (v *UpstreamInstance) MakeURI(ctx *fiber.Ctx) string { - var queries []string - for k, v := range ctx.Queries() { - parsed, _ := url.QueryUnescape(v) - value := url.QueryEscape(parsed) - queries = append(queries, fmt.Sprintf("%s=%s", k, value)) - } - - path := string(ctx.Request().URI().Path()) - hash := string(ctx.Request().URI().Hash()) - - return v.URI + path + - lo.Ternary(len(queries) > 0, "?"+strings.Join(queries, "&"), "") + - lo.Ternary(len(hash) > 0, "#"+hash, "") -} diff --git a/pkg/warden/executor.go b/pkg/warden/executor.go new file mode 100644 index 0000000..b49de91 --- /dev/null +++ b/pkg/warden/executor.go @@ -0,0 +1,120 @@ +package warden + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/samber/lo" +) + +var InstancePool []*AppInstance + +func GetFromPool(id string) *AppInstance { + val, ok := lo.Find(InstancePool, func(item *AppInstance) bool { + return item.Manifest.ID == id + }) + return lo.Ternary(ok, val, nil) +} + +func StartPool() []error { + var errors []error + for _, instance := range InstancePool { + if err := instance.Wake(); err != nil { + errors = append(errors, err) + } + } + return errors +} + +type AppStatus = int8 + +const ( + AppCreated = AppStatus(iota) + AppStarting + AppStarted + AppExited + AppFailure +) + +type AppInstance struct { + Manifest Application `json:"manifest"` + + Cmd *exec.Cmd `json:"-"` + Logger strings.Builder `json:"-"` + + Status AppStatus `json:"status"` +} + +func (v *AppInstance) Wake() error { + if v.Cmd != nil { + return nil + } + if v.Cmd == nil { + return v.Start() + } + if v.Cmd.Process == nil || v.Cmd.ProcessState == nil { + return v.Start() + } + if v.Cmd.ProcessState.Exited() { + return v.Start() + } else if v.Cmd.ProcessState.Exited() { + return fmt.Errorf("process already dead") + } + if v.Cmd.ProcessState.Exited() { + return fmt.Errorf("cannot start process") + } else { + return nil + } +} + +func (v *AppInstance) Start() error { + manifest := v.Manifest + + if len(manifest.Command) <= 0 { + return fmt.Errorf("you need set the command for %s to enable process manager", manifest.ID) + } + + v.Cmd = exec.Command(manifest.Command[0], manifest.Command[1:]...) + v.Cmd.Dir = filepath.Join(manifest.Workdir) + v.Cmd.Env = append(v.Cmd.Env, manifest.Environment...) + v.Cmd.Stdout = &v.Logger + v.Cmd.Stderr = &v.Logger + + // Monitor + go func() { + for { + if v.Cmd.Process == nil || v.Cmd.ProcessState == nil { + v.Status = AppStarting + } else if !v.Cmd.ProcessState.Exited() { + v.Status = AppStarted + } else { + v.Status = lo.Ternary(v.Cmd.ProcessState.Success(), AppExited, AppFailure) + return + } + time.Sleep(100 * time.Millisecond) + } + }() + + return v.Cmd.Start() +} + +func (v *AppInstance) Stop() error { + if v.Cmd != nil && v.Cmd.Process != nil { + if err := v.Cmd.Process.Signal(os.Interrupt); err != nil { + v.Cmd.Process.Kill() + return err + } else { + v.Cmd = nil + } + } + + return nil +} + +func (v *AppInstance) Logs() string { + return v.Logger.String() +} diff --git a/pkg/warden/manifest.go b/pkg/warden/manifest.go new file mode 100644 index 0000000..2f3e1a7 --- /dev/null +++ b/pkg/warden/manifest.go @@ -0,0 +1,8 @@ +package warden + +type Application struct { + ID string `json:"id" toml:"id"` + Workdir string `json:"workdir" toml:"workdir"` + Command []string `json:"command" toml:"command"` + Environment []string `json:"environment" toml:"environment"` +} diff --git a/settings.toml b/settings.toml new file mode 100644 index 0000000..f1f5fda --- /dev/null +++ b/settings.toml @@ -0,0 +1,35 @@ +[debug] +print_routes = false + +[hypertext] +sideload_ports = [":81"] +sideload_secured_ports = [] +ports = [":8000"] +secured_ports = [] + +[hypertext.certificate] +redirect = false +sideload_key = "./cert.key" +sideload_pem = "./cert.pem" +key = "./cert.key" +pem = "./cert.pem" + +[hypertext.limitation] +max_body_size = 549_755_813_888 # 512 GiB +max_qps = -1 + +[paths] +configs = "./config" + +[telemetry] +request_logging = true +capture_traces = true + +[performance] +traces_limit = 256 +network_timeout = 3_000 +prefork = false + +[security] +sideload_trusted_proxies = ["localhost"] +credential = "e81f43f32d934271af6322e5376f5f59" diff --git a/settings.yml b/settings.yml deleted file mode 100644 index e473310..0000000 --- a/settings.yml +++ /dev/null @@ -1,28 +0,0 @@ -debug: - print_routes: true -hypertext: - sideload_ports: - - :81 - sideload_secured_ports: [ ] - certificate: - redirect: false - sideload_key: ./cert.key - sideload_pem: ./cert.pem - key: ./cert.key - pem: ./cert.pem - limitation: - max_body_size: 536870912 - max_qps: -1 - ports: - - :8000 - secured_ports: [ ] -paths: - configs: ./config -performance: - request_logging: true - network_timeout: 3000 - prefork: false -security: - sideload_trusted_proxies: - - localhost - credential: e81f43f32d934271af6322e5376f5f59 diff --git a/test/data/.gitignore b/test/data/.gitignore index 29e9b8d..cf5ab73 100644 --- a/test/data/.gitignore +++ b/test/data/.gitignore @@ -1,3 +1 @@ -/ssr -/spa -/congress \ No newline at end of file +/warden \ No newline at end of file diff --git a/test/data/sse/index.html b/test/data/sse/index.html new file mode 100644 index 0000000..165148a --- /dev/null +++ b/test/data/sse/index.html @@ -0,0 +1,27 @@ + + + + + + + SSE Example + + +

Server-Sent Events Example

+
+ + + + diff --git a/test/data/sse/server.py b/test/data/sse/server.py new file mode 100644 index 0000000..429ea6f --- /dev/null +++ b/test/data/sse/server.py @@ -0,0 +1,28 @@ +import time + +from flask import Flask, render_template, Response + +app = Flask(__name__, template_folder=".") + + +# Generator function to simulate real-time updates +def event_stream(): + count = 0 + while True: + time.sleep(1) + count += 1 + yield f"data: {count}\n\n" + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/sse') +def sse(): + return Response(event_stream(), content_type='text/event-stream') + + +if __name__ == '__main__': + app.run(debug=True, threaded=True) diff --git a/test/data/websocket/index.html b/test/data/websocket/index.html new file mode 100644 index 0000000..1aa1d95 --- /dev/null +++ b/test/data/websocket/index.html @@ -0,0 +1,57 @@ + + + + + + WebSocket Durability Test + + +

WebSocket Client

+

+ This client will send a message every 500ms, or you can send message + manually. +

+
+ + + + + + diff --git a/test/data/websocket/server.py b/test/data/websocket/server.py new file mode 100644 index 0000000..44b6153 --- /dev/null +++ b/test/data/websocket/server.py @@ -0,0 +1,29 @@ +import asyncio +import websockets + +async def handle_websocket(websocket, path): + # This function will be called whenever a new WebSocket connection is established + + # Send a welcome message to the client + await websocket.send("Welcome to the WebSocket server!") + + try: + # Enter the main loop to handle incoming messages + async for message in websocket: + # Print the received message + print(f"Received message: {message}") + + # Send a response back to the client + response = f"Server received: {message}" + await websocket.send(response) + except websockets.exceptions.ConnectionClosedError: + print("Connection closed by the client.") + +# Create the WebSocket server +start_server = websockets.serve(handle_websocket, "localhost", 8765) + +print("WebSocket server started at ws://localhost:8765") + +# Run the server indefinitely +asyncio.get_event_loop().run_until_complete(start_server) +asyncio.get_event_loop().run_forever() diff --git a/test/roadsign-spa/config/example.toml b/test/roadsign-spa/config/example.toml new file mode 100644 index 0000000..5fedd0c --- /dev/null +++ b/test/roadsign-spa/config/example.toml @@ -0,0 +1,9 @@ +id = "example" + +[[locations]] +id = "example-location" +host = ["localhost:8000"] +path = ["/"] +[[locations.destinations]] +id = "example-destination" +uri = "files://../data/spa?fallback=index.html" \ No newline at end of file diff --git a/test/roadsign-spa/config/example.yaml b/test/roadsign-spa/config/example.yaml deleted file mode 100644 index f94fd66..0000000 --- a/test/roadsign-spa/config/example.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Example Site -rules: - - host: ["localhost:8000"] - path: ["/"] -upstreams: - - id: example - name: Benchmarking Data - uri: files://../data/spa?fallback=index.html diff --git a/test/roadsign-spa/settings.toml b/test/roadsign-spa/settings.toml new file mode 100644 index 0000000..c6ccfb3 --- /dev/null +++ b/test/roadsign-spa/settings.toml @@ -0,0 +1,31 @@ +[debug] +print_routes = true + +[hypertext] +sideload_ports = [":81"] +sideload_secured_ports = [] +ports = [":8000"] +secured_ports = [] + +[hypertext.certificate] +redirect = false +sideload_key = "./cert.key" +sideload_pem = "./cert.pem" +key = "./cert.key" +pem = "./cert.pem" + +[hypertext.limitation] +max_body_size = 549_755_813_888 # 512 GiB +max_qps = -1 + +[paths] +configs = "./config" + +[performance] +request_logging = true +network_timeout = 3_000 +prefork = false + +[security] +sideload_trusted_proxies = ["localhost"] +credential = "e81f43f32d934271af6322e5376f5f59" diff --git a/test/roadsign-spa/settings.yml b/test/roadsign-spa/settings.yml deleted file mode 100644 index 2546065..0000000 --- a/test/roadsign-spa/settings.yml +++ /dev/null @@ -1,26 +0,0 @@ -debug: - print_routes: false -hypertext: - sideload_ports: [":81"] - sideload_secured_ports: [] - certificate: - sideload_key: ./cert.key - sideload_pem: ./cert.pem - key: ./cert.key - pem: ./cert.pem - limitation: - max_body_size: 536870912 - max_qps: -1 - ports: - - :8000 - secured_ports: [] -paths: - configs: ./config -performance: - request_logging: false - network_timeout: 3000 - prefork: false -security: - sideload_trusted_proxies: - - localhost - credential: e81f43f32d934271af6322e5376f5f59 diff --git a/test/roadsign-ssr/config/example.toml b/test/roadsign-ssr/config/example.toml new file mode 100644 index 0000000..3300ab2 --- /dev/null +++ b/test/roadsign-ssr/config/example.toml @@ -0,0 +1,15 @@ +id = "example-region" + +[[locations]] +id = "example-warden" +host = ["localhost:8000"] +path = ["/"] +[[locations.destinations]] +id = "example-warden-destination" +uri = "http://localhost:4321" + +[[applications]] +id = "example-warden-app" +workdir = "../data/warden" +command = ["node", "dist/server/entry.mjs"] +environment = ["PUBLIC_CMS=https://smartsheep.studio"] \ No newline at end of file diff --git a/test/roadsign-ssr/config/example.yaml b/test/roadsign-ssr/config/example.yaml deleted file mode 100644 index b061b3f..0000000 --- a/test/roadsign-ssr/config/example.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: Example Site -rules: - - host: ["localhost:8000"] - path: ["/"] -upstreams: - - id: example - name: Benchmarking Data - uri: http://localhost:3000 -processes: - - id: nuxt-ssr - workdir: ../data/ssr - command: ["node", ".output/server/index.mjs"] diff --git a/test/roadsign-ssr/settings.toml b/test/roadsign-ssr/settings.toml new file mode 100644 index 0000000..c6ccfb3 --- /dev/null +++ b/test/roadsign-ssr/settings.toml @@ -0,0 +1,31 @@ +[debug] +print_routes = true + +[hypertext] +sideload_ports = [":81"] +sideload_secured_ports = [] +ports = [":8000"] +secured_ports = [] + +[hypertext.certificate] +redirect = false +sideload_key = "./cert.key" +sideload_pem = "./cert.pem" +key = "./cert.key" +pem = "./cert.pem" + +[hypertext.limitation] +max_body_size = 549_755_813_888 # 512 GiB +max_qps = -1 + +[paths] +configs = "./config" + +[performance] +request_logging = true +network_timeout = 3_000 +prefork = false + +[security] +sideload_trusted_proxies = ["localhost"] +credential = "e81f43f32d934271af6322e5376f5f59" diff --git a/test/roadsign-ssr/settings.yml b/test/roadsign-ssr/settings.yml deleted file mode 100644 index 2546065..0000000 --- a/test/roadsign-ssr/settings.yml +++ /dev/null @@ -1,26 +0,0 @@ -debug: - print_routes: false -hypertext: - sideload_ports: [":81"] - sideload_secured_ports: [] - certificate: - sideload_key: ./cert.key - sideload_pem: ./cert.pem - key: ./cert.key - pem: ./cert.pem - limitation: - max_body_size: 536870912 - max_qps: -1 - ports: - - :8000 - secured_ports: [] -paths: - configs: ./config -performance: - request_logging: false - network_timeout: 3000 - prefork: false -security: - sideload_trusted_proxies: - - localhost - credential: e81f43f32d934271af6322e5376f5f59 diff --git a/test/roadsign-with-prefork/config/example.toml b/test/roadsign-with-prefork/config/example.toml new file mode 100644 index 0000000..5fedd0c --- /dev/null +++ b/test/roadsign-with-prefork/config/example.toml @@ -0,0 +1,9 @@ +id = "example" + +[[locations]] +id = "example-location" +host = ["localhost:8000"] +path = ["/"] +[[locations.destinations]] +id = "example-destination" +uri = "files://../data/spa?fallback=index.html" \ No newline at end of file diff --git a/test/roadsign-with-prefork/config/example.yaml b/test/roadsign-with-prefork/config/example.yaml deleted file mode 100644 index 2a46d7d..0000000 --- a/test/roadsign-with-prefork/config/example.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Example Site -rules: - - host: ["localhost:8000"] - path: ["/"] -upstreams: - - id: example - name: Benchmarking Data - uri: files://../data diff --git a/test/roadsign-with-prefork/settings.toml b/test/roadsign-with-prefork/settings.toml new file mode 100644 index 0000000..f61f31d --- /dev/null +++ b/test/roadsign-with-prefork/settings.toml @@ -0,0 +1,31 @@ +[debug] +print_routes = true + +[hypertext] +sideload_ports = [":81"] +sideload_secured_ports = [] +ports = [":8000"] +secured_ports = [] + +[hypertext.certificate] +redirect = false +sideload_key = "./cert.key" +sideload_pem = "./cert.pem" +key = "./cert.key" +pem = "./cert.pem" + +[hypertext.limitation] +max_body_size = 549_755_813_888 # 512 GiB +max_qps = -1 + +[paths] +configs = "./config" + +[performance] +request_logging = true +network_timeout = 3_000 +prefork = true + +[security] +sideload_trusted_proxies = ["localhost"] +credential = "e81f43f32d934271af6322e5376f5f59" diff --git a/test/roadsign-with-prefork/settings.yml b/test/roadsign-with-prefork/settings.yml deleted file mode 100644 index 2dec20e..0000000 --- a/test/roadsign-with-prefork/settings.yml +++ /dev/null @@ -1,26 +0,0 @@ -debug: - print_routes: false -hypertext: - sideload_ports: [":81"] - sideload_secured_ports: [] - certificate: - sideload_key: ./cert.key - sideload_pem: ./cert.pem - key: ./cert.key - pem: ./cert.pem - limitation: - max_body_size: 536870912 - max_qps: -1 - ports: - - :8000 - secured_ports: [] -paths: - configs: ./config -performance: - request_logging: false - network_timeout: 3000 - prefork: true -security: - sideload_trusted_proxies: - - localhost - credential: e81f43f32d934271af6322e5376f5f59 diff --git a/test/roadsign/settings.toml b/test/roadsign/settings.toml new file mode 100644 index 0000000..c6ccfb3 --- /dev/null +++ b/test/roadsign/settings.toml @@ -0,0 +1,31 @@ +[debug] +print_routes = true + +[hypertext] +sideload_ports = [":81"] +sideload_secured_ports = [] +ports = [":8000"] +secured_ports = [] + +[hypertext.certificate] +redirect = false +sideload_key = "./cert.key" +sideload_pem = "./cert.pem" +key = "./cert.key" +pem = "./cert.pem" + +[hypertext.limitation] +max_body_size = 549_755_813_888 # 512 GiB +max_qps = -1 + +[paths] +configs = "./config" + +[performance] +request_logging = true +network_timeout = 3_000 +prefork = false + +[security] +sideload_trusted_proxies = ["localhost"] +credential = "e81f43f32d934271af6322e5376f5f59" diff --git a/test/roadsign/settings.yml b/test/roadsign/settings.yml deleted file mode 100644 index 2546065..0000000 --- a/test/roadsign/settings.yml +++ /dev/null @@ -1,26 +0,0 @@ -debug: - print_routes: false -hypertext: - sideload_ports: [":81"] - sideload_secured_ports: [] - certificate: - sideload_key: ./cert.key - sideload_pem: ./cert.pem - key: ./cert.key - pem: ./cert.pem - limitation: - max_body_size: 536870912 - max_qps: -1 - ports: - - :8000 - secured_ports: [] -paths: - configs: ./config -performance: - request_logging: false - network_timeout: 3000 - prefork: false -security: - sideload_trusted_proxies: - - localhost - credential: e81f43f32d934271af6322e5376f5f59