🎉 Start developing!
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +1,6 @@ | |||||||
| /config | /config | ||||||
| /letsencrypt | /letsencrypt | ||||||
|  |  | ||||||
|  | # Added by cargo | ||||||
|  |  | ||||||
|  | /target | ||||||
|   | |||||||
							
								
								
									
										2005
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2005
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | [package] | ||||||
|  | name = "roadsign" | ||||||
|  | version = "0.1.0" | ||||||
|  | edition = "2021" | ||||||
|  |  | ||||||
|  | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||||
|  |  | ||||||
|  | [dependencies] | ||||||
|  | config = { version = "0.13.4", features = ["toml"] } | ||||||
|  | poem = { version = "2.0.0", features = ["tokio-metrics"] } | ||||||
|  | poem-openapi = "4.0.0" | ||||||
|  | serde = "1.0.195" | ||||||
|  | serde_json = "1.0.111" | ||||||
|  | tokio = { version = "1.35.1", features = ["rt-multi-thread", "macros", "time"] } | ||||||
|  | tracing-subscriber = "0.3.18" | ||||||
							
								
								
									
										4
									
								
								Settings.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Settings.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | [listen] | ||||||
|  | proxies = "0.0.0.0:80" | ||||||
|  | proxies_tls = "0.0.0.0:443" | ||||||
|  | sideload = "0.0.0.0:81" | ||||||
							
								
								
									
										58
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,58 +0,0 @@ | |||||||
| 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/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 |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| 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/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect |  | ||||||
| 	golang.org/x/sync v0.5.0 // indirect |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| require ( |  | ||||||
| 	github.com/andybalholm/brotli v1.0.5 // 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 |  | ||||||
| 	github.com/magiconair/properties v1.8.7 // indirect |  | ||||||
| 	github.com/mattn/go-colorable v0.1.13 // indirect |  | ||||||
| 	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/philhofer/fwd v1.1.2 // indirect |  | ||||||
| 	github.com/rivo/uniseg v0.2.0 // 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/cast v1.5.1 // indirect |  | ||||||
| 	github.com/spf13/pflag v1.0.5 // indirect |  | ||||||
| 	github.com/subosito/gotenv v1.6.0 // indirect |  | ||||||
| 	github.com/tinylib/msgp v1.1.8 // indirect |  | ||||||
| 	github.com/valyala/bytebufferpool v1.0.0 // indirect |  | ||||||
| 	github.com/valyala/tcplisten v1.0.0 // indirect |  | ||||||
| 	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 |  | ||||||
| 	gopkg.in/ini.v1 v1.67.0 // indirect |  | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 |  | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect |  | ||||||
| ) |  | ||||||
							
								
								
									
										577
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										577
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,577 +0,0 @@ | |||||||
| 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/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= |  | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |  | ||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |  | ||||||
| github.com/davecgh/go-spew v1.1.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/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/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/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= |  | ||||||
| github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= |  | ||||||
| github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= |  | ||||||
| github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= |  | ||||||
| github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= |  | ||||||
| github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= |  | ||||||
| github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= |  | ||||||
| github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= |  | ||||||
| github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= |  | ||||||
| github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= |  | ||||||
| github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= |  | ||||||
| github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |  | ||||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= |  | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= |  | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/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/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/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= |  | ||||||
| github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= |  | ||||||
| github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= |  | ||||||
| github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= |  | ||||||
| github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= |  | ||||||
| github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= |  | ||||||
| github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= |  | ||||||
| github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= |  | ||||||
| github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= |  | ||||||
| github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= |  | ||||||
| github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= |  | ||||||
| github.com/saracen/fastzip v0.1.11 h1:NnExbTEJbya7148cov09BCxwfur9tQ5BQ1QyQH6XleA= |  | ||||||
| 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/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/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= |  | ||||||
| github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= |  | ||||||
| github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= |  | ||||||
| github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= |  | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |  | ||||||
| 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= |  | ||||||
| github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= |  | ||||||
| github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= |  | ||||||
| github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= |  | ||||||
| github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= |  | ||||||
| github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= |  | ||||||
| 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/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/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= |  | ||||||
| golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |  | ||||||
| golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |  | ||||||
| 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/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/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= |  | ||||||
| @@ -1,89 +0,0 @@ | |||||||
| package conn |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
|  |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| 	"github.com/samber/lo" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| 	"github.com/urfave/cli/v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var CliCommands = []*cli.Command{ |  | ||||||
| 	{ |  | ||||||
| 		Name:        "list", |  | ||||||
| 		Aliases:     []string{"ls"}, |  | ||||||
| 		Description: "List all connected remote server", |  | ||||||
| 		Action: func(ctx *cli.Context) error { |  | ||||||
| 			var servers []CliConnection |  | ||||||
| 			raw, _ := json.Marshal(viper.Get("servers")) |  | ||||||
| 			_ = json.Unmarshal(raw, &servers) |  | ||||||
|  |  | ||||||
| 			log.Info().Msgf("There are %d server(s) connected in total.", len(servers)) |  | ||||||
| 			for idx, server := range servers { |  | ||||||
| 				log.Info().Msgf("%d) %s: %s", idx+1, server.ID, server.Url) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return nil |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		Name:        "connect", |  | ||||||
| 		Aliases:     []string{"add"}, |  | ||||||
| 		Description: "Connect and save configuration of remote server", |  | ||||||
| 		ArgsUsage:   "<id> <server url> <credential>", |  | ||||||
| 		Action: func(ctx *cli.Context) error { |  | ||||||
| 			if ctx.Args().Len() < 3 { |  | ||||||
| 				return fmt.Errorf("must have three arguments: <id> <server url> <credential>") |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			c := CliConnection{ |  | ||||||
| 				ID:         ctx.Args().Get(0), |  | ||||||
| 				Url:        ctx.Args().Get(1), |  | ||||||
| 				Credential: ctx.Args().Get(2), |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if err := c.CheckConnectivity(); err != nil { |  | ||||||
| 				return fmt.Errorf("couldn't connect server: %s", err.Error()) |  | ||||||
| 			} else { |  | ||||||
| 				var servers []CliConnection |  | ||||||
| 				raw, _ := json.Marshal(viper.Get("servers")) |  | ||||||
| 				_ = json.Unmarshal(raw, &servers) |  | ||||||
| 				viper.Set("servers", append(servers, c)) |  | ||||||
|  |  | ||||||
| 				if err := viper.WriteConfig(); err != nil { |  | ||||||
| 					return err |  | ||||||
| 				} else { |  | ||||||
| 					log.Info().Msg("Successfully connected a new remote server, enter \"rds ls\" to get more info.") |  | ||||||
| 					return nil |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		Name:        "disconnect", |  | ||||||
| 		Aliases:     []string{"remove"}, |  | ||||||
| 		Description: "Remove a remote server configuration", |  | ||||||
| 		ArgsUsage:   "<id>", |  | ||||||
| 		Action: func(ctx *cli.Context) error { |  | ||||||
| 			if ctx.Args().Len() < 1 { |  | ||||||
| 				return fmt.Errorf("must have more one arguments: <server url>") |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			var servers []CliConnection |  | ||||||
| 			raw, _ := json.Marshal(viper.Get("servers")) |  | ||||||
| 			_ = json.Unmarshal(raw, &servers) |  | ||||||
| 			viper.Set("servers", lo.Filter(servers, func(item CliConnection, idx int) bool { |  | ||||||
| 				return item.ID != ctx.Args().Get(0) |  | ||||||
| 			})) |  | ||||||
|  |  | ||||||
| 			if err := viper.WriteConfig(); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} else { |  | ||||||
| 				log.Info().Msg("Successfully disconnected a remote server, enter \"rds ls\" to get more info.") |  | ||||||
| 				return nil |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| } |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| package conn |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type CliConnection struct { |  | ||||||
| 	ID         string `json:"id"` |  | ||||||
| 	Url        string `json:"url"` |  | ||||||
| 	Credential string `json:"credential"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (v CliConnection) CheckConnectivity() error { |  | ||||||
| 	client := fiber.Get(v.Url + "/cgi/connectivity") |  | ||||||
| 	client.BasicAuth("RoadSign CLI", v.Credential) |  | ||||||
|  |  | ||||||
| 	if status, data, err := client.Bytes(); len(err) > 0 { |  | ||||||
| 		return fmt.Errorf("couldn't connect to server: %q", err) |  | ||||||
| 	} else if status != 200 { |  | ||||||
| 		return fmt.Errorf("server rejected request, may cause by invalid credential") |  | ||||||
| 	} else { |  | ||||||
| 		var resp fiber.Map |  | ||||||
| 		if err := json.Unmarshal(data, &resp); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} else if resp["server"] != "RoadSign" { |  | ||||||
| 			return fmt.Errorf("remote server isn't roadsign") |  | ||||||
| 		} else if resp["version"] != roadsign.AppVersion { |  | ||||||
| 			if strings.Contains(roadsign.AppVersion, "#") { |  | ||||||
| 				return fmt.Errorf("remote server version mismatch client version, update or downgrade client required") |  | ||||||
| 			} else { |  | ||||||
| 				log.Warn().Msg("RoadSign CLI didn't complied with vcs information, compatibility was disabled. To enable it, reinstall cli with -buildvcs flag.") |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| package conn |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/samber/lo" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func GetConnection(id string) (CliConnection, bool) { |  | ||||||
| 	var servers []CliConnection |  | ||||||
| 	raw, _ := json.Marshal(viper.Get("servers")) |  | ||||||
| 	_ = json.Unmarshal(raw, &servers) |  | ||||||
| 	return lo.Find(servers, func(item CliConnection) bool { |  | ||||||
| 		return item.ID == id |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @@ -1,101 +0,0 @@ | |||||||
| 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" |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| 	"github.com/urfave/cli/v2" |  | ||||||
| 	"gopkg.in/yaml.v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var DeployCommands = []*cli.Command{ |  | ||||||
| 	{ |  | ||||||
| 		Name:      "deploy", |  | ||||||
| 		Aliases:   []string{"dp"}, |  | ||||||
| 		ArgsUsage: "<server> <site> <upstream> [path]", |  | ||||||
| 		Action: func(ctx *cli.Context) error { |  | ||||||
| 			if ctx.Args().Len() < 4 { |  | ||||||
| 				return fmt.Errorf("must have four arguments: <server> <site> <upstream> <path>") |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if !strings.HasSuffix(ctx.Args().Get(3), ".zip") { |  | ||||||
| 				return fmt.Errorf("input file must be a zip file and ends with .zip") |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			server, ok := conn.GetConnection(ctx.Args().Get(0)) |  | ||||||
| 			if !ok { |  | ||||||
| 				return fmt.Errorf("server was not found, use \"rds connect\" add one first") |  | ||||||
| 			} else if err := server.CheckConnectivity(); err != nil { |  | ||||||
| 				return fmt.Errorf("couldn't connect server: %s", err.Error()) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			// Send request |  | ||||||
| 			log.Info().Msg("Now publishing to remote server...") |  | ||||||
|  |  | ||||||
| 			url := fmt.Sprintf("/webhooks/publish/%s/%s?mimetype=%s", ctx.Args().Get(1), ctx.Args().Get(2), "application/zip") |  | ||||||
| 			client := fiber.Put(server.Url+url). |  | ||||||
| 				SendFile(ctx.Args().Get(3), "attachments"). |  | ||||||
| 				MultipartForm(nil). |  | ||||||
| 				BasicAuth("RoadSign CLI", server.Credential) |  | ||||||
|  |  | ||||||
| 			if status, data, err := client.Bytes(); len(err) > 0 { |  | ||||||
| 				return fmt.Errorf("failed to publish to remote: %q", err) |  | ||||||
| 			} else if status != 200 { |  | ||||||
| 				return fmt.Errorf("server rejected request, status code %d, response %s", status, string(data)) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			log.Info().Msg("Well done! Your site is successfully published! 🎉") |  | ||||||
|  |  | ||||||
| 			return nil |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		Name:      "sync", |  | ||||||
| 		Aliases:   []string{"sc"}, |  | ||||||
| 		ArgsUsage: "<server> <site> <configuration path>", |  | ||||||
| 		Action: func(ctx *cli.Context) error { |  | ||||||
| 			if ctx.Args().Len() < 3 { |  | ||||||
| 				return fmt.Errorf("must have three arguments: <server> <site> <configuration path>") |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			server, ok := conn.GetConnection(ctx.Args().Get(0)) |  | ||||||
| 			if !ok { |  | ||||||
| 				return fmt.Errorf("server was not found, use \"rds connect\" add one first") |  | ||||||
| 			} else if err := server.CheckConnectivity(); err != nil { |  | ||||||
| 				return fmt.Errorf("couldn't connect server: %s", err.Error()) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			var site sign.SiteConfig |  | ||||||
| 			if file, err := os.Open(ctx.Args().Get(2)); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} else { |  | ||||||
| 				raw, _ := io.ReadAll(file) |  | ||||||
| 				yaml.Unmarshal(raw, &site) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			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). |  | ||||||
| 				BasicAuth("RoadSign CLI", server.Credential) |  | ||||||
|  |  | ||||||
| 			if status, data, err := client.Bytes(); len(err) > 0 { |  | ||||||
| 				return fmt.Errorf("failed to sync to remote: %q", err) |  | ||||||
| 			} else if status != 200 { |  | ||||||
| 				return fmt.Errorf("server rejected request, status code %d, response %s", status, string(data)) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			log.Info().Msg("Well done! Your site configuration is up-to-date! 🎉") |  | ||||||
|  |  | ||||||
| 			return nil |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| } |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| 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" |  | ||||||
| 	"github.com/rs/zerolog" |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| 	"github.com/urfave/cli/v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix |  | ||||||
| 	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	// Configure settings |  | ||||||
| 	viper.AddConfigPath("$HOME") |  | ||||||
| 	viper.SetConfigName(".roadsignrc") |  | ||||||
| 	viper.SetConfigType("yaml") |  | ||||||
|  |  | ||||||
| 	// Load settings |  | ||||||
| 	if err := viper.ReadInConfig(); err != nil { |  | ||||||
| 		if _, ok := err.(viper.ConfigFileNotFoundError); ok { |  | ||||||
| 			viper.SafeWriteConfig() |  | ||||||
| 			viper.ReadInConfig() |  | ||||||
| 		} else { |  | ||||||
| 			log.Panic().Err(err).Msg("An error occurred when loading settings.") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Configure CLI |  | ||||||
| 	app := &cli.App{ |  | ||||||
| 		Name:     "RoadSign CLI", |  | ||||||
| 		Version:  roadsign.AppVersion, |  | ||||||
| 		Suggest:  true, |  | ||||||
| 		Commands: append(append([]*cli.Command{}, conn.CliCommands...), deploy.DeployCommands...), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Run CLI |  | ||||||
| 	if err := app.Run(os.Args); err != nil { |  | ||||||
| 		log.Fatal().Err(err).Msg("An error occurred when running cli.") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,86 +0,0 @@ | |||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"os" |  | ||||||
| 	"os/signal" |  | ||||||
| 	"strings" |  | ||||||
| 	"syscall" |  | ||||||
|  |  | ||||||
| 	roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" |  | ||||||
| 	"code.smartsheep.studio/goatworks/roadsign/pkg/hypertext" |  | ||||||
| 	"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" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix |  | ||||||
| 	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	// Configure settings |  | ||||||
| 	viper.AddConfigPath(".") |  | ||||||
| 	viper.AddConfigPath("..") |  | ||||||
| 	viper.SetConfigName("settings") |  | ||||||
| 	viper.SetConfigType("yaml") |  | ||||||
|  |  | ||||||
| 	// Load settings |  | ||||||
| 	if err := viper.ReadInConfig(); err != nil { |  | ||||||
| 		log.Panic().Err(err).Msg("An error occurred when loading settings.") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Present settings |  | ||||||
| 	if len(viper.GetString("security.credential")) <= 0 { |  | ||||||
| 		credential := strings.ReplaceAll(uuid.NewString(), "-", "") |  | ||||||
| 		viper.Set("security.credential", credential) |  | ||||||
| 		_ = viper.WriteConfig() |  | ||||||
|  |  | ||||||
| 		log.Warn().Msg("There isn't any api credential configured in settings.yml, auto generated a credential for api accessing.") |  | ||||||
| 		log.Warn().Msgf("RoadSign auto generated api credential is %s", credential) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Load & init sign |  | ||||||
| 	if err := sign.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.") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// 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 hypertext server |  | ||||||
| 	hypertext.RunServer( |  | ||||||
| 		hypertext.InitServer(), |  | ||||||
| 		viper.GetStringSlice("hypertext.ports"), |  | ||||||
| 		viper.GetStringSlice("hypertext.secured_ports"), |  | ||||||
| 		viper.GetString("hypertext.certificate.pem"), |  | ||||||
| 		viper.GetString("hypertext.certificate.key"), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	// Init sideload server |  | ||||||
| 	hypertext.RunServer( |  | ||||||
| 		sideload.InitSideload(), |  | ||||||
| 		viper.GetStringSlice("hypertext.sideload_ports"), |  | ||||||
| 		viper.GetStringSlice("hypertext.sideload_secured_ports"), |  | ||||||
| 		viper.GetString("hypertext.certificate.sideload_pem"), |  | ||||||
| 		viper.GetString("hypertext.certificate.sideload_key"), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	log.Info().Msgf("RoadSign v%s is started...", roadsign.AppVersion) |  | ||||||
|  |  | ||||||
| 	quit := make(chan os.Signal, 1) |  | ||||||
| 	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) |  | ||||||
| 	<-quit |  | ||||||
|  |  | ||||||
| 	log.Info().Msgf("RoadSign v%s is quitting...", roadsign.AppVersion) |  | ||||||
| } |  | ||||||
| @@ -1,111 +0,0 @@ | |||||||
| package hypertext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"regexp" |  | ||||||
|  |  | ||||||
| 	"code.smartsheep.studio/goatworks/roadsign/pkg/sign" |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/samber/lo" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func UseProxies(app *fiber.App) { |  | ||||||
| 	app.All("/*", func(ctx *fiber.Ctx) error { |  | ||||||
| 		host := ctx.Hostname() |  | ||||||
| 		path := ctx.Path() |  | ||||||
| 		queries := ctx.Queries() |  | ||||||
| 		headers := ctx.GetReqHeaders() |  | ||||||
|  |  | ||||||
| 		// Filtering sites |  | ||||||
| 		for _, site := range sign.App.Sites { |  | ||||||
| 			// Matching rules |  | ||||||
| 			for _, rule := range site.Rules { |  | ||||||
| 				if !lo.Contains(rule.Host, host) { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if !func() bool { |  | ||||||
| 					flag := false |  | ||||||
| 					for _, pattern := range rule.Path { |  | ||||||
| 						if ok, _ := regexp.MatchString(pattern, path); ok { |  | ||||||
| 							flag = true |  | ||||||
| 							break |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					return flag |  | ||||||
| 				}() { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// Filter query strings |  | ||||||
| 				flag := true |  | ||||||
| 				for rk, rv := range rule.Queries { |  | ||||||
| 					for ik, iv := range queries { |  | ||||||
| 						if rk != ik && rv != iv { |  | ||||||
| 							flag = false |  | ||||||
| 							break |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					if !flag { |  | ||||||
| 						break |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				if !flag { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// Filter headers |  | ||||||
| 				for rk, rv := range rule.Headers { |  | ||||||
| 					for ik, iv := range headers { |  | ||||||
| 						if rk == ik { |  | ||||||
| 							for _, ov := range iv { |  | ||||||
| 								if !lo.Contains(rv, ov) { |  | ||||||
| 									flag = false |  | ||||||
| 									break |  | ||||||
| 								} |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 						if !flag { |  | ||||||
| 							break |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					if !flag { |  | ||||||
| 						break |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				if !flag { |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// Passing all the rules means the site is what we are looking for. |  | ||||||
| 				// Let us respond to our client! |  | ||||||
| 				return makeResponse(ctx, site) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// There is no site available for this request. |  | ||||||
| 		// Just ignore it and give our client a not found status. |  | ||||||
| 		// Do not care about the user experience, we can do it in custom error handler. |  | ||||||
| 		return fiber.ErrNotFound |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func makeResponse(ctx *fiber.Ctx, site *sign.SiteConfig) error { |  | ||||||
| 	// Modify request |  | ||||||
| 	for _, transformer := range site.Transformers { |  | ||||||
| 		if err := transformer.TransformRequest(ctx); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Forward |  | ||||||
| 	err := sign.App.Forward(ctx, site) |  | ||||||
|  |  | ||||||
| 	// Modify response |  | ||||||
| 	for _, transformer := range site.Transformers { |  | ||||||
| 		if err := transformer.TransformResponse(ctx); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
| @@ -1,79 +0,0 @@ | |||||||
| package hypertext |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	jsoniter "github.com/json-iterator/go" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/gofiber/fiber/v2/middleware/limiter" |  | ||||||
| 	"github.com/gofiber/fiber/v2/middleware/logger" |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func InitServer() *fiber.App { |  | ||||||
| 	app := fiber.New(fiber.Config{ |  | ||||||
| 		AppName:               "RoadSign", |  | ||||||
| 		ServerHeader:          "RoadSign", |  | ||||||
| 		DisableStartupMessage: true, |  | ||||||
| 		EnableIPValidation:    true, |  | ||||||
| 		JSONDecoder:           jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal, |  | ||||||
| 		JSONEncoder:           jsoniter.ConfigCompatibleWithStandardLibrary.Marshal, |  | ||||||
| 		Prefork:               viper.GetBool("performance.prefork"), |  | ||||||
| 		BodyLimit:             viper.GetInt("hypertext.limitation.max_body_size"), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	if viper.GetBool("performance.request_logging") { |  | ||||||
| 		app.Use(logger.New(logger.Config{ |  | ||||||
| 			Output: log.Logger, |  | ||||||
| 			Format: "[Proxies] [${time}] ${status} - ${latency} ${method} ${path}\n", |  | ||||||
| 		})) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if viper.GetInt("hypertext.limitation.max_qps") > 0 { |  | ||||||
| 		app.Use(limiter.New(limiter.Config{ |  | ||||||
| 			Max:        viper.GetInt("hypertext.limitation.max_qps"), |  | ||||||
| 			Expiration: 1 * time.Second, |  | ||||||
| 		})) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	UseProxies(app) |  | ||||||
|  |  | ||||||
| 	return app |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RunServer(app *fiber.App, ports []string, securedPorts []string, pem string, key string) { |  | ||||||
| 	for _, port := range ports { |  | ||||||
| 		port := port |  | ||||||
| 		go func() { |  | ||||||
| 			if viper.GetBool("hypertext.certificate.redirect") { |  | ||||||
| 				redirector := fiber.New(fiber.Config{ |  | ||||||
| 					AppName:               "RoadSign", |  | ||||||
| 					ServerHeader:          "RoadSign", |  | ||||||
| 					DisableStartupMessage: true, |  | ||||||
| 					EnableIPValidation:    true, |  | ||||||
| 				}) |  | ||||||
| 				redirector.All("/", func(c *fiber.Ctx) error { |  | ||||||
| 					return c.Redirect(strings.ReplaceAll(string(c.Request().URI().FullURI()), "http", "https")) |  | ||||||
| 				}) |  | ||||||
| 				if err := redirector.Listen(port); err != nil { |  | ||||||
| 					log.Panic().Err(err).Msg("An error occurred when listening hypertext common ports.") |  | ||||||
| 				} |  | ||||||
| 			} else { |  | ||||||
| 				if err := app.Listen(port); err != nil { |  | ||||||
| 					log.Panic().Err(err).Msg("An error occurred when listening hypertext common ports.") |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, port := range securedPorts { |  | ||||||
| 		port := port |  | ||||||
| 		go func() { |  | ||||||
| 			if err := app.ListenTLS(port, pem, key); err != nil { |  | ||||||
| 				log.Panic().Err(err).Msg("An error occurred when listening hypertext tls ports.") |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										17
									
								
								pkg/meta.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								pkg/meta.go
									
									
									
									
									
								
							| @@ -1,17 +0,0 @@ | |||||||
| package roadsign |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"runtime/debug" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	if info, ok := debug.ReadBuildInfo(); ok { |  | ||||||
| 		for _, setting := range info.Settings { |  | ||||||
| 			if setting.Key == "vcs.revision" { |  | ||||||
| 				AppVersion += "#" + setting.Value |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var AppVersion = "1.2.1" |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| package sideload |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	roadsign "code.smartsheep.studio/goatworks/roadsign/pkg" |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func responseConnectivity(c *fiber.Ctx) error { |  | ||||||
| 	return c.Status(fiber.StatusOK).JSON(fiber.Map{ |  | ||||||
| 		"server":  "RoadSign", |  | ||||||
| 		"version": roadsign.AppVersion, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @@ -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()) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,85 +0,0 @@ | |||||||
| package sideload |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
|  |  | ||||||
| 	"code.smartsheep.studio/goatworks/roadsign/pkg/sign" |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/google/uuid" |  | ||||||
| 	"github.com/samber/lo" |  | ||||||
| 	"github.com/saracen/fastzip" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| 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 { |  | ||||||
| 		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 _, proc := range item.Processes { |  | ||||||
| 				if proc.ID == c.Params("slug") { |  | ||||||
| 					process = proc |  | ||||||
| 					workdir = proc.Workdir |  | ||||||
| 					break |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if upstream == nil && process == nil { |  | ||||||
| 		return fiber.ErrNotFound |  | ||||||
| 	} else if upstream != nil && upstream.GetType() != sign.UpstreamTypeFile { |  | ||||||
| 		return fiber.ErrUnprocessableEntity |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, process := range site.Processes { |  | ||||||
| 		process.StopProcess() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if c.Query("overwrite", "yes") == "yes" { |  | ||||||
| 		files, _ := filepath.Glob(filepath.Join(workdir, "*")) |  | ||||||
| 		for _, file := range files { |  | ||||||
| 			_ = os.Remove(file) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if form, err := c.MultipartForm(); err == nil { |  | ||||||
| 		files := form.File["attachments"] |  | ||||||
| 		for _, file := range files { |  | ||||||
| 			mimetype := lo.Ternary(len(c.Query("mimetype")) > 0, c.Query("mimetype"), file.Header["Content-Type"][0]) |  | ||||||
| 			switch mimetype { |  | ||||||
| 			case "application/zip": |  | ||||||
| 				dst := filepath.Join(os.TempDir(), uuid.NewString()+".zip") |  | ||||||
| 				if err := c.SaveFile(file, dst); err != nil { |  | ||||||
| 					return err |  | ||||||
| 				} else { |  | ||||||
| 					if ex, err := fastzip.NewExtractor(dst, workdir); err != nil { |  | ||||||
| 						return err |  | ||||||
| 					} else if err = ex.Extract(context.Background()); err != nil { |  | ||||||
| 						defer ex.Close() |  | ||||||
| 						return err |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			default: |  | ||||||
| 				dst := filepath.Join(workdir, file.Filename) |  | ||||||
| 				if err := c.SaveFile(file, dst); err != nil { |  | ||||||
| 					return err |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return c.SendStatus(fiber.StatusOK) |  | ||||||
| } |  | ||||||
| @@ -1,69 +0,0 @@ | |||||||
| package sideload |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"code.smartsheep.studio/goatworks/roadsign/pkg/sideload/view" |  | ||||||
| 	"fmt" |  | ||||||
| 	"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" |  | ||||||
| 	"github.com/gofiber/fiber/v2/middleware/basicauth" |  | ||||||
| 	"github.com/gofiber/fiber/v2/middleware/logger" |  | ||||||
| 	"github.com/rs/zerolog/log" |  | ||||||
| 	"github.com/spf13/viper" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func InitSideload() *fiber.App { |  | ||||||
| 	app := fiber.New(fiber.Config{ |  | ||||||
| 		AppName:               "RoadSign Sideload", |  | ||||||
| 		ServerHeader:          "RoadSign Sideload", |  | ||||||
| 		DisableStartupMessage: true, |  | ||||||
| 		EnableIPValidation:    true, |  | ||||||
| 		JSONDecoder:           jsoniter.ConfigCompatibleWithStandardLibrary.Unmarshal, |  | ||||||
| 		JSONEncoder:           jsoniter.ConfigCompatibleWithStandardLibrary.Marshal, |  | ||||||
| 		EnablePrintRoutes:     viper.GetBool("debug.print_routes"), |  | ||||||
| 		TrustedProxies:        viper.GetStringSlice("security.sideload_trusted_proxies"), |  | ||||||
| 		BodyLimit:             viper.GetInt("hypertext.limitation.max_body_size"), |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	if viper.GetBool("performance.request_logging") { |  | ||||||
| 		app.Use(logger.New(logger.Config{ |  | ||||||
| 			Output: log.Logger, |  | ||||||
| 			Format: "[Sideload] [${time}] ${status} - ${latency} ${method} ${path}\n", |  | ||||||
| 		})) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	app.Use(basicauth.New(basicauth.Config{ |  | ||||||
| 		Realm: fmt.Sprintf("RoadSign v%s", roadsign.AppVersion), |  | ||||||
| 		Authorizer: func(_, password string) bool { |  | ||||||
| 			return password == viper.GetString("security.credential") |  | ||||||
| 		}, |  | ||||||
| 	})) |  | ||||||
|  |  | ||||||
| 	app.Use("/", filesystem.New(filesystem.Config{ |  | ||||||
| 		Root:         http.FS(view.FS), |  | ||||||
| 		PathPrefix:   "dist", |  | ||||||
| 		Index:        "index.html", |  | ||||||
| 		NotFoundFile: "index.html", |  | ||||||
| 	})) |  | ||||||
|  |  | ||||||
| 	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) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	webhooks := app.Group("/webhooks").Name("WebHooks") |  | ||||||
| 	{ |  | ||||||
| 		webhooks.Put("/publish/:site/:slug", doPublish) |  | ||||||
| 		webhooks.Put("/sync/:slug", doSyncSite) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return app |  | ||||||
| } |  | ||||||
| @@ -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) |  | ||||||
| } |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| package sideload |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"code.smartsheep.studio/goatworks/roadsign/pkg/sign" |  | ||||||
| 	"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 |  | ||||||
| 	}) |  | ||||||
| 	processes := lo.FlatMap(sign.App.Sites, func(item *sign.SiteConfig, idx int) []*sign.ProcessInstance { |  | ||||||
| 		return item.Processes |  | ||||||
| 	}) |  | ||||||
| 	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 |  | ||||||
| 		}) |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	return c.JSON(fiber.Map{ |  | ||||||
| 		"sites":     len(sign.App.Sites), |  | ||||||
| 		"upstreams": len(upstreams), |  | ||||||
| 		"processes": len(processes), |  | ||||||
| 		"status":    len(unhealthy) == 0, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| /dist |  | ||||||
| /node_modules |  | ||||||
| /*.lock |  | ||||||
| @@ -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' |  | ||||||
|   } |  | ||||||
| } |  | ||||||
							
								
								
									
										30
									
								
								pkg/sideload/view/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								pkg/sideload/view/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,30 +0,0 @@ | |||||||
| # Logs |  | ||||||
| logs |  | ||||||
| *.log |  | ||||||
| npm-debug.log* |  | ||||||
| yarn-debug.log* |  | ||||||
| yarn-error.log* |  | ||||||
| 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 |  | ||||||
| *.suo |  | ||||||
| *.ntvs* |  | ||||||
| *.njsproj |  | ||||||
| *.sln |  | ||||||
| *.sw? |  | ||||||
|  |  | ||||||
| *.tsbuildinfo |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| { |  | ||||||
|   "$schema": "https://json.schemastore.org/prettierrc", |  | ||||||
|   "semi": false, |  | ||||||
|   "tabWidth": 2, |  | ||||||
|   "singleQuote": false, |  | ||||||
|   "printWidth": 120, |  | ||||||
|   "trailingComma": "none" |  | ||||||
| } |  | ||||||
							
								
								
									
										8
									
								
								pkg/sideload/view/.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								pkg/sideload/view/.vscode/extensions.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +0,0 @@ | |||||||
| { |  | ||||||
|   "recommendations": [ |  | ||||||
|     "Vue.volar", |  | ||||||
|     "Vue.vscode-typescript-vue-plugin", |  | ||||||
|     "dbaeumer.vscode-eslint", |  | ||||||
|     "esbenp.prettier-vscode" |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
| @@ -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 |  | ||||||
| ``` |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| package view |  | ||||||
|  |  | ||||||
| import "embed" |  | ||||||
|  |  | ||||||
| //go:embed all:dist |  | ||||||
| var FS embed.FS |  | ||||||
							
								
								
									
										1
									
								
								pkg/sideload/view/env.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								pkg/sideload/view/env.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | |||||||
| /// <reference types="vite/client" /> |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
|   <head> |  | ||||||
|     <meta charset="UTF-8"> |  | ||||||
|     <link rel="icon" href="/favicon.ico"> |  | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> |  | ||||||
|     <title>RoadSign</title> |  | ||||||
|   </head> |  | ||||||
|   <body> |  | ||||||
|     <div id="app"></div> |  | ||||||
|     <script type="module" src="/src/main.ts"></script> |  | ||||||
|   </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "@roadsign/sideload-ui", |  | ||||||
|   "version": "0.0.0", |  | ||||||
|   "private": true, |  | ||||||
|   "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/" |  | ||||||
|   }, |  | ||||||
|   "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" |  | ||||||
|   }, |  | ||||||
|   "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" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| @import "vfonts/IBMPlexSans.css"; |  | ||||||
| @import "vfonts/IBMPlexMono.css"; |  | ||||||
|  |  | ||||||
| a { |  | ||||||
|     color: #3f7ee8; |  | ||||||
| } |  | ||||||
| @@ -1,135 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="flex gap-[4px]"> |  | ||||||
|     <n-button size="small" @click="publishing = true"> |  | ||||||
|       <template #icon> |  | ||||||
|         <n-icon :component="CloudUpload" /> |  | ||||||
|       </template> |  | ||||||
|     </n-button> |  | ||||||
|     <n-button size="small" @click="editConfig()"> |  | ||||||
|       <template #icon> |  | ||||||
|         <n-icon :component="Edit" /> |  | ||||||
|       </template> |  | ||||||
|     </n-button> |  | ||||||
|  |  | ||||||
|     <n-modal |  | ||||||
|       v-model:show="publishing" |  | ||||||
|       class="w-[720px]" |  | ||||||
|       preset="card" |  | ||||||
|       title="Publish Artifacts" |  | ||||||
|       segmented |  | ||||||
|       closable |  | ||||||
|     > |  | ||||||
|       We are sorry about this tool isn't completed yet. <br> |  | ||||||
|       For now, you can use our <b>Wonderful Command Line Tool —— RDS</b> <br> |  | ||||||
|       Learn more on our <a href="https://wiki.smartsheep.studio/roadsign/index.html" target="_blank">official wiki</a>. |  | ||||||
|       <br> |  | ||||||
|       <br> |  | ||||||
|       Install it by this command below |  | ||||||
|       <n-code code="go install code.smartsheep.studio/goatworks/roadsign/pkg/cmd/rds@latest" /> |  | ||||||
|       <br> |  | ||||||
|       Then connect your rds client to this server |  | ||||||
|       <n-code :code="`rds connect <name> ${host} <credentials>`" /> |  | ||||||
|       <br> |  | ||||||
|       After that you can publish your stuff (You need to compress them to zip archive before publish) |  | ||||||
|       <n-code :code="`rds deploy <name> ${props.id} <upstream id or process id>`" /> |  | ||||||
|     </n-modal> |  | ||||||
|  |  | ||||||
|     <n-modal |  | ||||||
|       v-model:show="editing" |  | ||||||
|       class="w-[720px]" |  | ||||||
|       content-style="padding: 0" |  | ||||||
|       preset="card" |  | ||||||
|       title="Edit Configuration" |  | ||||||
|       segmented |  | ||||||
|       closable |  | ||||||
|     > |  | ||||||
|       <div class="relative h-[540px]"> |  | ||||||
|         <vue-monaco-editor |  | ||||||
|           v-model:value="config" |  | ||||||
|           :options="{ automaticLayout: true, minimap: { enabled: false } }" |  | ||||||
|           language="yaml" |  | ||||||
|         /> |  | ||||||
|  |  | ||||||
|         <div class="fab"> |  | ||||||
|           <n-tooltip placement="left"> |  | ||||||
|             <template #trigger> |  | ||||||
|               <n-button |  | ||||||
|                 circle |  | ||||||
|                 type="primary" |  | ||||||
|                 size="large" |  | ||||||
|                 class="shadow-lg" |  | ||||||
|                 :loading="submitting" |  | ||||||
|                 @click="syncConfig()" |  | ||||||
|               > |  | ||||||
|                 <template #icon> |  | ||||||
|                   <n-icon :component="Save" /> |  | ||||||
|                 </template> |  | ||||||
|               </n-button> |  | ||||||
|             </template> |  | ||||||
|             This operation will restart all processes related. Service may interrupted for some while. |  | ||||||
|           </n-tooltip> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </n-modal> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NButton, NCode, NIcon, NModal, NTooltip, useMessage } from "naive-ui" |  | ||||||
| import { CloudUpload, Edit, Save } from "@vicons/carbon" |  | ||||||
| import { ref } from "vue" |  | ||||||
| import { VueMonacoEditor } from "@guolao/vue-monaco-editor" |  | ||||||
| import * as yaml from "js-yaml" |  | ||||||
|  |  | ||||||
| const message = useMessage() |  | ||||||
|  |  | ||||||
| const props = defineProps<{ id: string, rules: any[], upstreams: any[], processes: any[] }>() |  | ||||||
| const emits = defineEmits(["reload"]) |  | ||||||
| const host = location.protocol + "//" + location.host |  | ||||||
|  |  | ||||||
| const submitting = ref(false) |  | ||||||
|  |  | ||||||
| const publishing = ref(false) |  | ||||||
| const editing = ref(false) |  | ||||||
|  |  | ||||||
| const config = ref<string | undefined>(undefined) |  | ||||||
|  |  | ||||||
| async function editConfig() { |  | ||||||
|   const resp = await fetch(`/cgi/sites/cfg/${props.id}`) |  | ||||||
|   config.value = await resp.text() |  | ||||||
|   editing.value = true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function syncConfig() { |  | ||||||
|   if (config.value == null) return |  | ||||||
|  |  | ||||||
|   let content |  | ||||||
|   try { |  | ||||||
|     content = yaml.load(config.value) |  | ||||||
|   } catch (e: any) { |  | ||||||
|     message.warning(`Your configuration has some issue: ${e.message}`) |  | ||||||
|     return |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   submitting.value = true |  | ||||||
|   const resp = await fetch(`/webhooks/sync/${props.id}`, { |  | ||||||
|     method: "PUT", |  | ||||||
|     headers: { "Content-Type": "application/json" }, |  | ||||||
|     body: JSON.stringify(content) |  | ||||||
|   }) |  | ||||||
|   if (resp.status != 200) { |  | ||||||
|     message.error(`Something went wrong... ${await resp.text()}`) |  | ||||||
|   } else { |  | ||||||
|     emits("reload") |  | ||||||
|   } |  | ||||||
|   submitting.value = false |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| .fab { |  | ||||||
|   position: absolute; |  | ||||||
|   bottom: 16px; |  | ||||||
|   right: 24px; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,110 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <n-button circle size="small" type="primary" @click="creating = true"> |  | ||||||
|       <template #icon> |  | ||||||
|         <n-icon :component="Add" /> |  | ||||||
|       </template> |  | ||||||
|     </n-button> |  | ||||||
|  |  | ||||||
|     <n-modal |  | ||||||
|       v-model:show="creating" |  | ||||||
|       class="w-[720px]" |  | ||||||
|       content-style="padding: 0" |  | ||||||
|       preset="card" |  | ||||||
|       title="Create Site" |  | ||||||
|       segmented |  | ||||||
|       closable |  | ||||||
|     > |  | ||||||
|       <div class="py-4 px-5 border border-solid border-b border-[#eee]"> |  | ||||||
|         <n-input |  | ||||||
|           v-model:value="data.id" |  | ||||||
|           placeholder="Will be the file name of this file" |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
|  |  | ||||||
|       <div class="relative mt-[4px] h-[540px]"> |  | ||||||
|         <vue-monaco-editor |  | ||||||
|           v-model:value="data.content" |  | ||||||
|           :options="{ automaticLayout: true, minimap: { enabled: false } }" |  | ||||||
|           language="yaml" |  | ||||||
|         /> |  | ||||||
|  |  | ||||||
|         <div class="fab"> |  | ||||||
|           <n-tooltip placement="left"> |  | ||||||
|             <template #trigger> |  | ||||||
|               <n-button |  | ||||||
|                 circle |  | ||||||
|                 type="primary" |  | ||||||
|                 size="large" |  | ||||||
|                 class="shadow-lg" |  | ||||||
|                 :loading="submitting" |  | ||||||
|                 @click="submit()" |  | ||||||
|               > |  | ||||||
|                 <template #icon> |  | ||||||
|                   <n-icon :component="Checkmark" /> |  | ||||||
|                 </template> |  | ||||||
|               </n-button> |  | ||||||
|             </template> |  | ||||||
|             This operation will publish this site right away. |  | ||||||
|           </n-tooltip> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </n-modal> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NButton, NIcon, NInput, NModal, NTooltip, useMessage } from "naive-ui" |  | ||||||
| import { Add, Checkmark } from "@vicons/carbon" |  | ||||||
| import { VueMonacoEditor } from "@guolao/vue-monaco-editor" |  | ||||||
| import { ref } from "vue" |  | ||||||
| import * as yaml from "js-yaml" |  | ||||||
|  |  | ||||||
| const message = useMessage() |  | ||||||
|  |  | ||||||
| const emits = defineEmits(["reload"]) |  | ||||||
|  |  | ||||||
| const submitting = ref(false) |  | ||||||
| const creating = ref(false) |  | ||||||
|  |  | ||||||
| const data = ref<any>({}) |  | ||||||
|  |  | ||||||
| async function submit() { |  | ||||||
|   let content |  | ||||||
|   try { |  | ||||||
|     content = yaml.load(data.value.content) |  | ||||||
|   } catch (e: any) { |  | ||||||
|     message.warning(`Your configuration has some issue: ${e.message}`) |  | ||||||
|     return |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   submitting.value = true |  | ||||||
|   const resp = await fetch(`/webhooks/sync/${data.value.id}`, { |  | ||||||
|     method: "PUT", |  | ||||||
|     headers: { "Content-Type": "application/json" }, |  | ||||||
|     body: JSON.stringify(content) |  | ||||||
|   }) |  | ||||||
|   if (resp.status != 200) { |  | ||||||
|     message.error(`Something went wrong... ${await resp.text()}`) |  | ||||||
|   } else { |  | ||||||
|     reset() |  | ||||||
|     emits("reload") |  | ||||||
|     message.success("Your site has been created! 🎉") |  | ||||||
|     creating.value = false |  | ||||||
|   } |  | ||||||
|   submitting.value = false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function reset() { |  | ||||||
|   data.value.id = "" |  | ||||||
|   data.value.content = "" |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| .fab { |  | ||||||
|   position: absolute; |  | ||||||
|   bottom: 16px; |  | ||||||
|   right: 24px; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="flex flex-col gap-1"> |  | ||||||
|  |  | ||||||
|     <div> |  | ||||||
|       <div class="font-bold">Rules</div> |  | ||||||
|       <n-code :hljs="hljs" :code="parseData(props.rules)" language="json" /> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div> |  | ||||||
|       <div class="font-bold">Upstreams</div> |  | ||||||
|       <n-code :hljs="hljs" :code="parseData(props.upstreams)" language="json" /> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <div> |  | ||||||
|       <div class="font-bold">Processes</div> |  | ||||||
|       <n-code :hljs="hljs" :code="parseData(props.processes)" language="json" /> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NCode } from "naive-ui" |  | ||||||
| import hljs from "highlight.js/lib/core" |  | ||||||
| import json from "highlight.js/lib/languages/json" |  | ||||||
|  |  | ||||||
| hljs.registerLanguage("json", json) |  | ||||||
|  |  | ||||||
| const props = defineProps<{ rules: any[], upstreams: any[], processes: any[] }>() |  | ||||||
|  |  | ||||||
| function parseData(data: any): string { |  | ||||||
|   return JSON.stringify(data, null, 1) |  | ||||||
|     .replace(/  +/g, " ") |  | ||||||
|     .replace(/\n/g, "") |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
| @@ -1,76 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <n-card title="Sites"> |  | ||||||
|       <template #header-extra> |  | ||||||
|         <sites-table-add @reload="readSites()" /> |  | ||||||
|       </template> |  | ||||||
|  |  | ||||||
|       <n-data-table |  | ||||||
|         :columns="columns" |  | ||||||
|         :data="data" |  | ||||||
|         :row-key="(row: any) => row.id" |  | ||||||
|       /> |  | ||||||
|     </n-card> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NCard, NDataTable, NTag } from "naive-ui" |  | ||||||
| import { h, ref } from "vue" |  | ||||||
| import SitesTableExpand from "@/components/data/sites-table-expand.vue" |  | ||||||
| import SitesTableAction from "@/components/data/sites-table-action.vue" |  | ||||||
| import SitesTableAdd from "@/components/data/sites-table-add.vue" |  | ||||||
|  |  | ||||||
| const columns: any[] = [ |  | ||||||
|   { |  | ||||||
|     type: "expand", |  | ||||||
|     renderExpand(row: any) { |  | ||||||
|       return h(SitesTableExpand, { ...row, class: "pl-[38px]" }) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     title: "ID", |  | ||||||
|     key: "id", |  | ||||||
|     render(row: any) { |  | ||||||
|       return h(NTag, { type: "info", bordered: false, size: "small" }, row?.id) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     title: "Rules", |  | ||||||
|     key: "rules", |  | ||||||
|     render(row: any) { |  | ||||||
|       return row?.rules?.length ?? 0 |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     title: "Upstreams", |  | ||||||
|     key: "upstreams", |  | ||||||
|     render(row: any) { |  | ||||||
|       return row?.upstreams?.length ?? 0 |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     title: "Processes", |  | ||||||
|     key: "processes", |  | ||||||
|     render(row: any) { |  | ||||||
|       return row?.processes?.length ?? 0 |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   { |  | ||||||
|     title: "Actions", |  | ||||||
|     key: "actions", |  | ||||||
|     render(row: any) { |  | ||||||
|       return h(SitesTableAction, { ...row, onReload: () => readSites() }) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| const data = ref<any[]>([]) |  | ||||||
|  |  | ||||||
| async function readSites() { |  | ||||||
|   const resp = await fetch("/cgi/sites") |  | ||||||
|   data.value = await resp.json() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| readSites() |  | ||||||
| </script> |  | ||||||
| @@ -1,60 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <n-layout> |  | ||||||
|     <n-layout-header class="header py-[8px] px-[36px]" bordered> |  | ||||||
|       <div class="flex items-center gap-2"> |  | ||||||
|         <router-link class="link" to="/"> |  | ||||||
|           RoadSign<i>!</i> |  | ||||||
|         </router-link> |  | ||||||
|       </div> |  | ||||||
|  |  | ||||||
|       <div class="nav-menu"> |  | ||||||
|         <div class="h-full flex items-center header-nav"> |  | ||||||
|           <n-menu v-model:value="key" :options="options" mode="horizontal" /> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </n-layout-header> |  | ||||||
|     <n-layout-content class="h-[calc(100vh-70px)] container mx-auto" content-style="padding: 24px"> |  | ||||||
|       <router-view /> |  | ||||||
|     </n-layout-content> |  | ||||||
|   </n-layout> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { type MenuOption, NIcon, NLayout, NLayoutContent, NLayoutHeader, NMenu } from "naive-ui" |  | ||||||
| import { type Component, h, ref } from "vue" |  | ||||||
| import { Dashboard } from "@vicons/carbon" |  | ||||||
| import { RouterLink, useRoute, useRouter } from "vue-router" |  | ||||||
|  |  | ||||||
| const route = useRoute() |  | ||||||
| const router = useRouter() |  | ||||||
| const key = ref(route.name?.toString()) |  | ||||||
|  |  | ||||||
| router.afterEach((to) => { |  | ||||||
|   key.value = to.name?.toString() ?? "index" |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| const options: MenuOption[] = [ |  | ||||||
|   { |  | ||||||
|     label: () => h(RouterLink, { to: { name: "dashboard" } }, "Dashboard"), |  | ||||||
|     icon: renderIcon(Dashboard), |  | ||||||
|     key: "dashboard" |  | ||||||
|   } |  | ||||||
| ] |  | ||||||
|  |  | ||||||
| function renderIcon(icon: Component) { |  | ||||||
|   return () => h(NIcon, null, { default: () => h(icon) }) |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| .header { |  | ||||||
|   display: grid; |  | ||||||
|   grid-template-columns: 1fr auto 1fr; |  | ||||||
|   gap: 40px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .link { |  | ||||||
|   all: unset; |  | ||||||
|   cursor: pointer; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -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") |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <n-message-provider> |  | ||||||
|     <router-view /> |  | ||||||
|   </n-message-provider> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NMessageProvider } from "naive-ui" |  | ||||||
| </script> |  | ||||||
| @@ -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 |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="flex flex-col gap-2"> |  | ||||||
|     <div class="grid gap-2 grid-cols-2 lg:grid-cols-4"> |  | ||||||
|       <n-card embedded> |  | ||||||
|         <n-statistic label="Status">{{ data?.status ? "Operational" : "Incident" }}</n-statistic> |  | ||||||
|       </n-card> |  | ||||||
|       <n-card embedded> |  | ||||||
|         <n-statistic label="Sites">{{ data?.sites }}</n-statistic> |  | ||||||
|       </n-card> |  | ||||||
|       <n-card embedded> |  | ||||||
|         <n-statistic label="Upstreams">{{ data?.upstreams }}</n-statistic> |  | ||||||
|       </n-card> |  | ||||||
|       <n-card embedded> |  | ||||||
|         <n-statistic label="Processes">{{ data?.processes }}</n-statistic> |  | ||||||
|       </n-card> |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|     <sites-table /> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| import { NCard, NStatistic } from "naive-ui" |  | ||||||
| import { ref } from "vue" |  | ||||||
| import SitesTable from "@/components/data/sites-table.vue" |  | ||||||
|  |  | ||||||
| const data = ref<any>({}) |  | ||||||
|  |  | ||||||
| async function readStatistics() { |  | ||||||
|   const resp = await fetch("/cgi/statistics") |  | ||||||
|   data.value = await resp.json() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| readStatistics() |  | ||||||
| </script> |  | ||||||
| @@ -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/*"] |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| { |  | ||||||
|   "files": [], |  | ||||||
|   "references": [ |  | ||||||
|     { |  | ||||||
|       "path": "./tsconfig.node.json" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "path": "./tsconfig.app.json" |  | ||||||
|     } |  | ||||||
|   ] |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| { |  | ||||||
|   "extends": "@tsconfig/node18/tsconfig.json", |  | ||||||
|   "include": [ |  | ||||||
|     "vite.config.*", |  | ||||||
|     "vitest.config.*", |  | ||||||
|     "cypress.config.*", |  | ||||||
|     "nightwatch.conf.*", |  | ||||||
|     "playwright.config.*" |  | ||||||
|   ], |  | ||||||
|   "compilerOptions": { |  | ||||||
|     "composite": true, |  | ||||||
|     "noEmit": true, |  | ||||||
|     "module": "ESNext", |  | ||||||
|     "moduleResolution": "Bundler", |  | ||||||
|     "types": ["node"] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| import { defineConfig, presetUno } from "unocss" |  | ||||||
|  |  | ||||||
| export default defineConfig({ |  | ||||||
|   presets: [presetUno({ preflight: false })] |  | ||||||
| }) |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| import { fileURLToPath, URL } from "node:url" |  | ||||||
|  |  | ||||||
| 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" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
| @@ -1,45 +0,0 @@ | |||||||
| package sign |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"io" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"gopkg.in/yaml.v2" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var App *RoadApp |  | ||||||
|  |  | ||||||
| func ReadInConfig(root string) error { |  | ||||||
| 	instance := &RoadApp{ |  | ||||||
| 		Sites: []*SiteConfig{}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := filepath.Walk(root, func(fp string, info os.FileInfo, err error) error { |  | ||||||
| 		var site SiteConfig |  | ||||||
| 		if info.IsDir() { |  | ||||||
| 			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 { |  | ||||||
| 			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) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return nil |  | ||||||
| 	}); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	App = instance |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
							
								
								
									
										144
									
								
								pkg/sign/pm.go
									
									
									
									
									
								
							
							
						
						
									
										144
									
								
								pkg/sign/pm.go
									
									
									
									
									
								
							| @@ -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) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,127 +0,0 @@ | |||||||
| package sign |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"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 { |  | ||||||
| 	timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond |  | ||||||
| 	return proxy.Do(c, upstream.MakeURI(c), &fasthttp.Client{ |  | ||||||
| 		ReadTimeout:  timeout, |  | ||||||
| 		WriteTimeout: timeout, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func makeFileResponse(c *fiber.Ctx, upstream *UpstreamInstance) error { |  | ||||||
| 	uri, queries := upstream.GetRawURI() |  | ||||||
| 	root := http.Dir(uri) |  | ||||||
|  |  | ||||||
| 	method := c.Method() |  | ||||||
|  |  | ||||||
| 	// We only serve static assets for GET and HEAD methods |  | ||||||
| 	if method != fiber.MethodGet && method != fiber.MethodHead { |  | ||||||
| 		return c.Next() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Strip prefix |  | ||||||
| 	prefix := c.Route().Path |  | ||||||
| 	path := strings.TrimPrefix(c.Path(), prefix) |  | ||||||
| 	if !strings.HasPrefix(path, "/") { |  | ||||||
| 		path = "/" + path |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Add prefix |  | ||||||
| 	if queries.Get("prefix") != "" { |  | ||||||
| 		path = queries.Get("prefix") + path |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(path) > 1 { |  | ||||||
| 		path = utils.TrimRight(path, '/') |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	file, err := root.Open(path) |  | ||||||
| 	if err != nil && errors.Is(err, fs.ErrNotExist) { |  | ||||||
| 		if queries.Get("suffix") != "" { |  | ||||||
| 			file, err = root.Open(path + queries.Get("suffix")) |  | ||||||
| 		} |  | ||||||
| 		if err != nil && queries.Get("fallback") != "" { |  | ||||||
| 			file, err = root.Open(queries.Get("fallback")) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if err != nil { |  | ||||||
| 		if errors.Is(err, fs.ErrNotExist) { |  | ||||||
| 			return fiber.ErrNotFound |  | ||||||
| 		} |  | ||||||
| 		return fmt.Errorf("failed to open: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	stat, err := file.Stat() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed to stat: %w", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Serve index if path is directory |  | ||||||
| 	if stat.IsDir() { |  | ||||||
| 		indexFile := lo.Ternary(len(queries.Get("index")) > 0, queries.Get("index"), "index.html") |  | ||||||
| 		indexPath := utils.TrimRight(path, '/') + indexFile |  | ||||||
| 		index, err := root.Open(indexPath) |  | ||||||
| 		if err == nil { |  | ||||||
| 			indexStat, err := index.Stat() |  | ||||||
| 			if err == nil { |  | ||||||
| 				file = index |  | ||||||
| 				stat = indexStat |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c.Status(fiber.StatusOK) |  | ||||||
|  |  | ||||||
| 	modTime := stat.ModTime() |  | ||||||
| 	contentLength := int(stat.Size()) |  | ||||||
|  |  | ||||||
| 	// Set Content-Type header |  | ||||||
| 	if queries.Get("charset") == "" { |  | ||||||
| 		c.Type(filepath.Ext(stat.Name())) |  | ||||||
| 	} else { |  | ||||||
| 		c.Type(filepath.Ext(stat.Name()), queries.Get("charset")) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Set Last-Modified header |  | ||||||
| 	if !modTime.IsZero() { |  | ||||||
| 		c.Set(fiber.HeaderLastModified, modTime.UTC().Format(http.TimeFormat)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if method == fiber.MethodGet { |  | ||||||
| 		maxAge, err := strconv.Atoi(queries.Get("maxAge")) |  | ||||||
| 		if lo.Ternary(err != nil, maxAge, 0) > 0 { |  | ||||||
| 			c.Set(fiber.HeaderCacheControl, "public, max-age="+queries.Get("maxAge")) |  | ||||||
| 		} |  | ||||||
| 		c.Response().SetBodyStream(file, contentLength) |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if method == fiber.MethodHead { |  | ||||||
| 		c.Request().ResetBody() |  | ||||||
| 		c.Response().SkipBody = true |  | ||||||
| 		c.Response().Header.SetContentLength(contentLength) |  | ||||||
| 		if err := file.Close(); err != nil { |  | ||||||
| 			return fmt.Errorf("failed to close: %w", err) |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return fiber.ErrNotFound |  | ||||||
| } |  | ||||||
| @@ -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"` |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| package transformers |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"github.com/valyala/fasthttp" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var CompressResponse = RequestTransformer{ |  | ||||||
| 	ModifyResponse: func(options any, ctx *fiber.Ctx) error { |  | ||||||
| 		opts := DeserializeOptions[struct { |  | ||||||
| 			Level int `json:"level" yaml:"level"` |  | ||||||
| 		}](options) |  | ||||||
|  |  | ||||||
| 		var fctx = func(c *fasthttp.RequestCtx) {} |  | ||||||
| 		var compressor fasthttp.RequestHandler |  | ||||||
| 		switch opts.Level { |  | ||||||
| 		// Best Speed Mode |  | ||||||
| 		case 1: |  | ||||||
| 			compressor = fasthttp.CompressHandlerBrotliLevel(fctx, |  | ||||||
| 				fasthttp.CompressBrotliBestSpeed, |  | ||||||
| 				fasthttp.CompressBestSpeed, |  | ||||||
| 			) |  | ||||||
| 		// Best Compression Mode |  | ||||||
| 		case 2: |  | ||||||
| 			compressor = fasthttp.CompressHandlerBrotliLevel(fctx, |  | ||||||
| 				fasthttp.CompressBrotliBestCompression, |  | ||||||
| 				fasthttp.CompressBestCompression, |  | ||||||
| 			) |  | ||||||
| 		// Default Mode |  | ||||||
| 		default: |  | ||||||
| 			compressor = fasthttp.CompressHandlerBrotliLevel(fctx, |  | ||||||
| 				fasthttp.CompressBrotliDefaultCompression, |  | ||||||
| 				fasthttp.CompressDefaultCompression, |  | ||||||
| 			) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		compressor(ctx.Context()) |  | ||||||
|  |  | ||||||
| 		return nil |  | ||||||
| 	}, |  | ||||||
| } |  | ||||||
| @@ -1,61 +0,0 @@ | |||||||
| package transformers |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	jsoniter "github.com/json-iterator/go" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Definitions |  | ||||||
|  |  | ||||||
| var json = jsoniter.ConfigCompatibleWithStandardLibrary |  | ||||||
|  |  | ||||||
| type RequestTransformer 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"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (v *RequestTransformerConfig) TransformRequest(ctx *fiber.Ctx) error { |  | ||||||
| 	for k, f := range Transformers { |  | ||||||
| 		if k == v.Type { |  | ||||||
| 			if f.ModifyRequest != nil { |  | ||||||
| 				return f.ModifyRequest(v.Options, ctx) |  | ||||||
| 			} |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (v *RequestTransformerConfig) TransformResponse(ctx *fiber.Ctx) error { |  | ||||||
| 	for k, f := range Transformers { |  | ||||||
| 		if k == v.Type { |  | ||||||
| 			if f.ModifyResponse != nil { |  | ||||||
| 				return f.ModifyResponse(v.Options, ctx) |  | ||||||
| 			} |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Helpers |  | ||||||
|  |  | ||||||
| func DeserializeOptions[T any](data any) T { |  | ||||||
| 	var out T |  | ||||||
| 	raw, _ := json.Marshal(data) |  | ||||||
| 	_ = json.Unmarshal(raw, &out) |  | ||||||
| 	return out |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Map of Transformers |  | ||||||
| // Every transformer need to be mapped here so that they can get work. |  | ||||||
|  |  | ||||||
| var Transformers = map[string]RequestTransformer{ |  | ||||||
| 	"replacePath":      ReplacePath, |  | ||||||
| 	"compressResponse": CompressResponse, |  | ||||||
| } |  | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| package transformers |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/gofiber/fiber/v2" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ReplacePath = RequestTransformer{ |  | ||||||
| 	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"` |  | ||||||
| 		}](options) |  | ||||||
| 		path := string(ctx.Request().URI().Path()) |  | ||||||
| 		if !opts.Complex { |  | ||||||
| 			ctx.Path(strings.ReplaceAll(path, opts.Pattern, opts.Value)) |  | ||||||
| 		} else if ex := regexp.MustCompile(opts.Pattern); ex != nil { |  | ||||||
| 			ctx.Path(ex.ReplaceAllString(path, opts.Repl)) |  | ||||||
| 		} |  | ||||||
| 		return nil |  | ||||||
| 	}, |  | ||||||
| } |  | ||||||
| @@ -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, "") |  | ||||||
| } |  | ||||||
							
								
								
									
										28
									
								
								settings.yml
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								settings.yml
									
									
									
									
									
								
							| @@ -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 |  | ||||||
							
								
								
									
										9
									
								
								src/config/loader.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/config/loader.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | use config::Config; | ||||||
|  |  | ||||||
|  | pub fn load_settings() -> Config { | ||||||
|  |     Config::builder() | ||||||
|  |         .add_source(config::File::with_name("Settings")) | ||||||
|  |         .add_source(config::Environment::with_prefix("ROADSIGN")) | ||||||
|  |         .build() | ||||||
|  |         .unwrap() | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								src/config/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/config/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | pub mod loader; | ||||||
							
								
								
									
										39
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | |||||||
|  | mod config; | ||||||
|  | mod proxies; | ||||||
|  | mod sideload; | ||||||
|  |  | ||||||
|  | use poem::{listener::TcpListener, Route, Server}; | ||||||
|  | use poem_openapi::OpenApiService; | ||||||
|  |  | ||||||
|  | #[tokio::main] | ||||||
|  | async fn main() -> Result<(), std::io::Error> { | ||||||
|  |     // Load settings | ||||||
|  |     let settings = config::loader::load_settings(); | ||||||
|  |  | ||||||
|  |     println!( | ||||||
|  |         "Will listen at {:?}", | ||||||
|  |         settings.get_array("listen.proxies").unwrap() | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     if std::env::var_os("RUST_LOG").is_none() { | ||||||
|  |         std::env::set_var("RUST_LOG", "poem=debug"); | ||||||
|  |     } | ||||||
|  |     tracing_subscriber::fmt::init(); | ||||||
|  |  | ||||||
|  |     // Proxies | ||||||
|  |  | ||||||
|  |     // Sideload | ||||||
|  |     let sideload = OpenApiService::new(sideload::SideloadApi, "Sideload API", "1.0") | ||||||
|  |         .server("http://localhost:3000/cgi"); | ||||||
|  |  | ||||||
|  |     let sideload_server = Server::new(TcpListener::bind( | ||||||
|  |         settings | ||||||
|  |             .get_string("listen.sideload") | ||||||
|  |             .unwrap_or("0.0.0.0:81".to_string()), | ||||||
|  |     )) | ||||||
|  |     .run(Route::new().nest("/cgi", sideload)); | ||||||
|  |  | ||||||
|  |     tokio::try_join!(sideload_server)?; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								src/proxies/config.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/proxies/config.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | use std::{collections::HashMap, time::Duration}; | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct Region { | ||||||
|  |     id: String, | ||||||
|  |     locations: Vec<Location>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct Location { | ||||||
|  |     hosts: Vec<String>, | ||||||
|  |     paths: Vec<String>, | ||||||
|  |     headers: Vec<HashMap<String, String>>, | ||||||
|  |     query_strings: Vec<HashMap<String, String>>, | ||||||
|  |     destination: Vec<Destination>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct Destination { | ||||||
|  |     uri: Vec<String>, | ||||||
|  |     timeout: Duration, | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								src/proxies/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/proxies/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | pub mod config; | ||||||
							
								
								
									
										3
									
								
								src/sideload/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/sideload/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | pub mod overview; | ||||||
|  |  | ||||||
|  | pub struct SideloadApi; | ||||||
							
								
								
									
										14
									
								
								src/sideload/overview.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/sideload/overview.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | use poem_openapi::{param::Query, payload::PlainText, OpenApi}; | ||||||
|  |  | ||||||
|  | use super::SideloadApi; | ||||||
|  |  | ||||||
|  | #[OpenApi] | ||||||
|  | impl SideloadApi { | ||||||
|  |     #[oai(path = "/hello", method = "get")] | ||||||
|  |     async fn index(&self, name: Query<Option<String>>) -> PlainText<String> { | ||||||
|  |         match name.0 { | ||||||
|  |             Some(name) => PlainText(format!("hello, {name}!")), | ||||||
|  |             None => PlainText("hello!".to_string()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,85 +0,0 @@ | |||||||
| # Benchmark |  | ||||||
|  |  | ||||||
| This result is design for test the performance of the roadsign. |  | ||||||
| Welcome to contribute more tests of others reverse proxy software! |  | ||||||
|  |  | ||||||
| ## Platform |  | ||||||
|  |  | ||||||
| All tests are running on my workstation: |  | ||||||
|  |  | ||||||
| ```text |  | ||||||
|                      ..'          littlesheep@LittleSheepdeMacBook-Pro |  | ||||||
|                  ,xNMM.           ------------------------------------ |  | ||||||
|                .OMMMMo            OS: macOS Sonoma 14.1 23B2073 arm64 |  | ||||||
|                lMM"               Host: MacBook Pro (14-inch, Nov 2023, Three Thunderbolt 4 ports) |  | ||||||
|      .;loddo:.  .olloddol;.       Kernel: 23.1.0 |  | ||||||
|    cKMMMMMMMMMMNWMMMMMMMMMM0:     Uptime: 2 days, 1 hour, 16 mins |  | ||||||
|  .KMMMMMMMMMMMMMMMMMMMMMMMWd.     Packages: 63 (brew), 4 (brew-cask) |  | ||||||
|  XMMMMMMMMMMMMMMMMMMMMMMMX.       Shell: zsh 5.9 |  | ||||||
| ;MMMMMMMMMMMMMMMMMMMMMMMM:        Display (Color LCD): 3024x1964 @ 120Hz (as 1512x982) [Built-in] |  | ||||||
| :MMMMMMMMMMMMMMMMMMMMMMMM:        DE: Aqua |  | ||||||
| .MMMMMMMMMMMMMMMMMMMMMMMMX.       WM: Quartz Compositor |  | ||||||
|  kMMMMMMMMMMMMMMMMMMMMMMMMWd.     WM Theme: Multicolor (Dark) |  | ||||||
|  'XMMMMMMMMMMMMMMMMMMMMMMMMMMk    Font: .AppleSystemUIFont [System], Helvetica [User] |  | ||||||
|   'XMMMMMMMMMMMMMMMMMMMMMMMMK.    Cursor: Fill - Black, Outline - White (32px) |  | ||||||
|     kMMMMMMMMMMMMMMMMMMMMMMd      Terminal: iTerm 3.4.22 |  | ||||||
|      ;KMMMMMMMWXXWMMMMMMMk.       Terminal Font: MesloLGMNFM-Regular (12pt) |  | ||||||
|        "cooc*"    "*coo'"         CPU: Apple M3 Max (14) @ 4.06 GHz |  | ||||||
|                                   GPU: Apple M3 Max (30) [Integrated] |  | ||||||
|                                   Memory: 18.45 GiB / 36.00 GiB (51%) |  | ||||||
|                                   Swap: Disabled |  | ||||||
|                                   Disk (/): 72.52 GiB / 926.35 GiB (8%) - apfs [Read-only] |  | ||||||
|                                   Local IP (en0): 192.168.50.0/24 * |  | ||||||
|                                   Battery: 100% [AC connected] |  | ||||||
|                                   Power Adapter: 96W USB-C Power Adapter |  | ||||||
|                                   Locale: zh_CN.UTF-8 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Results |  | ||||||
|  |  | ||||||
| The tests are run in the order `nginx -> roadsign without prefork -> roadsign with prefork`. There is no reason why nginx performance should be affected by hardware temperature. |  | ||||||
|  |  | ||||||
| ### Nginx |  | ||||||
|  |  | ||||||
| ```shell |  | ||||||
| go-wrk -c 60 -d 120 http://localhost:8001 |  | ||||||
| # => Running 120s test @ http://localhost:8001 |  | ||||||
| # =>   60 goroutine(s) running concurrently |  | ||||||
| # => 515749 requests in 1m59.953302003s, 245.92MB read |  | ||||||
| # => Requests/sec:           4299.58 |  | ||||||
| # => Transfer/sec:           2.05MB |  | ||||||
| # => Avg Req Time:           13.954846ms |  | ||||||
| # => Fastest Request:        0s |  | ||||||
| # => Slowest Request:        410.6972ms |  | ||||||
| # => Number of Errors:       0 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### RoadSign |  | ||||||
|  |  | ||||||
| ```shell |  | ||||||
| go-wrk -c 60 -d 120 http://localhost:8000 |  | ||||||
| # => Running 120s test @ http://localhost:8000 |  | ||||||
| # =>   60 goroutine(s) running concurrently |  | ||||||
| # => 8905230 requests in 1m56.215762709s, 3.52GB read |  | ||||||
| # => Requests/sec:		76626.70 |  | ||||||
| # => Transfer/sec:		30.98MB |  | ||||||
| # => Avg Req Time:		783.016µs |  | ||||||
| # => Fastest Request:	28.542µs |  | ||||||
| # => Slowest Request:	46.773083ms |  | ||||||
| # => Number of Errors:	0 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### RoadSign w/ Prefork |  | ||||||
|  |  | ||||||
| ```shell |  | ||||||
| go-wrk -c 60 -d 120 http://localhost:8000 |  | ||||||
| # => Running 120s test @ http://localhost:8000 |  | ||||||
| # =>  60 goroutine(s) running concurrently |  | ||||||
| # => 4784308 requests in 1m59.100307178s, 1.89GB read |  | ||||||
| # => Requests/sec:		40170.41 |  | ||||||
| # => Transfer/sec:		16.24MB |  | ||||||
| # => Avg Req Time:		1.493636ms |  | ||||||
| # => Fastest Request:	34.291µs |  | ||||||
| # => Slowest Request:	8.727666ms |  | ||||||
| # => Number of Errors:	0 |  | ||||||
| ``` |  | ||||||
							
								
								
									
										3
									
								
								test/data/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								test/data/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +0,0 @@ | |||||||
| /ssr |  | ||||||
| /spa |  | ||||||
| /congress |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html> |  | ||||||
| <head> |  | ||||||
| 	<meta charset="utf-8"> |  | ||||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1"> |  | ||||||
| 	<title>Hello, World!</title> |  | ||||||
| </head> |  | ||||||
| <body> |  | ||||||
| 	<p>Hello, there!</p> |  | ||||||
| 	<p>Here's the roadsign vs. nginx benchmarking test data!</p> |  | ||||||
| </body> |  | ||||||
| </html> |  | ||||||
| @@ -1,117 +0,0 @@ | |||||||
|  |  | ||||||
| #user  nobody; |  | ||||||
| worker_processes  1; |  | ||||||
|  |  | ||||||
| #error_log  logs/error.log; |  | ||||||
| #error_log  logs/error.log  notice; |  | ||||||
| #error_log  logs/error.log  info; |  | ||||||
|  |  | ||||||
| #pid        logs/nginx.pid; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| events { |  | ||||||
|     worker_connections  1024; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| http { |  | ||||||
|     include       mime.types; |  | ||||||
|     default_type  application/octet-stream; |  | ||||||
|  |  | ||||||
|     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ' |  | ||||||
|     #                  '$status $body_bytes_sent "$http_referer" ' |  | ||||||
|     #                  '"$http_user_agent" "$http_x_forwarded_for"'; |  | ||||||
|  |  | ||||||
|     #access_log  logs/access.log  main; |  | ||||||
|  |  | ||||||
|     sendfile        on; |  | ||||||
|     #tcp_nopush     on; |  | ||||||
|  |  | ||||||
|     #keepalive_timeout  0; |  | ||||||
|     keepalive_timeout  65; |  | ||||||
|  |  | ||||||
|     #gzip  on; |  | ||||||
|  |  | ||||||
|     server { |  | ||||||
|         listen       8001; |  | ||||||
|         server_name  localhost; |  | ||||||
|  |  | ||||||
|         #charset koi8-r; |  | ||||||
|  |  | ||||||
|         #access_log  logs/host.access.log  main; |  | ||||||
|  |  | ||||||
|         location / { |  | ||||||
|             root   ../data; |  | ||||||
|             index  index.html index.htm; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         #error_page  404              /404.html; |  | ||||||
|  |  | ||||||
|         # redirect server error pages to the static page /50x.html |  | ||||||
|         # |  | ||||||
|         error_page   500 502 503 504  /50x.html; |  | ||||||
|         location = /50x.html { |  | ||||||
|             root   html; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         # proxy the PHP scripts to Apache listening on 127.0.0.1:80 |  | ||||||
|         # |  | ||||||
|         #location ~ \.php$ { |  | ||||||
|         #    proxy_pass   http://127.0.0.1; |  | ||||||
|         #} |  | ||||||
|  |  | ||||||
|         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 |  | ||||||
|         # |  | ||||||
|         #location ~ \.php$ { |  | ||||||
|         #    root           html; |  | ||||||
|         #    fastcgi_pass   127.0.0.1:9000; |  | ||||||
|         #    fastcgi_index  index.php; |  | ||||||
|         #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name; |  | ||||||
|         #    include        fastcgi_params; |  | ||||||
|         #} |  | ||||||
|  |  | ||||||
|         # deny access to .htaccess files, if Apache's document root |  | ||||||
|         # concurs with nginx's one |  | ||||||
|         # |  | ||||||
|         #location ~ /\.ht { |  | ||||||
|         #    deny  all; |  | ||||||
|         #} |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     # another virtual host using mix of IP-, name-, and port-based configuration |  | ||||||
|     # |  | ||||||
|     #server { |  | ||||||
|     #    listen       8000; |  | ||||||
|     #    listen       somename:8080; |  | ||||||
|     #    server_name  somename  alias  another.alias; |  | ||||||
|  |  | ||||||
|     #    location / { |  | ||||||
|     #        root   html; |  | ||||||
|     #        index  index.html index.htm; |  | ||||||
|     #    } |  | ||||||
|     #} |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     # HTTPS server |  | ||||||
|     # |  | ||||||
|     #server { |  | ||||||
|     #    listen       443 ssl; |  | ||||||
|     #    server_name  localhost; |  | ||||||
|  |  | ||||||
|     #    ssl_certificate      cert.pem; |  | ||||||
|     #    ssl_certificate_key  cert.key; |  | ||||||
|  |  | ||||||
|     #    ssl_session_cache    shared:SSL:1m; |  | ||||||
|     #    ssl_session_timeout  5m; |  | ||||||
|  |  | ||||||
|     #    ssl_ciphers  HIGH:!aNULL:!MD5; |  | ||||||
|     #    ssl_prefer_server_ciphers  on; |  | ||||||
|  |  | ||||||
|     #    location / { |  | ||||||
|     #        root   html; |  | ||||||
|     #        index  index.html index.htm; |  | ||||||
|     #    } |  | ||||||
|     #} |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @@ -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 |  | ||||||
| @@ -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 |  | ||||||
| @@ -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"] |  | ||||||
| @@ -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 |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| name: Example Site |  | ||||||
| rules: |  | ||||||
|   - host: ["localhost:8000"] |  | ||||||
|     path: ["/"] |  | ||||||
| upstreams: |  | ||||||
|   - id: example |  | ||||||
|     name: Benchmarking Data |  | ||||||
|     uri: files://../data |  | ||||||
| @@ -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 |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| name: Example Site |  | ||||||
| rules: |  | ||||||
|   - host: ["localhost:8000"] |  | ||||||
|     path: ["/"] |  | ||||||
| upstreams: |  | ||||||
|   - id: example |  | ||||||
|     name: Benchmarking Data |  | ||||||
|     uri: files://../data |  | ||||||
| @@ -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 |  | ||||||
		Reference in New Issue
	
	Block a user