From 1523438aff652bc01126a2061269b9411712db42 Mon Sep 17 00:00:00 2001 From: Alexandre Negrel Date: Wed, 10 Jan 2024 10:55:00 +0100 Subject: [PATCH] add wire for DI --- .gitignore | 3 +++ Makefile | 5 ++++- cmd/server/app.go | 22 ++++++++++++++++++++ cmd/server/config.go | 15 ++++++++++++++ cmd/server/echo.go | 24 ++++++++++++++++++++++ cmd/server/loggers.go | 39 ++++++++++++++++++++++++++++++++++++ cmd/server/main.go | 40 +++---------------------------------- cmd/server/wire.go | 21 +++++++++++++++++++ flake.nix | 1 + go.mod | 1 + go.sum | 9 +++++++++ internal/config/postgres.go | 4 ++-- internal/config/server.go | 1 + 13 files changed, 145 insertions(+), 40 deletions(-) create mode 100644 cmd/server/app.go create mode 100644 cmd/server/config.go create mode 100644 cmd/server/echo.go create mode 100644 cmd/server/loggers.go create mode 100644 cmd/server/wire.go diff --git a/.gitignore b/.gitignore index e77308f..803a4a9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ .config/genenv.local.sh node_modules/ + +# Generated go files. +_gen.go diff --git a/Makefile b/Makefile index b31fec2..f4f4a20 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,12 @@ include $(repository_root)/variables.mk GENENV_FILE ?= ./config/genenv.local.sh .PHONY: start -start: dev/start +start: dev/start ./cmd/server/wire_gen.go source ./.env && go run ./cmd/server |& bunyan +./cmd/server/wire_gen.go: + wire ./... + .PHONY: dev/start dev/start: .env source ./.env && $(DOCKER_COMPOSE) up --wait -d diff --git a/cmd/server/app.go b/cmd/server/app.go new file mode 100644 index 0000000..5380777 --- /dev/null +++ b/cmd/server/app.go @@ -0,0 +1,22 @@ +package main + +import ( + "github.com/labstack/echo/v4" + "github.com/prismelabs/prismeanalytics/internal/config" + "github.com/prismelabs/prismeanalytics/internal/log" +) + +type App struct { + cfg config.Config + echo *echo.Echo + logger log.Logger +} + +// ProvideApp is a wire provider for App. +func ProvideApp(cfg config.Config, e *echo.Echo, logger StandardLogger) App { + return App{ + cfg: cfg, + echo: e, + logger: logger.Logger, + } +} diff --git a/cmd/server/config.go b/cmd/server/config.go new file mode 100644 index 0000000..3698457 --- /dev/null +++ b/cmd/server/config.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/prismelabs/prismeanalytics/internal/config" + "github.com/prismelabs/prismeanalytics/internal/log" +) + +// ProvideConfig is a wire provider config.Config. +func ProvideConfig(logger log.Logger) config.Config { + logger.Info().Msg("loading configuration...") + cfg := config.FromEnv() + logger.Info().Any("config", cfg).Msg("configuration successfully loaded.") + + return cfg +} diff --git a/cmd/server/echo.go b/cmd/server/echo.go new file mode 100644 index 0000000..64c2ef8 --- /dev/null +++ b/cmd/server/echo.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/labstack/echo/v4" + "github.com/prismelabs/prismeanalytics/internal/config" + "github.com/prismelabs/prismeanalytics/internal/middlewares" +) + +// ProvideEcho is a wire provider for echo.Echo. It setup middleware and handlers. +func ProvideEcho(cfg config.Config, accessLogger AccessLogger) *echo.Echo { + e := echo.New() + if cfg.Server.TrustProxy { + e.IPExtractor = echo.ExtractIPFromXFFHeader() + } else { + e.IPExtractor = echo.ExtractIPDirect() + } + e.HideBanner = true + e.HidePort = true + + e.Use(middlewares.RequestId(cfg.Server)) + e.Use(middlewares.AccessLog(accessLogger.Logger)) + + return e +} diff --git a/cmd/server/loggers.go b/cmd/server/loggers.go new file mode 100644 index 0000000..8100c0e --- /dev/null +++ b/cmd/server/loggers.go @@ -0,0 +1,39 @@ +package main + +import ( + "os" + + "github.com/prismelabs/prismeanalytics/internal/config" + "github.com/prismelabs/prismeanalytics/internal/log" +) + +// StandardLogger is the application logger. +type StandardLogger struct { + log.Logger +} + +// ProvideStandardLogger is a wire provider for StandardLogger. +func ProvideStandardLogger(cfg config.Config) StandardLogger { + logger := log.NewLogger("app", os.Stderr, cfg.Server.Debug) + log.TestLoggers(logger) + + return StandardLogger{logger} +} + +type AccessLogger struct { + log.Logger +} + +// ProvideAccessLogger is a wire provider for AccessLogger. +func ProvideAccessLogger(cfg config.Config, logger StandardLogger) AccessLogger { + // Open access log file. + accessLogFile, err := os.OpenFile(cfg.Server.AccessLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm) + if err != nil { + logger.Panic().Err(err).Msgf("failed to open access log file: %v", cfg.Server.AccessLog) + } + + accessLogger := log.NewLogger("access_log", accessLogFile, cfg.Server.Debug) + log.TestLoggers(accessLogger) + + return AccessLogger{accessLogger} +} diff --git a/cmd/server/main.go b/cmd/server/main.go index b66e5ba..b3436b3 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,13 +2,9 @@ package main import ( "fmt" - "net/http" "os" - "github.com/labstack/echo/v4" - "github.com/prismelabs/prismeanalytics/internal/config" "github.com/prismelabs/prismeanalytics/internal/log" - "github.com/prismelabs/prismeanalytics/internal/middlewares" ) func main() { @@ -16,39 +12,9 @@ func main() { logger := log.NewLogger("bootstrap", os.Stderr, true) log.TestLoggers(logger) - logger.Info().Msg("loading configuration...") - cfg := config.FromEnv() - logger.Info().Any("config", cfg).Msg("configuration successfully loaded.") + app := initialize(logger) - // Application logger. - logger = log.NewLogger("app", os.Stderr, cfg.Server.Debug) - log.TestLoggers(logger) - - // Open access log file. - accessLogFile, err := os.OpenFile(cfg.Server.AccessLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, os.ModePerm) - if err != nil { - logger.Panic().Err(err).Msgf("failed to open access log file: %v", cfg.Server.AccessLog) - } - accessLogger := log.NewLogger("access_log", accessLogFile, cfg.Server.Debug) - log.TestLoggers(logger) - - e := echo.New() - if cfg.Server.TrustProxy { - e.IPExtractor = echo.ExtractIPFromXFFHeader() - } else { - e.IPExtractor = echo.ExtractIPDirect() - } - e.HideBanner = true - e.HidePort = true - - e.Use(middlewares.RequestId(cfg.Server)) - e.Use(middlewares.AccessLog(accessLogger)) - - e.GET("/", func(c echo.Context) error { - return c.String(http.StatusOK, "Hello, World!") - }) - - socket := "0.0.0.0:" + fmt.Sprint(cfg.Server.Port) + socket := "0.0.0.0:" + fmt.Sprint(app.cfg.Server.Port) logger.Info().Msgf("start listening for incoming requests on http://%v", socket) - logger.Panic().Err(e.Start(socket)).Send() + logger.Panic().Err(app.echo.Start(socket)).Send() } diff --git a/cmd/server/wire.go b/cmd/server/wire.go new file mode 100644 index 0000000..d628e0e --- /dev/null +++ b/cmd/server/wire.go @@ -0,0 +1,21 @@ +//go:build wireinject +// +build wireinject + +package main + +import ( + "github.com/google/wire" + "github.com/prismelabs/prismeanalytics/internal/log" + "github.com/prismelabs/prismeanalytics/internal/middlewares" +) + +func initialize(logger log.Logger) App { + wire.Build( + ProvideConfig, + ProvideStandardLogger, + ProvideAccessLogger, + ProvideEcho, + ProvideApp, + ) + return App{} +} diff --git a/flake.nix b/flake.nix index 82d5f69..e133ea0 100644 --- a/flake.nix +++ b/flake.nix @@ -21,6 +21,7 @@ go gopls golangci-lint + wire bunyan-rs entr bun diff --git a/go.mod b/go.mod index 3fc8e20..f5d45c8 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/golang-migrate/migrate/v4 v4.17.0 github.com/google/uuid v1.5.0 + github.com/google/wire v0.5.0 github.com/labstack/echo/v4 v4.11.4 github.com/rs/zerolog v1.31.0 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 5aa5163..78c471e 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,12 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/golang-migrate/migrate/v4 v4.17.0 h1:rd40H3QXU0AA4IoLllFcEAEo9dYKRHYND2gB4p7xcaU= github.com/golang-migrate/migrate/v4 v4.17.0/go.mod h1:+Cp2mtLP4/aXDTKb9wmXYitdrNx2HGs45rbWAo6OsKM= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= +github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -53,18 +57,23 @@ github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/config/postgres.go b/internal/config/postgres.go index e73d3f0..8846cce 100644 --- a/internal/config/postgres.go +++ b/internal/config/postgres.go @@ -1,11 +1,11 @@ package config -// Postgres connection options. +// Postgres related options. type Postgres struct { Url SecretString } -// PostgresFromEnv loads postgres config from environment variables. +// PostgresFromEnv loads postgres related options from environment variables. // This function panics if required environment variables are missing. func PostgresFromEnv() Postgres { return Postgres{ diff --git a/internal/config/server.go b/internal/config/server.go index a1298a1..445dd64 100644 --- a/internal/config/server.go +++ b/internal/config/server.go @@ -12,6 +12,7 @@ type Server struct { TrustProxy bool } +// ServerFromEnv loads server related options from environment variables. func ServerFromEnv() Server { return Server{ AccessLog: getEnvOrDefault("PRISME_ACCESS_LOG", "/dev/stdout"),