package app import ( "context" "fmt" "net" "net/http" "os" "time" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/reflection" "route256/loms/internal/app/server" ordersRepository "route256/loms/internal/domain/repository/orders" stocksRepository "route256/loms/internal/domain/repository/stocks" "route256/loms/internal/domain/service" "route256/loms/internal/infra/config" mw "route256/loms/internal/infra/grpc/middleware" pb "route256/pkg/api/loms/v1" ) type App struct { config *config.Config controller *server.Server } func NewApp(configPath string) (*App, error) { c, err := config.LoadConfig(configPath) if err != nil { return nil, fmt.Errorf("unable to load config: %w", err) } log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) zerolog.SetGlobalLevel(zerolog.InfoLevel) if c.Service.LogLevel != "" { level, logErr := zerolog.ParseLevel(c.Service.LogLevel) if logErr != nil { return nil, fmt.Errorf("unknown log level `%s` provided: %w", c.Service.LogLevel, logErr) } zerolog.SetGlobalLevel(level) } log.WithLevel(zerolog.GlobalLevel()).Msgf("using logging level=`%s`", zerolog.GlobalLevel().String()) stockRepo, err := stocksRepository.NewInMemoryRepository(100) if err != nil { return nil, fmt.Errorf("stocksRepository.NewInMemoryRepository: %w", err) } orderRepo := ordersRepository.NewInMemoryRepository(100) service := service.NewLomsService(orderRepo, stockRepo) controller := server.NewServer(service) app := &App{ config: c, controller: controller, } return app, nil } func (app *App) ListenAndServe() error { grpcAddr := fmt.Sprintf("%s:%s", app.config.Service.Host, app.config.Service.GRPCPort) l, err := net.Listen("tcp", grpcAddr) if err != nil { return err } grpcServer := grpc.NewServer( grpc.ChainUnaryInterceptor( mw.Logging, mw.Validate, ), ) reflection.Register(grpcServer) pb.RegisterLOMSServer(grpcServer, app.controller) go func() { if err = grpcServer.Serve(l); err != nil { log.Fatal().Msgf("failed to serve: %v", err) } }() log.Info().Msgf("Serving grpc loms at grpc://%s", l.Addr()) // Setup HTTP gateway conn, err := grpc.NewClient( grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { return fmt.Errorf("grpc.NewClient: %w", err) } gwmux := runtime.NewServeMux() if err = pb.RegisterLOMSHandler(context.Background(), gwmux, conn); err != nil { return fmt.Errorf("pb.RegisterLOMSHandler: %w", err) } gwServer := &http.Server{ Addr: fmt.Sprintf("%s:%s", app.config.Service.Host, app.config.Service.HTTPPort), Handler: gwmux, ReadTimeout: 10 * time.Second, } log.Info().Msgf("Serving http loms at http://%s", gwServer.Addr) return gwServer.ListenAndServe() }