diff --git a/.gitignore b/.gitignore index 65bd64a..c0921b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .task -examples/everything/cmd/everything/everything +examples/webserver/cmd/webserver/webserver diff --git a/README.md b/README.md index 5464ac7..cf8f931 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ By using stdfx as an application starter you benefit from: - builtin cobra subcommands like config or version - configurable structured logging -See [examples/everything](./examples/everything/) to test and experience it in action. +See [examples/webserver](./examples/webserver/) to test and experience it in action. ### Usage example diff --git a/Taskfile.yml b/Taskfile.yml index 611f0e5..7554a57 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,9 +8,9 @@ dotenv: ['.env'] # include other taskfiles includes: - everything: - taskfile: ./examples/everything/Taskfile.yml - dir: ./examples/everything + webserver: + taskfile: ./examples/webserver/Taskfile.yml + dir: ./examples/webserver tasks: ## upgrade dependencies @@ -19,7 +19,7 @@ tasks: cmds: - go get -u ./... - go mod tidy - - task: everything:upgrade + - task: webserver:upgrade # static tests diff --git a/examples/everything/everything b/examples/everything/everything deleted file mode 100755 index e9228b6..0000000 Binary files a/examples/everything/everything and /dev/null differ diff --git a/examples/everything/README.md b/examples/webserver/README.md similarity index 51% rename from examples/everything/README.md rename to examples/webserver/README.md index fc077ce..9020e74 100644 --- a/examples/everything/README.md +++ b/examples/webserver/README.md @@ -1,4 +1,4 @@ -# everything +# webserver This example shows the usage of every stdfx feature. @@ -6,15 +6,15 @@ You can choose to run several subcommands: ```shell # run the server -go run ./cmd/everything -c . server +go run ./cmd/webserver -c . server # or task run # or try different subcommands -go run ./cmd/everything -c . help -go run ./cmd/everything -c . version -go run ./cmd/everything -c . config validate -go run ./cmd/everything -c . config get webserver.port +go run ./cmd/webserver -c . help +go run ./cmd/webserver -c . version +go run ./cmd/webserver -c . config validate +go run ./cmd/webserver -c . config get webserver.port ``` You can also build the binary and run it natively: @@ -24,5 +24,5 @@ task build # afterwards run -cmd/everything/everything -c . server +cmd/webserver/webserver -c . server ``` diff --git a/examples/everything/Taskfile.yml b/examples/webserver/Taskfile.yml similarity index 87% rename from examples/everything/Taskfile.yml rename to examples/webserver/Taskfile.yml index aea49f2..2e34418 100644 --- a/examples/everything/Taskfile.yml +++ b/examples/webserver/Taskfile.yml @@ -8,17 +8,17 @@ shopt: [globstar] # support double star glob paths: **/*.go # include other taskfiles includes: - everything: - taskfile: ./cmd/everything/Taskfile.yml - dir: ./cmd/everything + webserver: + taskfile: ./cmd/webserver/Taskfile.yml + dir: ./cmd/webserver tasks: # building build: - desc: Builds everything + desc: Builds webserver cmds: - - task: everything:build - # - task: everything:completion + - task: webserver:build + # - task: webserver:completion # build container image image: @@ -30,15 +30,15 @@ tasks: clean: desc: Removes any files created by tasks cmds: - - task: everything:clean + - task: webserver:clean - rm -rf build # run - run-everything: - desc: Runs the everything program + run-webserver: + desc: Runs the webserver program aliases: [run] cmds: - - go run ./cmd/everything/ -c . server + - go run ./cmd/webserver/ -c . server ## upgrade dependencies upgrade: diff --git a/examples/everything/cmd/everything/Taskfile.yml b/examples/webserver/cmd/webserver/Taskfile.yml similarity index 93% rename from examples/everything/cmd/everything/Taskfile.yml rename to examples/webserver/cmd/webserver/Taskfile.yml index 9349613..c894b81 100644 --- a/examples/everything/cmd/everything/Taskfile.yml +++ b/examples/webserver/cmd/webserver/Taskfile.yml @@ -1,12 +1,12 @@ version: '3' env: - BIN: '{{ .BIN | default "everything" }}' + BIN: '{{ .BIN | default "webserver" }}' tasks: # builds binary build: - desc: Builds the everything binary + desc: Builds the webserver binary env: GOOS: '{{ .GOOS | default "" }}' GOARCH: '{{ .GOARCH | default "" }}' diff --git a/examples/everything/cmd/everything/main.go b/examples/webserver/cmd/webserver/main.go similarity index 85% rename from examples/everything/cmd/everything/main.go rename to examples/webserver/cmd/webserver/main.go index e3aba3f..a630389 100644 --- a/examples/everything/cmd/everything/main.go +++ b/examples/webserver/cmd/webserver/main.go @@ -21,7 +21,7 @@ import ( "github.com/choopm/stdfx" "github.com/choopm/stdfx/configfx" - "github.com/choopm/stdfx/examples/everything" + "github.com/choopm/stdfx/examples/webserver" "github.com/choopm/stdfx/loggingfx/zerologfx" "github.com/rs/zerolog" "github.com/spf13/cobra" @@ -36,15 +36,15 @@ func main() { // logging zerologfx.Module, fx.WithLogger(zerologfx.ToFx), - fx.Decorate(zerologfx.Decorator[everything.Config]), + fx.Decorate(zerologfx.Decorator[webserver.Config]), // viper configuration - fx.Provide(stdfx.ConfigFile[everything.Config]("server")), + fx.Provide(stdfx.ConfigFile[webserver.Config]("webserver")), // cobra commands fx.Provide( stdfx.AutoRegister(stdfx.VersionCommand(version)), - stdfx.AutoRegister(stdfx.ConfigCommand[everything.Config]), + stdfx.AutoRegister(stdfx.ConfigCommand[webserver.Config]), stdfx.AutoRegister(serverCommand), stdfx.AutoCommand, // add registered commands to root ), @@ -57,7 +57,7 @@ func main() { // serverCommand returns a *cobra.Command to start the server from a ConfigProvider func serverCommand( - configProvider configfx.Provider[everything.Config], + configProvider configfx.Provider[webserver.Config], logger *zerolog.Logger, ) *cobra.Command { cmd := &cobra.Command{ @@ -71,7 +71,7 @@ func serverCommand( } // create server instance - server, err := everything.NewServer(cfg, logger) + server, err := webserver.NewServer(cfg, logger) if err != nil { return err } diff --git a/examples/everything/config.go b/examples/webserver/config.go similarity index 99% rename from examples/everything/config.go rename to examples/webserver/config.go index ae57f2b..858ca78 100644 --- a/examples/everything/config.go +++ b/examples/webserver/config.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package everything +package webserver import ( "fmt" diff --git a/examples/everything/go.mod b/examples/webserver/go.mod similarity index 87% rename from examples/everything/go.mod rename to examples/webserver/go.mod index 48add87..72678a6 100644 --- a/examples/everything/go.mod +++ b/examples/webserver/go.mod @@ -1,9 +1,7 @@ -module github.com/choopm/stdfx/examples/everything +module github.com/choopm/stdfx/examples/webserver go 1.23 -replace github.com/choopm/stdfx => ../../ - require ( github.com/choopm/stdfx v0.1.0 github.com/go-viper/mapstructure/v2 v2.2.1 @@ -18,14 +16,14 @@ require ( github.com/earthboundkid/versioninfo/v2 v2.24.1 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/samber/lo v1.47.0 // indirect github.com/samber/slog-common v0.18.1 // indirect - github.com/samber/slog-zerolog/v2 v2.7.2 // indirect + github.com/samber/slog-zerolog/v2 v2.7.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect diff --git a/examples/everything/go.sum b/examples/webserver/go.sum similarity index 76% rename from examples/everything/go.sum rename to examples/webserver/go.sum index 989ce4d..24a8960 100644 --- a/examples/everything/go.sum +++ b/examples/webserver/go.sum @@ -1,29 +1,22 @@ +github.com/choopm/stdfx v0.1.0 h1:KKl5eXJwxk98l4lkBJlzbqp716QsbNv/sABxbwJJMaI= +github.com/choopm/stdfx v0.1.0/go.mod h1:luiv/eXXvvtpghNwbCifhtKr9FGvCY3On+ZWRdOLPFk= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/earthboundkid/versioninfo/v2 v2.24.1 h1:SJTMHaoUx3GzjjnUO1QzP3ZXK6Ee/nbWyCm58eY3oUg= github.com/earthboundkid/versioninfo/v2 v2.24.1/go.mod h1:VcWEooDEuyUJnMfbdTh0uFN4cfEIg+kHMuWB2CDCLjw= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 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= @@ -31,9 +24,6 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= @@ -45,8 +35,8 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samber/slog-common v0.18.1 h1:c0EipD/nVY9HG5shgm/XAs67mgpWDMF+MmtptdJNCkQ= github.com/samber/slog-common v0.18.1/go.mod h1:QNZiNGKakvrfbJ2YglQXLCZauzkI9xZBjOhWFKS3IKk= -github.com/samber/slog-zerolog/v2 v2.7.2 h1:z2Flxz1igvyKDLqv4QjZSC6kEyB02emXL7u49R7Jxx0= -github.com/samber/slog-zerolog/v2 v2.7.2/go.mod h1:TMj08Lvcs2dSNOw03UZ01Uw7001vIOjsixD3S+V5ZOE= +github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY= +github.com/samber/slog-zerolog/v2 v2.7.3/go.mod h1:oWU7WHof4Xp8VguiNO02r1a4VzkgoOyOZhY5CuRke60= 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.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= @@ -59,8 +49,6 @@ 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.20.0-alpha.6 h1:f65Cr/+2qk4GfHC0xqT/isoupQppwN5+VLRztUGTDbY= github.com/spf13/viper v1.20.0-alpha.6/go.mod h1:CGBZzv0c9fOUASm6rfus4wdeIjR/04NOLq1P4KRhX3k= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= @@ -69,8 +57,6 @@ go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw= go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg= go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -85,8 +71,6 @@ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/examples/everything/server.go b/examples/webserver/server.go similarity index 99% rename from examples/everything/server.go rename to examples/webserver/server.go index 81b9e5e..45d32e1 100644 --- a/examples/everything/server.go +++ b/examples/webserver/server.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package everything +package webserver import ( "context" diff --git a/examples/everything/server.yaml b/examples/webserver/webserver.yaml similarity index 100% rename from examples/everything/server.yaml rename to examples/webserver/webserver.yaml diff --git a/go.mod b/go.mod index c3d6767..b30df35 100644 --- a/go.mod +++ b/go.mod @@ -2,16 +2,13 @@ module github.com/choopm/stdfx go 1.23 -replace github.com/choopm/stdfx/examples/everything => ./examples/everything - require ( - github.com/choopm/stdfx/examples/everything v0.0.0 github.com/creasty/defaults v1.8.0 github.com/earthboundkid/versioninfo/v2 v2.24.1 github.com/go-viper/mapstructure/v2 v2.2.1 github.com/rs/zerolog v1.33.0 - github.com/samber/slog-zap/v2 v2.6.1 - github.com/samber/slog-zerolog/v2 v2.7.2 + github.com/samber/slog-zap/v2 v2.6.2 + github.com/samber/slog-zerolog/v2 v2.7.3 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.20.0-alpha.6 @@ -27,7 +24,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 56b9ce1..553d608 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,9 @@ 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/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-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= 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= @@ -36,8 +37,8 @@ github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xl github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +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.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -48,10 +49,10 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samber/slog-common v0.18.1 h1:c0EipD/nVY9HG5shgm/XAs67mgpWDMF+MmtptdJNCkQ= github.com/samber/slog-common v0.18.1/go.mod h1:QNZiNGKakvrfbJ2YglQXLCZauzkI9xZBjOhWFKS3IKk= -github.com/samber/slog-zap/v2 v2.6.1 h1:qgh8RPiFNF28q5n0P08U9BxCQZnthFfi4DZs43rpBlM= -github.com/samber/slog-zap/v2 v2.6.1/go.mod h1:IzmWnT8qkhiaEDQ/JdDhkwh6paKLu+t34GdhHhI+Pi4= -github.com/samber/slog-zerolog/v2 v2.7.2 h1:z2Flxz1igvyKDLqv4QjZSC6kEyB02emXL7u49R7Jxx0= -github.com/samber/slog-zerolog/v2 v2.7.2/go.mod h1:TMj08Lvcs2dSNOw03UZ01Uw7001vIOjsixD3S+V5ZOE= +github.com/samber/slog-zap/v2 v2.6.2 h1:IPHgVQjBfEwqu7fBxSxvvl+/E4b7TqAu/eispdQdv9M= +github.com/samber/slog-zap/v2 v2.6.2/go.mod h1:bMOphuaRcThr+2X7vE4kFaqyr1lqGkc9Js95n9X6xaU= +github.com/samber/slog-zerolog/v2 v2.7.3 h1:/MkPDl/tJhijN2GvB1MWwBn2FU8RiL3rQ8gpXkQm2EY= +github.com/samber/slog-zerolog/v2 v2.7.3/go.mod h1:oWU7WHof4Xp8VguiNO02r1a4VzkgoOyOZhY5CuRke60= 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.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= diff --git a/stdfx_test.go b/stdfx_test.go index fa2cbbc..fe7eef6 100644 --- a/stdfx_test.go +++ b/stdfx_test.go @@ -18,18 +18,23 @@ package stdfx_test import ( "context" + "errors" + "fmt" "io" + "net" "net/http" "os" "path/filepath" + "strconv" "testing" "time" "github.com/choopm/stdfx" "github.com/choopm/stdfx/configfx" - "github.com/choopm/stdfx/examples/everything" "github.com/choopm/stdfx/globals" + "github.com/choopm/stdfx/loggingfx" "github.com/choopm/stdfx/loggingfx/zerologfx" + "github.com/go-viper/mapstructure/v2" "github.com/rs/zerolog" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" @@ -59,8 +64,8 @@ routes: content: example from tests ` -// TestExampleEverything tests the same things as examples/everything -func TestExampleEverything(t *testing.T) { +// TestExampleWebserver tests the same things as examples/webserver +func TestExampleWebserver(t *testing.T) { d, _ := t.Deadline() ctx, cancel := context.WithDeadline(context.Background(), d) defer cancel() @@ -83,14 +88,14 @@ func TestExampleEverything(t *testing.T) { // logging zerologfx.Module, fx.WithLogger(zerologfx.ToFx), - fx.Decorate(zerologfx.Decorator[everything.Config]), + fx.Decorate(zerologfx.Decorator[Config]), // viper configuration - fx.Provide(stdfx.ConfigFile[everything.Config]("server")), + fx.Provide(stdfx.ConfigFile[Config]("server")), // cobra commands fx.Provide( stdfx.AutoRegister(stdfx.VersionCommand(version)), - stdfx.AutoRegister(stdfx.ConfigCommand[everything.Config]), + stdfx.AutoRegister(stdfx.ConfigCommand[Config]), stdfx.AutoRegister(serverCommand), stdfx.AutoCommand, // add registered commands to root ), @@ -127,7 +132,7 @@ func TestExampleEverything(t *testing.T) { // serverCommand returns a *cobra.Command to start the server from a ConfigProvider func serverCommand( - configProvider configfx.Provider[everything.Config], + configProvider configfx.Provider[Config], logger *zerolog.Logger, ) *cobra.Command { cmd := &cobra.Command{ @@ -141,7 +146,7 @@ func serverCommand( } // create server instance - server, err := everything.NewServer(cfg, logger) + server, err := NewServer(cfg, logger) if err != nil { return err } @@ -153,3 +158,184 @@ func serverCommand( return cmd } + +// Config struct stores all config data. +type Config struct { + Logging loggingfx.Config `mapstructure:"log"` + + // Webserver defines the http server config + Webserver WebserverConfig `mapstructure:"webserver"` + + // Routes defines the webserver routes + Routes []*Route `mapstructure:"routes" default:"[]"` +} + +// Validate validates the Config +func (c *Config) Validate() error { + if err := c.Webserver.Validate(); err != nil { + return err + } + for i, route := range c.Routes { + if err := route.Validate(); err != nil { + return fmt.Errorf("route %d (%s): %s", i, route.Path, err) + } + } + + return nil +} + +// WebserverConfig holds the webserver config +type WebserverConfig struct { + // Host is the listening host to use when starting a server + Host string `mapstructure:"host" default:"0.0.0.0"` + + // Port is the listening port to use when starting a server + Port int `mapstructure:"port" default:"8080"` +} + +// Validate validates the HTTPConfig +func (c *WebserverConfig) Validate() error { + if len(c.Host) == 0 { + return fmt.Errorf("missing webserver.host") + } + if c.Port == 0 { + return fmt.Errorf("missing webserver.port") + } + + return nil +} + +// Route maps paths to content +type Route struct { + // Path is the webserver path to register + Path string `mapstructure:"path"` + + // Content is the content to deliver on this path + Content any `mapstructure:"content"` +} + +// Validate validates the config +func (c *Route) Validate() error { + if len(c.Path) == 0 { + return fmt.Errorf("missing path") + } + if c.Content == nil { + return fmt.Errorf("missing content") + } + + return nil +} + +// DecodeHook returns the composite decoding hook for decoding Config +func (c *Config) DecodeHook() mapstructure.DecodeHookFunc { + return mapstructure.ComposeDecodeHookFunc( + // knx group addresses listed as an example + // knxGroupAddressDecoder(), + ) +} + +// // knxGroupAddressDecoder returns a decoder for knx group addresses. +// // It parses strings of "1/2/3" into cemi.GroupAddr. +// func knxGroupAddressDecoder() mapstructure.DecodeHookFunc { +// // groupAddressDecoder returns a DecodeHookFunc that converts +// // string to cemi.GroupAddress or error. +// return func( +// f reflect.Type, +// t reflect.Type, +// data interface{}, +// ) (interface{}, error) { +// if f.Kind() != reflect.String { +// return data, nil +// } +// if t != reflect.TypeOf(cemi.GroupAddr(0)) { +// return data, nil +// } + +// // Convert it by parsing +// return cemi.NewGroupAddrString(data.(string)) +// } +// } + +// LoggingConfig returns the loggingfx.Config. +// This implements an interface to support log decorators. +func (c *Config) LoggingConfig() loggingfx.Config { + return c.Logging +} + +// Server state struct +type Server struct { + config *Config + log *zerolog.Logger +} + +// NewServer creates a new *Server instance using a provided config +func NewServer(config *Config, logger *zerolog.Logger) (*Server, error) { + // validate config + if config == nil { + return nil, errors.New("missing config") + } + if err := config.Validate(); err != nil { + return nil, fmt.Errorf("config: %s", err) + } + + // init logger if missing + if logger == nil { + l := zerolog.Nop() + logger = &l + } + + s := &Server{ + config: config, + log: logger, + } + + return s, nil +} + +// Start starts the server using ctx +func (s *Server) Start(ctx context.Context) error { + s.log.Trace(). + Interface("config", s.config). + Msg("initializing server") + + // register routes + for _, route := range s.config.Routes { + http.HandleFunc(route.Path, func(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, route.Content) + }) + } + + s.log.Trace(). + Msg("starting server") + g, ctx := errgroup.WithContext(ctx) + + // build and start webserver + addr := net.JoinHostPort(s.config.Webserver.Host, + strconv.Itoa(s.config.Webserver.Port), + ) + server := &http.Server{Addr: addr, Handler: nil} + // shutdown hook, registered before starting + context.AfterFunc(ctx, func() { + _ = server.Close() + }) + g.Go(func() error { + err := server.ListenAndServe() + if err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + + return nil + }) + + // wait for started tasks + s.log.Info(). + Str("addr", addr). + Msg("server is running") + if err := g.Wait(); err != nil && !errors.Is(err, context.Canceled) { + return err + } + + s.log.Info().Msg("server stopped") + + return nil +}