package main import ( "context" "fmt" "net/http" "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/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" ) 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) } // db.Use(prometheus.New(prometheus.Config{ // DBName: "db1", // use `DBName` as metrics label // RefreshInterval: 15, // Refresh metrics interval (default 15 seconds) // MetricsCollector: []prometheus.MetricsCollector{ // &prometheus.MySQL{ // VariableNames: []string{"Threads_running"}, // }, // }, // user defined metrics // })) if err := db.AutoMigrate( &models.User{}, &models.Team{}, &models.TeamMember{}, &models.TeamRequest{}, &models.Game{}, &models.GamePassing{}, &models.Team{}, &models.TeamAtGame{}, &models.Task{}, &models.Solution{}, &models.Code{}, ); err != nil { fmt.Fprintf(os.Stderr, "Error DB migration\n: %s", err) os.Exit(1) } // --[ Services ]-- userService := service.NewUser(db) teamService := service.NewTeam(db) gameService := service.NewGame(db) // --[ 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) // userMW := appmiddleware.User(models.RoleUser, userService) authFunc := func(ctx context.Context, ai *openapi3filter.AuthenticationInput) error { echoCtx := ctx.Value(oapiMiddleware.EchoContextKey).(echo.Context) user := appmiddleware.GetUser(echoCtx) if user != nil { return nil } return echo.ErrForbidden } 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.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "cookie:_csrf", CookiePath: "/", // CookieDomain: "nquest.ru", // CookieSecure: true, CookieHTTPOnly: true, CookieSameSite: http.SameSiteStrictMode, }), middleware.Gzip(), echoprometheus.NewMiddleware("nquest"), appmiddleware.User(userService), ) // --[ Router ]-- handler := serverRouter{ Game: &controller.Game{ GameService: gameService, }, User: &controller.User{ UserService: userService, }, Team: &controller.Team{ UserService: userService, TeamService: teamService, }, Engine: &controller.Engine{ GameService: gameService, }, } codegen := e.Group("") codegen.Use( oapiMiddleware.OapiRequestValidatorWithOptions( swagger, &oapiMiddleware.Options{ Options: openapi3filter.Options{ AuthenticationFunc: authFunc, }, }, ), ) api.RegisterHandlersWithBaseURL(codegen, handler, "/api") e.StaticFS("/", distDirFS) e.FileFS("/*", "index.html", distIndexHtml) // --[ System ]-- e.GET("/metrics", echoprometheus.NewHandler()) e.Logger.Fatal(e.Start(cfg.Listen)) } type serverRouter struct { *controller.Game *controller.User *controller.Team *controller.Engine }