package router import ( "fmt" "net/http" "os" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/go-playground/validator/v10" "github.com/iliadenisov/galaxy/internal/controller" "github.com/iliadenisov/galaxy/internal/router/handler" ) const ( ISO8601 = "2006-01-02 15:04:05.0 -07:00" ) func initConfig() func(*controller.Param) { return func(p *controller.Param) { p.StoragePath = os.Getenv("STORAGE_PATH") } } type Router struct { r *gin.Engine executor handler.CommandExecutor } func (r Router) Run() error { return r.r.Run() } func NewRouter() Router { return NewRouterExecutor(handler.ExecuteCommand) } func NewRouterExecutor(executor handler.CommandExecutor) Router { return Router{r: setupRouter(initConfig(), executor)} } func setupRouter(config controller.Configurer, executor handler.CommandExecutor) *gin.Engine { gin.SetMode(gin.ReleaseMode) r := gin.New() // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. r.Use(gin.LoggerWithFormatter(logFormatter)) // Recovery middleware recovers from any panics and writes a 500 if there was one. r.Use(gin.CustomRecovery(recoveryHandler)) if v, ok := binding.Validator.Engine().(*validator.Validate); ok { v.RegisterValidation("notblank", notBlankStringValidator) } groupV1 := r.Group("/api/v1") groupV1.GET("/status", func(ctx *gin.Context) { handler.StatusHandler(ctx, config) }) groupV1.POST("/init", func(ctx *gin.Context) { handler.InitHandler(ctx, config) }) groupV1.PUT("/command", LimitMiddleware(1), func(ctx *gin.Context) { handler.CommandHandler(ctx, config, executor) }) return r } func logFormatter(param gin.LogFormatterParams) string { return fmt.Sprintf("[%s] \"%s %s %s %d %s\"\n", param.TimeStamp.Format(ISO8601), param.Method, param.Path, param.Request.Proto, param.StatusCode, param.Latency, ) } func recoveryHandler(c *gin.Context, recovered any) { if err, ok := recovered.(string); ok { fmt.Fprintf(os.Stderr, "recovered: %s", err) } c.AbortWithStatus(http.StatusInternalServerError) }