2023-11-01 23:21:12 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"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/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"
|
|
|
|
)
|
|
|
|
|
2024-01-21 17:49:35 +03:00
|
|
|
var (
|
|
|
|
Version = "dev"
|
|
|
|
)
|
|
|
|
|
2023-11-01 23:21:12 +03:00
|
|
|
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.Game{},
|
2024-01-05 03:50:33 +03:00
|
|
|
&models.GameCursor{},
|
2023-11-01 23:21:12 +03:00
|
|
|
&models.Task{},
|
|
|
|
&models.Solution{},
|
|
|
|
&models.Code{},
|
2024-01-20 21:37:49 +03:00
|
|
|
&models.File{},
|
2023-11-01 23:21:12 +03:00
|
|
|
); err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "Error DB migration\n: %s", err)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// --[ Services ]--
|
|
|
|
userService := service.NewUser(db)
|
|
|
|
gameService := service.NewGame(db)
|
2024-01-05 03:50:33 +03:00
|
|
|
engineService := service.NewEngine(db)
|
2024-01-20 21:37:49 +03:00
|
|
|
uploadService := service.NewFile(db)
|
2023-11-01 23:21:12 +03:00
|
|
|
|
|
|
|
// --[ 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 {
|
2024-01-21 02:20:59 +03:00
|
|
|
if len(ai.Scopes) > 0 {
|
|
|
|
for _, v := range ai.Scopes {
|
|
|
|
switch v {
|
|
|
|
case "user":
|
|
|
|
return nil
|
|
|
|
case "creator":
|
|
|
|
if user.HasRole(models.RoleCreator) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
case "admin":
|
|
|
|
if user.HasRole(models.RoleAdmin) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-21 02:29:41 +03:00
|
|
|
|
2024-01-21 02:20:59 +03:00
|
|
|
return echo.ErrForbidden
|
|
|
|
}
|
2024-01-21 02:29:41 +03:00
|
|
|
|
2023-11-01 23:21:12 +03:00
|
|
|
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)),
|
2024-01-05 03:50:33 +03:00
|
|
|
// middleware.CSRFWithConfig(middleware.CSRFConfig{
|
|
|
|
// TokenLookup: "cookie:_csrf",
|
|
|
|
// CookiePath: "/",
|
|
|
|
// // CookieDomain: "nquest.ru",
|
|
|
|
// // CookieSecure: true,
|
|
|
|
// CookieHTTPOnly: true,
|
|
|
|
// CookieSameSite: http.SameSiteStrictMode,
|
|
|
|
// }),
|
2023-11-01 23:21:12 +03:00
|
|
|
middleware.Gzip(),
|
|
|
|
echoprometheus.NewMiddleware("nquest"),
|
|
|
|
appmiddleware.User(userService),
|
|
|
|
)
|
|
|
|
|
|
|
|
// --[ Router ]--
|
|
|
|
handler := serverRouter{
|
|
|
|
Game: &controller.Game{
|
|
|
|
GameService: gameService,
|
|
|
|
},
|
|
|
|
User: &controller.User{
|
|
|
|
UserService: userService,
|
|
|
|
},
|
|
|
|
Engine: &controller.Engine{
|
2024-01-05 03:50:33 +03:00
|
|
|
GameService: gameService,
|
|
|
|
EngineService: engineService,
|
2023-11-01 23:21:12 +03:00
|
|
|
},
|
2023-11-19 22:54:54 +03:00
|
|
|
Admin: &controller.Admin{
|
|
|
|
GameService: gameService,
|
|
|
|
},
|
2024-01-20 21:37:49 +03:00
|
|
|
File: &controller.File{
|
|
|
|
FileService: uploadService,
|
|
|
|
},
|
2023-11-01 23:21:12 +03:00
|
|
|
}
|
|
|
|
codegen := e.Group("")
|
|
|
|
|
|
|
|
codegen.Use(
|
|
|
|
oapiMiddleware.OapiRequestValidatorWithOptions(
|
|
|
|
swagger,
|
|
|
|
&oapiMiddleware.Options{
|
|
|
|
Options: openapi3filter.Options{
|
|
|
|
AuthenticationFunc: authFunc,
|
|
|
|
},
|
2023-11-12 23:22:58 +03:00
|
|
|
SilenceServersWarning: true,
|
2023-11-01 23:21:12 +03:00
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
api.RegisterHandlersWithBaseURL(codegen, handler, "/api")
|
|
|
|
|
2024-01-20 23:57:16 +03:00
|
|
|
e.FileFS("/", "index.html", distIndexHtml)
|
2023-11-05 22:22:54 +03:00
|
|
|
e.FileFS("/*", "index.html", distIndexHtml)
|
2024-01-21 00:05:43 +03:00
|
|
|
e.StaticFS("/", distDirFS)
|
2023-11-01 23:21:12 +03:00
|
|
|
|
|
|
|
// --[ System ]--
|
|
|
|
e.GET("/metrics", echoprometheus.NewHandler())
|
2024-01-21 17:49:35 +03:00
|
|
|
e.Logger.Debugf("backend version %s", Version)
|
2023-11-01 23:21:12 +03:00
|
|
|
e.Logger.Fatal(e.Start(cfg.Listen))
|
|
|
|
}
|
|
|
|
|
|
|
|
type serverRouter struct {
|
|
|
|
*controller.Game
|
|
|
|
*controller.User
|
|
|
|
*controller.Engine
|
2023-11-19 22:54:54 +03:00
|
|
|
*controller.Admin
|
2024-01-20 21:37:49 +03:00
|
|
|
*controller.File
|
2023-11-01 23:21:12 +03:00
|
|
|
}
|