// startGRPC todo: add docs
func (a *App) startGRPC(ctx context.Context) error {
const op = "app.startGRPC"
logger := zerolog.Ctx(ctx).With().
Str("op", op).
Int("port", a.cfg.ServerGRPC.Port).
Logger()
// Initializing all repositories
imagesRepo := repository.NewImagesRepositoryV1(a.pgpool)
// Initialization all services
imagesFileService := file.NewServiceV1(imagesRepo)
imagesWebService := web.NewServiceV1(imagesRepo)
// Initialization all handlers
imagesHandler := grpc2.NewImageHandlersGRPCV1(imagesFileService, imagesWebService)
serverOptions := []grpc.ServerOption{
grpc.MaxRecvMsgSize(a.cfg.ServerGRPC.MaxRecvMsgSize),
grpc.MaxSendMsgSize(a.cfg.ServerGRPC.MaxSendMsgSize),
grpc.MaxConcurrentStreams(uint32(a.cfg.ServerGRPC.MaxConcurrentStreams)),
grpc.KeepaliveParams(keepalive.ServerParameters{
Time: a.cfg.ServerGRPC.KeepAliveTime,
Timeout: a.cfg.ServerGRPC.KeepAliveTimeout,
}),
grpc.ConnectionTimeout(a.cfg.ServerGRPC.MaxConnectionAge + a.cfg.ServerGRPC.MaxConnectionAgeGrace),
grpc.StatsHandler(otelgrpc.NewServerHandler()),
}
a.gRPCServer = grpc.NewServer(serverOptions...)
pb.RegisterImagesServiceV1Server(a.gRPCServer, imagesHandler)
if a.cfg.ServerGRPC.EnableReflection {
reflection.Register(a.gRPCServer)
}
// todo:
//if a.cfg.ServerGRPC.EnableHealthCheck {
// healthServer := health.NewServer()
// healthpb.RegisterHealthServer(a.gRPCServer, healthServer)
// healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
//}
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", a.cfg.ServerGRPC.Port))
if err != nil {
logger.Fatal().Err(err).Msg("failed to create listener gRPC")
return fmt.Errorf("%s: %w", op, err)
}
go func() {
logger.Info().Msg("starting gRPC server")
if err = a.gRPCServer.Serve(listener); err != nil {
logger.Fatal().Err(err).Msg("failed to server gRPC")
}
}()
return nil
}
// startHTTP todo: add docs
func (a *App) startHTTP(ctx context.Context) error {
const op = "app.startHTTP"
logger := zerolog.Ctx(ctx).With().
Str("op", op).
Int("port", a.cfg.ServerHTTP.Port).
Dur("read-timeout", a.cfg.ServerHTTP.ReadTimeout).
Dur("write-timeout", a.cfg.ServerHTTP.WriteTimeout).
Dur("idle-timeout", a.cfg.ServerHTTP.IdleTimeout).
Logger()
conn, err := a.createGRPCConn(fmt.Sprintf("localhost:%d", a.cfg.ServerGRPC.Port))
if err != nil {
logger.Fatal().Err(err).Msg("failed to create gRPC connection")
return fmt.Errorf("%s: %w", op, err)
}
handler := imagesHTTP.NewImagesHandlersHTTP(pb.NewImagesServiceV1Client(conn))
router := echo.New()
router.HTTPErrorHandler = func(err error, c echo.Context) {
var he *echo.HTTPError
if errors.As(err, &he) && he.Code == http.StatusNotFound {
_ = respond.NotFound(c, nil, nil)
return
}
router.DefaultHTTPErrorHandler(err, c)
}
if a.cfg.ServerHTTP.EnableCORS {
router.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: a.cfg.ServerHTTP.CORSAllowedOrigins,
AllowMethods: a.cfg.ServerHTTP.CORSAllowedMethods,
AllowHeaders: a.cfg.ServerHTTP.CORSAllowedHeaders,
}))
}
if a.cfg.ServerHTTP.EnableCompression {
router.Use(middleware.Gzip())
}
if a.cfg.ServerHTTP.EnableRequestLogging {
router.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{
LogURI: true,
LogStatus: true,
LogMethod: true,
LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error {
logger.Info().
Str("method", v.Method).
Str("uri", v.URI).
Int("status", v.Status).
Msg("request")
return nil
},
}))
}
if a.cfg.ServerHTTP.EnableResponseLogging {
router.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: `{"time":"${time_rfc3339_nano}","method":"${method}","uri":"${uri}","status":${status},"latency":${latency},"latency_human":"${latency_human}"}` + "\n",
Output: logger,
}))
}
api := router.Group("/api")
v1 := api.Group("/v1")
imagesRouter := v1.Group("/images")
handler.LoadHandlers(imagesRouter)
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", a.cfg.ServerHTTP.Port))
if err != nil {
logger.Fatal().Err(err).Msg("failed to create listener")
return fmt.Errorf("failed to create listener: %w", err)
}
a.httpServer = &http.Server{
Handler: router,
ReadTimeout: a.cfg.ServerHTTP.ReadTimeout,
WriteTimeout: a.cfg.ServerHTTP.WriteTimeout,
IdleTimeout: a.cfg.ServerHTTP.IdleTimeout,
MaxHeaderBytes: a.cfg.ServerHTTP.MaxHeaderBytes,
}
go func() {
logger.Info().Msg("start http successfully")
if err = a.httpServer.Serve(listener); err != nil {
logger.Fatal().Err(err).Msg("failed to start HTTP")
}
}()
return nil
}