package main import ( "fmt" "os" "time" "github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3filter" "github.com/labstack/echo-contrib/echoprometheus" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" oapiMiddleware "github.com/oapi-codegen/echo-middleware" "github.com/spf13/afero" "github.com/wader/gormstore/v2" "gorm.io/driver/postgres" "gorm.io/gorm" "gitrepo.ru/neonxp/nquest/api" appmiddleware "gitrepo.ru/neonxp/nquest/pkg/contextlib" "gitrepo.ru/neonxp/nquest/pkg/controller" "gitrepo.ru/neonxp/nquest/pkg/models" "gitrepo.ru/neonxp/nquest/pkg/service" ) var Version = "dev" func main() { cfg, err := GetConfig() if err != nil { fmt.Fprintf(os.Stderr, "Error loading config\n: %s", err) os.Exit(1) } db, err := gorm.Open(postgres.Open(cfg.DSN()), &gorm.Config{}) if err != nil { fmt.Fprintf(os.Stderr, "Error DB connection\n: %s", err) os.Exit(1) } if err := db.AutoMigrate( &models.User{}, &models.Game{}, &models.GameCursor{}, &models.Task{}, &models.Code{}, &models.File{}, ); err != nil { fmt.Fprintf(os.Stderr, "Error DB migration\n: %s", err) os.Exit(1) } storageFs := afero.NewOsFs() storage := afero.NewBasePathFs(storageFs, "store") // --[ Services ]-- userService := service.NewUser(db) gameService := service.NewGame(db) engineService := service.NewEngine(db) uploadService := service.NewFile(db, storage) // --[ HTTP server ]-- e := echo.New() e.Debug = true store := gormstore.New(db, []byte(cfg.Secret)) quit := make(chan struct{}) defer func() { close(quit) }() go store.PeriodicCleanup(12*time.Hour, quit) swagger, err := api.GetSwagger() if err != nil { fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err) os.Exit(1) } swagger.Servers = []*openapi3.Server{{URL: "/api", Description: "Needed to match path"}} e.Use( middleware.Recover(), middleware.RequestID(), session.Middleware(store), middleware.Logger(), middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20)), middleware.Gzip(), echoprometheus.NewMiddleware("nquest"), appmiddleware.User(userService), ) // --[ Router ]-- handler := serverRouter{ Game: &controller.Game{ GameService: gameService, }, User: &controller.User{ UserService: userService, }, Engine: &controller.Engine{ GameService: gameService, EngineService: engineService, }, Admin: &controller.Admin{ GameService: gameService, }, File: &controller.File{ FileService: uploadService, }, } codegen := e.Group("") codegen.Use( oapiMiddleware.OapiRequestValidatorWithOptions( swagger, &oapiMiddleware.Options{ Options: openapi3filter.Options{ AuthenticationFunc: authFunc, }, SilenceServersWarning: true, }, ), ) api.RegisterHandlersWithBaseURL(codegen, handler, "/api") // --[ System ]-- e.GET("/metrics", echoprometheus.NewHandler()) e.StaticFS("/file", afero.NewIOFS(storage)) e.StaticFS("/*", distDirFS) e.Logger.Debugf("backend version %s", Version) e.Logger.Fatal(e.Start(cfg.Listen)) } type serverRouter struct { *controller.Game *controller.User *controller.Engine *controller.Admin *controller.File }