From 30163527284c7c796aec737f128b5f0256d737f7 Mon Sep 17 00:00:00 2001 From: Bastien Rigaud Date: Sun, 18 Feb 2024 13:53:10 +0100 Subject: [PATCH] feat: skeleton --- Makefile | 5 +- .air.toml => src/.air.toml | 6 +- src/cmd/main.go | 54 +++++++------- go.mod => src/go.mod | 2 +- go.sum => src/go.sum | 4 +- src/internal/config/config.go | 7 +- .../{entity => entities}/user/v1/user.go | 2 +- src/internal/handlers/grpc/server.go | 74 +++++++++++++++++++ .../grpc}/user/v1/init.go | 6 +- .../grpc}/user/v1/user.go | 6 +- .../handlers/grpc/user/v1/user_test.go | 1 + src/internal/handlers/interface.go | 9 +++ src/internal/server/user/v1/server.go | 30 -------- src/internal/service/datastore/interface.go | 4 +- .../service/datastore/planetscale/init.go | 2 +- .../service/datastore/planetscale/user.go | 4 +- src/internal/service/init.go | 4 +- src/internal/service/interface.go | 4 +- src/internal/service/user.go | 4 +- 19 files changed, 140 insertions(+), 88 deletions(-) rename .air.toml => src/.air.toml (90%) rename go.mod => src/go.mod (93%) rename go.sum => src/go.sum (96%) rename src/internal/{entity => entities}/user/v1/user.go (94%) create mode 100644 src/internal/handlers/grpc/server.go rename src/internal/{handler => handlers/grpc}/user/v1/init.go (67%) rename src/internal/{handler => handlers/grpc}/user/v1/user.go (89%) create mode 100644 src/internal/handlers/grpc/user/v1/user_test.go create mode 100644 src/internal/handlers/interface.go delete mode 100644 src/internal/server/user/v1/server.go diff --git a/Makefile b/Makefile index 5e74658..12cd031 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ run: - air -c .air.toml + cd src && air -c .air.toml + +update: + cd src && go mod tidy test: cd src/tests/integration && go test -v \ No newline at end of file diff --git a/.air.toml b/src/.air.toml similarity index 90% rename from .air.toml rename to src/.air.toml index bd680a2..ab9dc28 100644 --- a/.air.toml +++ b/src/.air.toml @@ -4,8 +4,8 @@ tmp_dir = "tmp" [build] args_bin = [] - bin = "./tmp/main" - cmd = "go build -o ./tmp/main src/cmd/main.go" + bin = "tmp/main" + cmd = "go build -o tmp/main cmd/main.go" delay = 1000 exclude_dir = ["assets", "tmp", "vendor", "testdata"] exclude_file = [] @@ -28,7 +28,7 @@ tmp_dir = "tmp" stop_on_error = false [color] - app = "" + app = "magenta" build = "yellow" main = "magenta" runner = "green" diff --git a/src/cmd/main.go b/src/cmd/main.go index 74d1c2a..a90eeba 100644 --- a/src/cmd/main.go +++ b/src/cmd/main.go @@ -2,59 +2,57 @@ package main import ( "context" - "errors" - "fmt" - "net/http" "os" "os/signal" "syscall" - "github.com/Golerplate/user-store-svc/src/internal/config" - handler_user_v1 "github.com/Golerplate/user-store-svc/src/internal/handler/user/v1" - server_user_v1 "github.com/Golerplate/user-store-svc/src/internal/server/user/v1" - "github.com/Golerplate/user-store-svc/src/internal/service" + "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" - serviceDatastore "github.com/Golerplate/user-store-svc/src/internal/service/datastore/planetscale" + "github.com/Golerplate/user-store-svc/internal/config" + handlers_grpc "github.com/Golerplate/user-store-svc/internal/handlers/grpc" + "github.com/Golerplate/user-store-svc/internal/service" + serviceDatastore "github.com/Golerplate/user-store-svc/internal/service/datastore/planetscale" ) func main() { ctx, cancel := context.WithCancel(context.Background()) - sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGTERM) - cfg := config.GetServiceConfig() + cfg, err := config.GetServiceConfig() + if err != nil { + panic(err) + } + + zerolog.SetGlobalLevel(zerolog.InfoLevel) userStoreServiceDatastore := serviceDatastore.NewPlanetScaleDatastore() userStoreService := service.NewUserStoreService(userStoreServiceDatastore) - userStoreServiceHandler := handler_user_v1.NewUserStoreServiceHandler(userStoreService) - grpcBuilder := server_user_v1.NewGRPCBuilder(userStoreServiceHandler) + grpcServer, err := handlers_grpc.NewServer(ctx, cfg.GRPCServerConfig, userStoreService) + if err != nil { + log.Fatal().Err(err). + Msg("main: unable to create gRPC server") + } - grpcServer := http.Server{ - Addr: fmt.Sprintf(":%d", cfg.GRPCServerConfig.Port), - Handler: h2c.NewHandler(grpcBuilder, &http2.Server{}), + if err := grpcServer.Setup(ctx); err != nil { + log.Fatal().Err(err). + Msg("main: unable to setup gRPC server") } - go func() { - if err := grpcServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatal().Err(err).Msg("unable to start grpc server") - } - }() + if err := grpcServer.Start(ctx); err != nil { + log.Fatal().Err(err). + Msg("main: unable to start gRPC server") + } <-sigs - - log.Info().Msg("caught SIGTERM, exiting") cancel() - if err := grpcServer.Shutdown(ctx); err != nil { - log.Error().Err(err).Msg("unable to stop grpc server") + if err := grpcServer.Stop(ctx); err != nil { + log.Fatal().Err(err). + Msg("main: unable to stop gRPC server") } - log.Info().Msg("work done; exiting") - os.Exit(0) } diff --git a/go.mod b/src/go.mod similarity index 93% rename from go.mod rename to src/go.mod index 7f8440b..3768dfb 100644 --- a/go.mod +++ b/src/go.mod @@ -3,7 +3,7 @@ module github.com/Golerplate/user-store-svc go 1.21.5 require ( - github.com/Golerplate/contracts v0.0.1 + github.com/Golerplate/contracts v0.0.2 github.com/Golerplate/pkg v0.0.2 github.com/bufbuild/connect-go v1.10.0 github.com/bufbuild/connect-grpcreflect-go v1.1.0 diff --git a/go.sum b/src/go.sum similarity index 96% rename from go.sum rename to src/go.sum index d20d8b9..7d752bb 100644 --- a/go.sum +++ b/src/go.sum @@ -1,5 +1,5 @@ -github.com/Golerplate/contracts v0.0.1 h1:OtKvpCKVQGTjLFbxYPBkHn/ZC5wQoaumfTlpNuvSmO4= -github.com/Golerplate/contracts v0.0.1/go.mod h1:ALtjMgMcSLE6wGcB2zGIWand81y0HsU+MIvn1mmBP+0= +github.com/Golerplate/contracts v0.0.2 h1:nII6q/QV2QjeTYw4g21G8eT2lzIA6ZXGFHKGQkGiL2k= +github.com/Golerplate/contracts v0.0.2/go.mod h1:ALtjMgMcSLE6wGcB2zGIWand81y0HsU+MIvn1mmBP+0= github.com/Golerplate/pkg v0.0.2 h1:b1T2Rky4BaJ5c9bHeh0cVII8M1LWcvKfzDJkGmT/G5w= github.com/Golerplate/pkg v0.0.2/go.mod h1:xj+tuGKV3MtOpy/B6SMBJ0EkbaXMaivufhce/SzwqRk= github.com/bufbuild/connect-go v1.10.0 h1:QAJ3G9A1OYQW2Jbk3DeoJbkCxuKArrvZgDt47mjdTbg= diff --git a/src/internal/config/config.go b/src/internal/config/config.go index 0d0d46b..96d0c02 100644 --- a/src/internal/config/config.go +++ b/src/internal/config/config.go @@ -3,7 +3,6 @@ package config import ( "github.com/Golerplate/pkg/grpc" "github.com/caarlos0/env/v8" - "github.com/rs/zerolog/log" ) type Config struct { @@ -15,11 +14,11 @@ type GeneralConfig struct { Environment string `env:"ENVIRONMENT" envDefault:"local"` } -func GetServiceConfig() *Config { +func GetServiceConfig() (*Config, error) { var cfg Config if err := env.Parse(&cfg); err != nil { - log.Fatal().Err(err).Msg("unable to build config") + return nil, err } - return &cfg + return &cfg, nil } diff --git a/src/internal/entity/user/v1/user.go b/src/internal/entities/user/v1/user.go similarity index 94% rename from src/internal/entity/user/v1/user.go rename to src/internal/entities/user/v1/user.go index 4102bb1..3286bbd 100644 --- a/src/internal/entity/user/v1/user.go +++ b/src/internal/entities/user/v1/user.go @@ -1,4 +1,4 @@ -package entity_user_v1 +package entities_user_v1 import "time" diff --git a/src/internal/handlers/grpc/server.go b/src/internal/handlers/grpc/server.go new file mode 100644 index 0000000..66c6a7d --- /dev/null +++ b/src/internal/handlers/grpc/server.go @@ -0,0 +1,74 @@ +package handlers_grpc + +import ( + "context" + "fmt" + "net/http" + + "github.com/Golerplate/contracts/generated/services/servicesconnect" + "github.com/Golerplate/contracts/generated/services/user/store/v1/storev1connect" + "github.com/Golerplate/pkg/grpc" + pkghandlers "github.com/Golerplate/pkg/grpc/handlers" + sharedmidlewares "github.com/Golerplate/pkg/grpc/interceptors" + "github.com/Golerplate/user-store-svc/internal/handlers" + handlers_grpc_user_v1 "github.com/Golerplate/user-store-svc/internal/handlers/grpc/user/v1" + "github.com/Golerplate/user-store-svc/internal/service" + connectgo "github.com/bufbuild/connect-go" + grpcreflect "github.com/bufbuild/connect-grpcreflect-go" + "github.com/rs/zerolog/log" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" +) + +type grpcServer struct { + grpcServer *http.Server + config grpc.GRPCServerConfig + service service.UserStoreService +} + +func NewServer(ctx context.Context, cfg grpc.GRPCServerConfig, service service.UserStoreService) (handlers.Server, error) { + return &grpcServer{ + config: cfg, + service: service, + }, nil +} + +func (s *grpcServer) Setup(ctx context.Context) error { + log.Info(). + Msg("handlers.grpc.grpcServer.Setup: Setting up gRPC server...") + + userStoreServiceHandler := handlers_grpc_user_v1.NewUserStoreServiceHandler(s.service) + + interceptors := connectgo.WithInterceptors(sharedmidlewares.ServerDefaultChain()...) + + reflector := grpcreflect.NewStaticReflector( + "services.user.store.v1.UserStoreSvc", "services.health.HealthService", + ) + + mux := http.NewServeMux() + mux.Handle(servicesconnect.NewHealthServiceHandler(pkghandlers.NewHealthHandler())) + mux.Handle(storev1connect.NewUserStoreSvcHandler(userStoreServiceHandler, interceptors)) + mux.Handle(grpcreflect.NewHandlerV1(reflector)) + mux.Handle(grpcreflect.NewHandlerV1Alpha(reflector)) + + s.grpcServer = &http.Server{ + Addr: fmt.Sprintf(":%d", s.config.Port), + Handler: h2c.NewHandler(mux, &http2.Server{}), + } + + return nil +} + +func (s *grpcServer) Start(ctx context.Context) error { + log.Info(). + Msg("handlers.grpc.grpcServer.Start: Starting gRPC server...") + + return s.grpcServer.ListenAndServe() +} + +func (s *grpcServer) Stop(ctx context.Context) error { + log.Info(). + Msg("handlers.grpc.grpcServer.Stop: Stopping gRPC server...") + + return s.grpcServer.Shutdown(ctx) +} diff --git a/src/internal/handler/user/v1/init.go b/src/internal/handlers/grpc/user/v1/init.go similarity index 67% rename from src/internal/handler/user/v1/init.go rename to src/internal/handlers/grpc/user/v1/init.go index b60a387..a147ffc 100644 --- a/src/internal/handler/user/v1/init.go +++ b/src/internal/handlers/grpc/user/v1/init.go @@ -1,15 +1,15 @@ -package handler_user_v1 +package handlers_grpc_user_v1 import ( "github.com/Golerplate/contracts/generated/services/user/store/v1/storev1connect" - "github.com/Golerplate/user-store-svc/src/internal/service" + "github.com/Golerplate/user-store-svc/internal/service" ) type handler struct { userStoreService service.UserStoreService } -func NewUserStoreServiceHandler(userStoreService service.UserStoreService) storev1connect.UserStoreServiceHandler { +func NewUserStoreServiceHandler(userStoreService service.UserStoreService) storev1connect.UserStoreSvcHandler { return &handler{ userStoreService: userStoreService, } diff --git a/src/internal/handler/user/v1/user.go b/src/internal/handlers/grpc/user/v1/user.go similarity index 89% rename from src/internal/handler/user/v1/user.go rename to src/internal/handlers/grpc/user/v1/user.go index 04d2f35..0bc22c1 100644 --- a/src/internal/handler/user/v1/user.go +++ b/src/internal/handlers/grpc/user/v1/user.go @@ -1,4 +1,4 @@ -package handler_user_v1 +package handlers_grpc_user_v1 import ( "context" @@ -6,7 +6,7 @@ import ( userv1 "github.com/Golerplate/contracts/generated/services/user/store/v1" "github.com/Golerplate/pkg/grpc" - entity_user_v1 "github.com/Golerplate/user-store-svc/src/internal/entity/user/v1" + entities_user_v1 "github.com/Golerplate/user-store-svc/internal/entities/user/v1" connectgo "github.com/bufbuild/connect-go" "github.com/golang/protobuf/ptypes/wrappers" "google.golang.org/protobuf/types/known/timestamppb" @@ -24,7 +24,7 @@ func (h *handler) CreateUser(ctx context.Context, c *connectgo.Request[userv1.Cr return nil, connectgo.NewError(connectgo.CodeInvalidArgument, errors.New("invalid password")) } - user, err := h.userStoreService.CreateUser(ctx, &entity_user_v1.CreateUserRequest{ + user, err := h.userStoreService.CreateUser(ctx, &entities_user_v1.CreateUserRequest{ Username: c.Msg.GetUsername().GetValue(), Email: c.Msg.GetEmail().GetValue(), Password: c.Msg.GetPassword().GetValue(), diff --git a/src/internal/handlers/grpc/user/v1/user_test.go b/src/internal/handlers/grpc/user/v1/user_test.go new file mode 100644 index 0000000..cb62226 --- /dev/null +++ b/src/internal/handlers/grpc/user/v1/user_test.go @@ -0,0 +1 @@ +package handlers_grpc_user_v1 diff --git a/src/internal/handlers/interface.go b/src/internal/handlers/interface.go new file mode 100644 index 0000000..1a48360 --- /dev/null +++ b/src/internal/handlers/interface.go @@ -0,0 +1,9 @@ +package handlers + +import "context" + +type Server interface { + Setup(context.Context) error + Start(context.Context) error + Stop(context.Context) error +} diff --git a/src/internal/server/user/v1/server.go b/src/internal/server/user/v1/server.go deleted file mode 100644 index 0c9f13a..0000000 --- a/src/internal/server/user/v1/server.go +++ /dev/null @@ -1,30 +0,0 @@ -package server_user_v1 - -import ( - "net/http" - - "github.com/Golerplate/contracts/generated/services/servicesconnect" - "github.com/Golerplate/contracts/generated/services/user/store/v1/storev1connect" - handlers "github.com/Golerplate/pkg/grpc/handlers" - sharedmidlewares "github.com/Golerplate/pkg/grpc/interceptors" - connectgo "github.com/bufbuild/connect-go" - grpcreflect "github.com/bufbuild/connect-grpcreflect-go" -) - -func NewGRPCBuilder( - userStoreServiceHandler storev1connect.UserStoreServiceHandler, -) *http.ServeMux { - interceptors := connectgo.WithInterceptors(sharedmidlewares.ServerDefaultChain()...) - - reflector := grpcreflect.NewStaticReflector( - "services.user.store.v1.UserStoreSvc", "services.health.HealthService", - ) - - mux := http.NewServeMux() - mux.Handle(servicesconnect.NewHealthServiceHandler(handlers.NewHealthHandler())) - mux.Handle(storev1connect.NewUserStoreServiceHandler(userStoreServiceHandler, interceptors)) - mux.Handle(grpcreflect.NewHandlerV1(reflector)) - mux.Handle(grpcreflect.NewHandlerV1Alpha(reflector)) - - return mux -} diff --git a/src/internal/service/datastore/interface.go b/src/internal/service/datastore/interface.go index 7aef62a..5c4dd14 100644 --- a/src/internal/service/datastore/interface.go +++ b/src/internal/service/datastore/interface.go @@ -3,9 +3,9 @@ package datastore import ( "context" - entity_user_v1 "github.com/Golerplate/user-store-svc/src/internal/entity/user/v1" + entities_user_v1 "github.com/Golerplate/user-store-svc/internal/entities/user/v1" ) type UserStoreServiceDatastore interface { - CreateUser(ctx context.Context, req *entity_user_v1.CreateUserRequest) (*entity_user_v1.User, error) + CreateUser(ctx context.Context, req *entities_user_v1.CreateUserRequest) (*entities_user_v1.User, error) } diff --git a/src/internal/service/datastore/planetscale/init.go b/src/internal/service/datastore/planetscale/init.go index c60828b..6f28e0a 100644 --- a/src/internal/service/datastore/planetscale/init.go +++ b/src/internal/service/datastore/planetscale/init.go @@ -1,7 +1,7 @@ package planetscale import ( - "github.com/Golerplate/user-store-svc/src/internal/service/datastore" + "github.com/Golerplate/user-store-svc/internal/service/datastore" _ "github.com/go-sql-driver/mysql" ) diff --git a/src/internal/service/datastore/planetscale/user.go b/src/internal/service/datastore/planetscale/user.go index eb88386..0b300c9 100644 --- a/src/internal/service/datastore/planetscale/user.go +++ b/src/internal/service/datastore/planetscale/user.go @@ -3,9 +3,9 @@ package planetscale import ( "context" - entity_user_v1 "github.com/Golerplate/user-store-svc/src/internal/entity/user/v1" + entities_user_v1 "github.com/Golerplate/user-store-svc/internal/entities/user/v1" ) -func (d *dbClient) CreateUser(ctx context.Context, req *entity_user_v1.CreateUserRequest) (*entity_user_v1.User, error) { +func (d *dbClient) CreateUser(ctx context.Context, req *entities_user_v1.CreateUserRequest) (*entities_user_v1.User, error) { return nil, nil } diff --git a/src/internal/service/init.go b/src/internal/service/init.go index b6f73c3..d3588e8 100644 --- a/src/internal/service/init.go +++ b/src/internal/service/init.go @@ -1,8 +1,6 @@ package service -import ( - "github.com/Golerplate/user-store-svc/src/internal/service/datastore" -) +import "github.com/Golerplate/user-store-svc/internal/service/datastore" type service struct { store datastore.UserStoreServiceDatastore diff --git a/src/internal/service/interface.go b/src/internal/service/interface.go index 889ceef..3a8c720 100644 --- a/src/internal/service/interface.go +++ b/src/internal/service/interface.go @@ -3,9 +3,9 @@ package service import ( "context" - entity_user_v1 "github.com/Golerplate/user-store-svc/src/internal/entity/user/v1" + entities_user_v1 "github.com/Golerplate/user-store-svc/internal/entities/user/v1" ) type UserStoreService interface { - CreateUser(ctx context.Context, req *entity_user_v1.CreateUserRequest) (*entity_user_v1.User, error) + CreateUser(ctx context.Context, req *entities_user_v1.CreateUserRequest) (*entities_user_v1.User, error) } diff --git a/src/internal/service/user.go b/src/internal/service/user.go index e4dbedf..9f11b1e 100644 --- a/src/internal/service/user.go +++ b/src/internal/service/user.go @@ -3,9 +3,9 @@ package service import ( "context" - entity_user_v1 "github.com/Golerplate/user-store-svc/src/internal/entity/user/v1" + entities_user_v1 "github.com/Golerplate/user-store-svc/internal/entities/user/v1" ) -func (s *service) CreateUser(ctx context.Context, req *entity_user_v1.CreateUserRequest) (*entity_user_v1.User, error) { +func (s *service) CreateUser(ctx context.Context, req *entities_user_v1.CreateUserRequest) (*entities_user_v1.User, error) { return s.store.CreateUser(ctx, req) }