119 lines
2.7 KiB
Go
119 lines
2.7 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"os/signal"
|
||
|
|
"syscall"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/dnoulet/go-first/internal/config"
|
||
|
|
"github.com/dnoulet/go-first/internal/handler"
|
||
|
|
"github.com/dnoulet/go-first/internal/middleware"
|
||
|
|
"github.com/dnoulet/go-first/internal/service"
|
||
|
|
"github.com/gin-gonic/gin"
|
||
|
|
"github.com/joho/godotenv"
|
||
|
|
"github.com/rs/zerolog"
|
||
|
|
"github.com/rs/zerolog/log"
|
||
|
|
)
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
if err := godotenv.Load(); err != nil {
|
||
|
|
log.Info().Msg("No .env file found, using config.yaml")
|
||
|
|
}
|
||
|
|
|
||
|
|
cfg, err := config.Load("config.yaml")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal().Err(err).Msg("Failed to load config")
|
||
|
|
}
|
||
|
|
|
||
|
|
setupLogging(cfg.Logging)
|
||
|
|
|
||
|
|
if cfg.Server.Mode == "release" {
|
||
|
|
gin.SetMode(gin.ReleaseMode)
|
||
|
|
}
|
||
|
|
|
||
|
|
router := setupRouter(cfg)
|
||
|
|
|
||
|
|
srv := &http.Server{
|
||
|
|
Addr: cfg.Server.Address(),
|
||
|
|
Handler: router,
|
||
|
|
ReadTimeout: cfg.Server.ReadTimeoutDuration(),
|
||
|
|
WriteTimeout: cfg.Server.WriteTimeoutDuration(),
|
||
|
|
IdleTimeout: cfg.Server.IdleTimeoutDuration(),
|
||
|
|
}
|
||
|
|
|
||
|
|
go func() {
|
||
|
|
log.Info().Str("address", cfg.Server.Address()).Msg("Starting server")
|
||
|
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||
|
|
log.Fatal().Err(err).Msg("Failed to start server")
|
||
|
|
}
|
||
|
|
}()
|
||
|
|
|
||
|
|
quit := make(chan os.Signal, 1)
|
||
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||
|
|
<-quit
|
||
|
|
|
||
|
|
log.Info().Msg("Shutting down server...")
|
||
|
|
|
||
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||
|
|
defer cancel()
|
||
|
|
|
||
|
|
if err := srv.Shutdown(ctx); err != nil {
|
||
|
|
log.Fatal().Err(err).Msg("Server forced to shutdown")
|
||
|
|
}
|
||
|
|
|
||
|
|
log.Info().Msg("Server exited")
|
||
|
|
}
|
||
|
|
|
||
|
|
func setupLogging(cfg config.LoggingConfig) {
|
||
|
|
level, err := zerolog.ParseLevel(cfg.Level)
|
||
|
|
if err != nil {
|
||
|
|
level = zerolog.InfoLevel
|
||
|
|
}
|
||
|
|
zerolog.SetGlobalLevel(level)
|
||
|
|
|
||
|
|
if cfg.Format == "console" || cfg.Output == "stdout" {
|
||
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func setupRouter(cfg *config.Config) *gin.Engine {
|
||
|
|
router := gin.New()
|
||
|
|
|
||
|
|
router.Use(middleware.Recovery())
|
||
|
|
router.Use(middleware.Logger())
|
||
|
|
router.Use(middleware.SecurityHeaders())
|
||
|
|
router.Use(middleware.CORS(cfg.CORS.AllowedOrigins))
|
||
|
|
|
||
|
|
skillService := service.NewSkillService()
|
||
|
|
projectService := service.NewProjectService()
|
||
|
|
experienceService := service.NewExperienceService()
|
||
|
|
serviceService := service.NewServiceService()
|
||
|
|
emailService := service.NewMockEmailService()
|
||
|
|
contactService := service.NewContactService(emailService)
|
||
|
|
|
||
|
|
h := handler.NewHandler(
|
||
|
|
skillService,
|
||
|
|
projectService,
|
||
|
|
experienceService,
|
||
|
|
serviceService,
|
||
|
|
contactService,
|
||
|
|
)
|
||
|
|
|
||
|
|
h.RegisterRoutes(router)
|
||
|
|
|
||
|
|
router.NoRoute(func(c *gin.Context) {
|
||
|
|
c.JSON(404, gin.H{
|
||
|
|
"success": false,
|
||
|
|
"error": gin.H{
|
||
|
|
"code": "NOT_FOUND",
|
||
|
|
"message": "Route not found",
|
||
|
|
},
|
||
|
|
})
|
||
|
|
})
|
||
|
|
|
||
|
|
return router
|
||
|
|
}
|