api with functioning managment

This commit is contained in:
Fran Jurmanović
2025-02-05 00:26:12 +01:00
parent 954fe0ae82
commit 9118574203
26 changed files with 2017 additions and 55 deletions

View File

@@ -33,13 +33,15 @@ const docTemplate = `{
} }
} }
} }
}
}, },
"/v1/api/restart": {
"post": { "post": {
"description": "Return API", "description": "Restarts service",
"tags": [ "tags": [
"api" "api"
], ],
"summary": "Return API", "summary": "Restart service",
"parameters": [ "parameters": [
{ {
"description": "required", "description": "required",
@@ -63,6 +65,325 @@ const docTemplate = `{
} }
} }
} }
},
"/v1/api/start": {
"post": {
"description": "Starts service",
"tags": [
"api"
],
"summary": "Start service",
"parameters": [
{
"description": "required",
"name": "name",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/api/stop": {
"post": {
"description": "Stops service",
"tags": [
"api"
],
"summary": "Stop service",
"parameters": [
{
"description": "required",
"name": "name",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/api/{service}": {
"get": {
"description": "Returns service status",
"tags": [
"api"
],
"summary": "Return service status",
"parameters": [
{
"type": "string",
"description": "required",
"name": "service",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/car-models": {
"get": {
"description": "Return CarModels Lookup",
"tags": [
"Lookup"
],
"summary": "Return CarModels Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/cup-categories": {
"get": {
"description": "Return CupCategories Lookup",
"tags": [
"Lookup"
],
"summary": "Return CupCategories Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/driver-categories": {
"get": {
"description": "Return DriverCategories Lookup",
"tags": [
"Lookup"
],
"summary": "Return DriverCategories Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/session-types": {
"get": {
"description": "Return SessionTypes Lookup",
"tags": [
"Lookup"
],
"summary": "Return SessionTypes Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/tracks": {
"get": {
"description": "Return Tracks Lookup",
"tags": [
"Lookup"
],
"summary": "Return Tracks Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server": {
"get": {
"description": "Return Servers",
"tags": [
"Server"
],
"summary": "Return Servers",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server/{id}/config": {
"get": {
"description": "Return Config files",
"tags": [
"Config"
],
"summary": "Return Configs",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server/{id}/config/{file}": {
"get": {
"description": "Returns Config file",
"tags": [
"Config"
],
"summary": "Return Config file",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "required",
"name": "file",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"put": {
"description": "Updates config",
"tags": [
"Config"
],
"summary": "Update config",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "required",
"name": "file",
"in": "path",
"required": true
},
{
"description": "required",
"name": "content",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
} }
} }
}` }`

View File

@@ -22,13 +22,15 @@
} }
} }
} }
}
}, },
"/v1/api/restart": {
"post": { "post": {
"description": "Return API", "description": "Restarts service",
"tags": [ "tags": [
"api" "api"
], ],
"summary": "Return API", "summary": "Restart service",
"parameters": [ "parameters": [
{ {
"description": "required", "description": "required",
@@ -52,6 +54,325 @@
} }
} }
} }
},
"/v1/api/start": {
"post": {
"description": "Starts service",
"tags": [
"api"
],
"summary": "Start service",
"parameters": [
{
"description": "required",
"name": "name",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/api/stop": {
"post": {
"description": "Stops service",
"tags": [
"api"
],
"summary": "Stop service",
"parameters": [
{
"description": "required",
"name": "name",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/api/{service}": {
"get": {
"description": "Returns service status",
"tags": [
"api"
],
"summary": "Return service status",
"parameters": [
{
"type": "string",
"description": "required",
"name": "service",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/car-models": {
"get": {
"description": "Return CarModels Lookup",
"tags": [
"Lookup"
],
"summary": "Return CarModels Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/cup-categories": {
"get": {
"description": "Return CupCategories Lookup",
"tags": [
"Lookup"
],
"summary": "Return CupCategories Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/driver-categories": {
"get": {
"description": "Return DriverCategories Lookup",
"tags": [
"Lookup"
],
"summary": "Return DriverCategories Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/session-types": {
"get": {
"description": "Return SessionTypes Lookup",
"tags": [
"Lookup"
],
"summary": "Return SessionTypes Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/lookup/tracks": {
"get": {
"description": "Return Tracks Lookup",
"tags": [
"Lookup"
],
"summary": "Return Tracks Lookup",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server": {
"get": {
"description": "Return Servers",
"tags": [
"Server"
],
"summary": "Return Servers",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server/{id}/config": {
"get": {
"description": "Return Config files",
"tags": [
"Config"
],
"summary": "Return Configs",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"/v1/server/{id}/config/{file}": {
"get": {
"description": "Returns Config file",
"tags": [
"Config"
],
"summary": "Return Config file",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "required",
"name": "file",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"put": {
"description": "Updates config",
"tags": [
"Config"
],
"summary": "Update config",
"parameters": [
{
"type": "number",
"description": "required",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "required",
"name": "file",
"in": "path",
"required": true
},
{
"description": "required",
"name": "content",
"in": "body",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
} }
} }
} }

View File

@@ -14,8 +14,28 @@ paths:
summary: Return API summary: Return API
tags: tags:
- api - api
/v1/api/{service}:
get:
description: Returns service status
parameters:
- description: required
in: path
name: service
required: true
type: string
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return service status
tags:
- api
/v1/api/restart:
post: post:
description: Return API description: Restarts service
parameters: parameters:
- description: required - description: required
in: body in: body
@@ -30,7 +50,197 @@ paths:
items: items:
type: string type: string
type: array type: array
summary: Return API summary: Restart service
tags: tags:
- api - api
/v1/api/start:
post:
description: Starts service
parameters:
- description: required
in: body
name: name
required: true
schema:
type: string
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Start service
tags:
- api
/v1/api/stop:
post:
description: Stops service
parameters:
- description: required
in: body
name: name
required: true
schema:
type: string
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Stop service
tags:
- api
/v1/lookup/car-models:
get:
description: Return CarModels Lookup
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return CarModels Lookup
tags:
- Lookup
/v1/lookup/cup-categories:
get:
description: Return CupCategories Lookup
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return CupCategories Lookup
tags:
- Lookup
/v1/lookup/driver-categories:
get:
description: Return DriverCategories Lookup
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return DriverCategories Lookup
tags:
- Lookup
/v1/lookup/session-types:
get:
description: Return SessionTypes Lookup
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return SessionTypes Lookup
tags:
- Lookup
/v1/lookup/tracks:
get:
description: Return Tracks Lookup
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return Tracks Lookup
tags:
- Lookup
/v1/server:
get:
description: Return Servers
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return Servers
tags:
- Server
/v1/server/{id}/config:
get:
description: Return Config files
parameters:
- description: required
in: path
name: id
required: true
type: number
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return Configs
tags:
- Config
/v1/server/{id}/config/{file}:
get:
description: Returns Config file
parameters:
- description: required
in: path
name: id
required: true
type: number
- description: required
in: path
name: file
required: true
type: string
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Return Config file
tags:
- Config
put:
description: Updates config
parameters:
- description: required
in: path
name: id
required: true
type: number
- description: required
in: path
name: file
required: true
type: string
- description: required
in: body
name: content
required: true
schema:
type: string
responses:
"200":
description: OK
schema:
items:
type: string
type: array
summary: Update config
tags:
- Config
swagger: "2.0" swagger: "2.0"

View File

@@ -27,6 +27,9 @@ func Init(di *dig.Container, app *fiber.App) {
routeGroups := &common.RouteGroups{ routeGroups := &common.RouteGroups{
Api: groups.Group("/api"), Api: groups.Group("/api"),
Server: groups.Group("/server"),
Config: groups.Group("/server/:id").Group("/config"),
Lookup: groups.Group("/lookup"),
} }
routeGroups.Api.Use(basicAuthConfig) routeGroups.Api.Use(basicAuthConfig)

View File

@@ -25,7 +25,10 @@ func NewApiController(as *service.ApiService, routeGroups *common.RouteGroups) *
} }
routeGroups.Api.Get("/", ac.getFirst) routeGroups.Api.Get("/", ac.getFirst)
routeGroups.Api.Post("/", ac.startServer) routeGroups.Api.Get("/:service", ac.getStatus)
routeGroups.Api.Post("/start", ac.startServer)
routeGroups.Api.Post("/stop", ac.stopServer)
routeGroups.Api.Post("/restart", ac.restartServer)
return ac return ac
} }
@@ -42,14 +45,30 @@ func (ac *ApiController) getFirst(c *fiber.Ctx) error {
return c.SendString(apiModel.Api) return c.SendString(apiModel.Api)
} }
// startServer returns API // getStatus returns service status
// //
// @Summary Return API // @Summary Return service status
// @Description Return API // @Description Returns service status
// @Param service path string true "required"
// @Tags api
// @Success 200 {array} string
// @Router /v1/api/{service} [get]
func (ac *ApiController) getStatus(c *fiber.Ctx) error {
apiModel, err := ac.service.GetStatus(c)
if err != nil {
return c.Status(400).SendString(err.Error())
}
return c.SendString(apiModel)
}
// startServer starts service
//
// @Summary Start service
// @Description Starts service
// @Param name body string true "required" // @Param name body string true "required"
// @Tags api // @Tags api
// @Success 200 {array} string // @Success 200 {array} string
// @Router /v1/api [post] // @Router /v1/api/start [post]
func (ac *ApiController) startServer(c *fiber.Ctx) error { func (ac *ApiController) startServer(c *fiber.Ctx) error {
model := new(Service) model := new(Service)
if err := c.BodyParser(model); err != nil { if err := c.BodyParser(model); err != nil {
@@ -58,7 +77,49 @@ func (ac *ApiController) startServer(c *fiber.Ctx) error {
c.Locals("service", model.Name) c.Locals("service", model.Name)
apiModel, err := ac.service.ApiStartServer(c) apiModel, err := ac.service.ApiStartServer(c)
if err != nil { if err != nil {
return c.SendStatus(400) return c.Status(400).SendString(err.Error())
}
return c.SendString(apiModel)
}
// stopServer stops service
//
// @Summary Stop service
// @Description Stops service
// @Param name body string true "required"
// @Tags api
// @Success 200 {array} string
// @Router /v1/api/stop [post]
func (ac *ApiController) stopServer(c *fiber.Ctx) error {
model := new(Service)
if err := c.BodyParser(model); err != nil {
c.SendStatus(400)
}
c.Locals("service", model.Name)
apiModel, err := ac.service.ApiStopServer(c)
if err != nil {
return c.Status(400).SendString(err.Error())
}
return c.SendString(apiModel)
}
// restartServer returns API
//
// @Summary Restart service
// @Description Restarts service
// @Param name body string true "required"
// @Tags api
// @Success 200 {array} string
// @Router /v1/api/restart [post]
func (ac *ApiController) restartServer(c *fiber.Ctx) error {
model := new(Service)
if err := c.BodyParser(model); err != nil {
c.SendStatus(400)
}
c.Locals("service", model.Name)
apiModel, err := ac.service.ApiRestartServer(c)
if err != nil {
return c.Status(400).SendString(err.Error())
} }
return c.SendString(apiModel) return c.SendString(apiModel)
} }

View File

@@ -0,0 +1,89 @@
package controller
import (
"acc-server-manager/local/service"
"acc-server-manager/local/utl/common"
"github.com/gofiber/fiber/v2"
)
type ConfigController struct {
service *service.ConfigService
}
// NewConfigController
// Initializes ConfigController.
//
// Args:
// *services.ConfigService: Config service
// *Fiber.RouterGroup: Fiber Router Group
// Returns:
// *ConfigController: Controller for "Config" interactions
func NewConfigController(as *service.ConfigService, routeGroups *common.RouteGroups) *ConfigController {
ac := &ConfigController{
service: as,
}
routeGroups.Config.Put("/:file", ac.updateConfig)
routeGroups.Config.Get("/:file", ac.getConfig)
routeGroups.Config.Get("/", ac.getConfigs)
return ac
}
// updateConfig returns Config
//
// @Summary Update config
// @Description Updates config
// @Param id path number true "required"
// @Param file path string true "required"
// @Param content body string true "required"
// @Tags Config
// @Success 200 {array} string
// @Router /v1/server/{id}/config/{file} [put]
func (ac *ConfigController) updateConfig(c *fiber.Ctx) error {
var config map[string]interface{}
if err := c.BodyParser(&config); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid config format"})
}
ConfigModel, err := ac.service.UpdateConfig(c, &config)
if err != nil {
return c.Status(400).SendString(err.Error())
}
return c.JSON(ConfigModel)
}
// getConfig returns Config
//
// @Summary Return Config file
// @Description Returns Config file
// @Param id path number true "required"
// @Param file path string true "required"
// @Tags Config
// @Success 200 {array} string
// @Router /v1/server/{id}/config/{file} [get]
func (ac *ConfigController) getConfig(c *fiber.Ctx) error {
Model, err := ac.service.GetConfig(c)
if err != nil {
return c.Status(400).SendString(err.Error())
}
return c.JSON(Model)
}
// getConfigs returns Config
//
// @Summary Return Configs
// @Description Return Config files
// @Param id path number true "required"
// @Tags Config
// @Success 200 {array} string
// @Router /v1/server/{id}/config [get]
func (ac *ConfigController) getConfigs(c *fiber.Ctx) error {
Model, err := ac.service.GetConfigs(c)
if err != nil {
return c.Status(400).SendString(err.Error())
}
return c.JSON(Model)
}

View File

@@ -24,6 +24,21 @@ func InitializeControllers(c *dig.Container) {
if err != nil { if err != nil {
panic("unable to initialize api controller") panic("unable to initialize api controller")
} }
err = c.Invoke(NewConfigController)
if err != nil {
panic("unable to initialize config controller")
}
err = c.Invoke(NewServerController)
if err != nil {
panic("unable to initialize server controller")
}
err = c.Invoke(NewLookupController)
if err != nil {
panic("unable to initialize lookup controller")
}
} }
// FilteredResponse // FilteredResponse

View File

@@ -0,0 +1,93 @@
package controller
import (
"acc-server-manager/local/service"
"acc-server-manager/local/utl/common"
"github.com/gofiber/fiber/v2"
)
type LookupController struct {
service *service.LookupService
}
// NewLookupController
// Initializes LookupController.
//
// Args:
// *services.LookupService: Lookup service
// *Fiber.RouterGroup: Fiber Router Group
// Returns:
// *LookupController: Controller for "Lookup" interactions
func NewLookupController(as *service.LookupService, routeGroups *common.RouteGroups) *LookupController {
ac := &LookupController{
service: as,
}
routeGroups.Lookup.Get("/tracks", ac.getTracks)
routeGroups.Lookup.Get("/car-models", ac.getCarModels)
routeGroups.Lookup.Get("/driver-categories", ac.getDriverCategories)
routeGroups.Lookup.Get("/cup-categories", ac.getCupCategories)
routeGroups.Lookup.Get("/session-types", ac.getSessionTypes)
return ac
}
// getTracks returns Tracks
//
// @Summary Return Tracks Lookup
// @Description Return Tracks Lookup
// @Tags Lookup
// @Success 200 {array} string
// @Router /v1/lookup/tracks [get]
func (ac *LookupController) getTracks(c *fiber.Ctx) error {
LookupModel := ac.service.GetTracks(c)
return c.JSON(LookupModel)
}
// getCarModels returns CarModels
//
// @Summary Return CarModels Lookup
// @Description Return CarModels Lookup
// @Tags Lookup
// @Success 200 {array} string
// @Router /v1/lookup/car-models [get]
func (ac *LookupController) getCarModels(c *fiber.Ctx) error {
LookupModel := ac.service.GetCarModels(c)
return c.JSON(LookupModel)
}
// getDriverCategories returns DriverCategories
//
// @Summary Return DriverCategories Lookup
// @Description Return DriverCategories Lookup
// @Tags Lookup
// @Success 200 {array} string
// @Router /v1/lookup/driver-categories [get]
func (ac *LookupController) getDriverCategories(c *fiber.Ctx) error {
LookupModel := ac.service.GetDriverCategories(c)
return c.JSON(LookupModel)
}
// getCupCategories returns CupCategories
//
// @Summary Return CupCategories Lookup
// @Description Return CupCategories Lookup
// @Tags Lookup
// @Success 200 {array} string
// @Router /v1/lookup/cup-categories [get]
func (ac *LookupController) getCupCategories(c *fiber.Ctx) error {
LookupModel := ac.service.GetCupCategories(c)
return c.JSON(LookupModel)
}
// getSessionTypes returns SessionTypes
//
// @Summary Return SessionTypes Lookup
// @Description Return SessionTypes Lookup
// @Tags Lookup
// @Success 200 {array} string
// @Router /v1/lookup/session-types [get]
func (ac *LookupController) getSessionTypes(c *fiber.Ctx) error {
LookupModel := ac.service.GetSessionTypes(c)
return c.JSON(LookupModel)
}

View File

@@ -0,0 +1,42 @@
package controller
import (
"acc-server-manager/local/service"
"acc-server-manager/local/utl/common"
"github.com/gofiber/fiber/v2"
)
type ServerController struct {
service *service.ServerService
}
// NewServerController
// Initializes ServerController.
//
// Args:
// *services.ServerService: Server service
// *Fiber.RouterGroup: Fiber Router Group
// Returns:
// *ServerController: Controller for "Server" interactions
func NewServerController(as *service.ServerService, routeGroups *common.RouteGroups) *ServerController {
ac := &ServerController{
service: as,
}
routeGroups.Server.Get("/", ac.getAll)
return ac
}
// getAll returns Servers
//
// @Summary Return Servers
// @Description Return Servers
// @Tags Server
// @Success 200 {array} string
// @Router /v1/server [get]
func (ac *ServerController) getAll(c *fiber.Ctx) error {
ServerModel := ac.service.GetAll(c)
return c.JSON(ServerModel)
}

View File

@@ -3,3 +3,9 @@ package model
type ApiModel struct { type ApiModel struct {
Api string `json:"api"` Api string `json:"api"`
} }
// ServiceStatus represents a Windows service state
type ServiceStatus struct {
Name string `json:"name"`
Status string `json:"status"` // "running", "stopped", "pending"
}

21
local/model/config.go Normal file
View File

@@ -0,0 +1,21 @@
package model
import "time"
// Config tracks configuration modifications
type Config struct {
ID uint `gorm:"primaryKey"`
ServerID uint `gorm:"not null"`
ConfigFile string `gorm:"not null"` // e.g. "settings.json"
OldConfig string `gorm:"type:text"`
NewConfig string `gorm:"type:text"`
ChangedAt time.Time `gorm:"default:CURRENT_TIMESTAMP"`
}
type Configurations struct {
Configuration map[string]interface{}
Entrylist map[string]interface{}
Event map[string]interface{}
EventRules map[string]interface{}
Settings map[string]interface{}
}

32
local/model/lookup.go Normal file
View File

@@ -0,0 +1,32 @@
package model
// Track represents a track and its capacity
type Track struct {
Name string `json:"track" gorm:"primaryKey;size:50"`
UniquePitBoxes int `json:"unique_pit_boxes"`
PrivateServerSlots int `json:"private_server_slots"`
}
// CarModel represents a car model mapping
type CarModel struct {
Value int `json:"value" gorm:"primaryKey"`
CarModel string `json:"car_model"`
}
// DriverCategory represents driver skill categories
type DriverCategory struct {
Value int `json:"value" gorm:"primaryKey"`
Category string `json:"category"`
}
// CupCategory represents championship cup categories
type CupCategory struct {
Value int `json:"value" gorm:"primaryKey"`
Category string `json:"category"`
}
// SessionType represents session types
type SessionType struct {
Value int `json:"value" gorm:"primaryKey"`
SessionType string `json:"session_type"`
}

11
local/model/server.go Normal file
View File

@@ -0,0 +1,11 @@
package model
// Server represents an ACC server instance
type Server struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"not null"`
IP string `gorm:"not null"`
Port int `gorm:"not null"`
ConfigPath string `gorm:"not null"` // e.g. "/acc/servers/server1/"
ServiceName string `gorm:"not null"` // Windows service name
}

View File

@@ -3,6 +3,7 @@ package repository
import ( import (
"acc-server-manager/local/model" "acc-server-manager/local/model"
"context" "context"
"errors"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -27,6 +28,9 @@ func NewApiRepository(db *gorm.DB) *ApiRepository {
func (as ApiRepository) GetFirst(ctx context.Context) *model.ApiModel { func (as ApiRepository) GetFirst(ctx context.Context) *model.ApiModel {
db := as.db.WithContext(ctx) db := as.db.WithContext(ctx)
apiModel := new(model.ApiModel) apiModel := new(model.ApiModel)
db.First(&apiModel) result := db.First(&apiModel)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil
}
return apiModel return apiModel
} }

View File

@@ -0,0 +1,66 @@
package repository
import (
"acc-server-manager/local/model"
"context"
"errors"
"gorm.io/gorm"
)
type ConfigRepository struct {
db *gorm.DB
}
func NewConfigRepository(db *gorm.DB) *ConfigRepository {
return &ConfigRepository{
db: db,
}
}
// UpdateConfig
// Updates first row from Config table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ConfigModel: Config object from database.
func (as ConfigRepository) UpdateFirst(ctx context.Context) *model.Config {
db := as.db.WithContext(ctx)
ConfigModel := new(model.Config)
db.First(&ConfigModel)
return ConfigModel
}
// UpdateAll
// Updates All rows from Config table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ConfigModel: Config object from database.
func (as ConfigRepository) UpdateAll(ctx context.Context) *[]model.Config {
db := as.db.WithContext(ctx)
ConfigModel := new([]model.Config)
db.Find(&ConfigModel)
return ConfigModel
}
// UpdateConfig
// Updates Config row from Config table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ConfigModel: Config object from database.
func (as ConfigRepository) UpdateConfig(ctx context.Context, body *model.Config) *model.Config {
db := as.db.WithContext(ctx)
existingConfig := new(model.Config)
result := db.Where("server_id=?", body.ServerID).Where("config_file=?", body.ConfigFile).First(existingConfig)
if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
body.ID = existingConfig.ID
}
db.Save(body)
return body
}

View File

@@ -0,0 +1,88 @@
package repository
import (
"acc-server-manager/local/model"
"context"
"gorm.io/gorm"
)
type LookupRepository struct {
db *gorm.DB
}
func NewLookupRepository(db *gorm.DB) *LookupRepository {
return &LookupRepository{
db: db,
}
}
// GetTracks
// Gets Tracks rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupRepository) GetTracks(ctx context.Context) *[]model.Track {
db := as.db.WithContext(ctx)
TrackModel := new([]model.Track)
db.Find(&TrackModel)
return TrackModel
}
// GetCarModels
// Gets CarModels rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupRepository) GetCarModels(ctx context.Context) *[]model.CarModel {
db := as.db.WithContext(ctx)
CarModelModel := new([]model.CarModel)
db.Find(&CarModelModel)
return CarModelModel
}
// GetDriverCategories
// Gets DriverCategories rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupRepository) GetDriverCategories(ctx context.Context) *[]model.DriverCategory {
db := as.db.WithContext(ctx)
DriverCategoryModel := new([]model.DriverCategory)
db.Find(&DriverCategoryModel)
return DriverCategoryModel
}
// GetCupCategories
// Gets CupCategories rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupRepository) GetCupCategories(ctx context.Context) *[]model.CupCategory {
db := as.db.WithContext(ctx)
CupCategoryModel := new([]model.CupCategory)
db.Find(&CupCategoryModel)
return CupCategoryModel
}
// GetSessionTypes
// Gets SessionTypes rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupRepository) GetSessionTypes(ctx context.Context) *[]model.SessionType {
db := as.db.WithContext(ctx)
SessionTypesModel := new([]model.SessionType)
db.Find(&SessionTypesModel)
return SessionTypesModel
}

View File

@@ -11,4 +11,7 @@ import (
// *dig.Container: Dig Container // *dig.Container: Dig Container
func InitializeRepositories(c *dig.Container) { func InitializeRepositories(c *dig.Container) {
c.Provide(NewApiRepository) c.Provide(NewApiRepository)
c.Provide(NewServerRepository)
c.Provide(NewConfigRepository)
c.Provide(NewLookupRepository)
} }

View File

@@ -0,0 +1,64 @@
package repository
import (
"acc-server-manager/local/model"
"context"
"errors"
"gorm.io/gorm"
)
type ServerRepository struct {
db *gorm.DB
}
func NewServerRepository(db *gorm.DB) *ServerRepository {
return &ServerRepository{
db: db,
}
}
// GetFirst
// Gets first row from Server table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ServerModel: Server object from database.
func (as ServerRepository) GetFirst(ctx context.Context, serverId int) *model.Server {
db := as.db.WithContext(ctx)
ServerModel := new(model.Server)
db.Where("id=?", serverId).First(&ServerModel)
return ServerModel
}
// GetFirstByServiceName
// Gets first row from Server table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ServerModel: Server object from database.
func (as ServerRepository) GetFirstByServiceName(ctx context.Context, serviceName string) *model.Server {
db := as.db.WithContext(ctx)
ServerModel := new(model.Server)
result := db.Where("service_name=?", serviceName).First(&ServerModel)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
return nil
}
return ServerModel
}
// GetAll
// Gets All rows from Server table.
//
// Args:
// context.Context: Application context
// Returns:
// model.ServerModel: Server object from database.
func (as ServerRepository) GetAll(ctx context.Context) *[]model.Server {
db := as.db.WithContext(ctx)
ServerModel := new([]model.Server)
db.Find(&ServerModel)
return ServerModel
}

View File

@@ -11,11 +11,14 @@ import (
type ApiService struct { type ApiService struct {
repository *repository.ApiRepository repository *repository.ApiRepository
serverRepository *repository.ServerRepository
} }
func NewApiService(repository *repository.ApiRepository) *ApiService { func NewApiService(repository *repository.ApiRepository,
serverRepository *repository.ServerRepository) *ApiService {
return &ApiService{ return &ApiService{
repository: repository, repository: repository,
serverRepository: serverRepository,
} }
} }
@@ -30,16 +33,17 @@ func (as ApiService) GetFirst(ctx *fiber.Ctx) *model.ApiModel {
return as.repository.GetFirst(ctx.UserContext()) return as.repository.GetFirst(ctx.UserContext())
} }
func (as ApiService) GetStatus(ctx *fiber.Ctx) (string, error) {
service := ctx.Params("service")
return as.StatusServer(ctx, service)
}
func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) { func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) {
service, ok := ctx.Locals("service").(string) service, ok := ctx.Locals("service").(string)
if !ok { if !ok {
return "", errors.New("service name missing") return "", errors.New("service name missing")
} }
return as.StartServer(service) return as.StartServer(ctx, service)
}
func (as ApiService) StartServer(serviceName string) (string, error) {
return as.ManageService("start", serviceName)
} }
func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) { func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
@@ -47,11 +51,7 @@ func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) {
if !ok { if !ok {
return "", errors.New("service name missing") return "", errors.New("service name missing")
} }
return as.StopServer(service) return as.StopServer(ctx, service)
}
func (as ApiService) StopServer(serviceName string) (string, error) {
return as.ManageService("stop", serviceName)
} }
func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) { func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
@@ -59,18 +59,31 @@ func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) {
if !ok { if !ok {
return "", errors.New("service name missing") return "", errors.New("service name missing")
} }
return as.RestartServer(service) return as.RestartServer(ctx, service)
} }
func (as ApiService) RestartServer(serviceName string) (string, error) { func (as ApiService) StatusServer(ctx *fiber.Ctx, serviceName string) (string, error) {
_, err := as.ManageService("stop", serviceName) return as.ManageService(ctx, "status", serviceName)
if err != nil { }
return "", err
} func (as ApiService) StartServer(ctx *fiber.Ctx, serviceName string) (string, error) {
return as.ManageService("start", serviceName) return as.ManageService(ctx, "start", serviceName)
}
func (as ApiService) StopServer(ctx *fiber.Ctx, serviceName string) (string, error) {
return as.ManageService(ctx, "stop", serviceName)
}
func (as ApiService) RestartServer(ctx *fiber.Ctx, serviceName string) (string, error) {
return as.ManageService(ctx, "restart", serviceName)
}
func (as ApiService) ManageService(ctx *fiber.Ctx, action string, serviceName string) (string, error) {
server := as.serverRepository.GetFirstByServiceName(ctx.UserContext(), serviceName)
if server == nil {
return "", fiber.NewError(404, "Server not found")
} }
func (as ApiService) ManageService(action string, serviceName string) (string, error) {
output, err := common.RunElevatedCommand(action, serviceName) output, err := common.RunElevatedCommand(action, serviceName)
if err != nil { if err != nil {
return "", err return "", err

238
local/service/config.go Normal file
View File

@@ -0,0 +1,238 @@
package service
import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"bytes"
"encoding/json"
"errors"
"io"
"os"
"path/filepath"
"time"
"github.com/gofiber/fiber/v2"
"golang.org/x/text/encoding/unicode"
"golang.org/x/text/transform"
)
type ConfigService struct {
repository *repository.ConfigRepository
serverRepository *repository.ServerRepository
}
func NewConfigService(repository *repository.ConfigRepository, serverRepository *repository.ServerRepository) *ConfigService {
return &ConfigService{
repository: repository,
serverRepository: serverRepository,
}
}
// UpdateConfig
// Updates physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface{}) (*model.Config, error) {
serverID, _ := ctx.ParamsInt("id")
configFile := ctx.Params("file")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
// Read existing config
configPath := filepath.Join(server.ConfigPath, "\\server\\cfg", configFile)
oldData, err := os.ReadFile(configPath)
if err != nil {
return nil, err
}
oldDataUTF8, err := DecodeUTF16LEBOM(oldData)
if err != nil {
return nil, err
}
// Write new config
newData, err := json.MarshalIndent(&body, "", " ")
if err != nil {
return nil, err
}
newDataUTF16, err := EncodeUTF16LEBOM(newData)
if err != nil {
return nil, err
}
if err := os.WriteFile(configPath, newDataUTF16, 0644); err != nil {
return nil, err
}
// Log change
return as.repository.UpdateConfig(ctx.UserContext(), &model.Config{
ServerID: uint(serverID),
ConfigFile: configFile,
OldConfig: string(oldDataUTF8),
NewConfig: string(newData),
ChangedAt: time.Now(),
}), nil
}
// GetConfig
// Gets physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) GetConfig(ctx *fiber.Ctx) (map[string]interface{}, error) {
serverID, _ := ctx.ParamsInt("id")
configFile := ctx.Params("file")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
config, err := readFile(server.ConfigPath, configFile)
if err != nil {
return nil, err
}
decoded, err := DecodeToMap(config)
if err != nil {
return nil, err
}
return decoded, nil
}
// GetConfigs
// Gets physical config file and caches it in database.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, error) {
serverID, _ := ctx.ParamsInt("id")
server := as.serverRepository.GetFirst(ctx.UserContext(), serverID)
if server == nil {
return nil, fiber.NewError(404, "Server not found")
}
configuration, err := readFile(server.ConfigPath, "configuration.json")
if err != nil {
return nil, err
}
decodedconfiguration, err := DecodeToMap(configuration)
if err != nil {
return nil, err
}
entrylist, err := readFile(server.ConfigPath, "entrylist.json")
if err != nil {
return nil, err
}
decodedentrylist, err := DecodeToMap(entrylist)
if err != nil {
return nil, err
}
event, err := readFile(server.ConfigPath, "event.json")
if err != nil {
return nil, err
}
decodedevent, err := DecodeToMap(event)
if err != nil {
return nil, err
}
eventRules, err := readFile(server.ConfigPath, "eventRules.json")
if err != nil {
return nil, err
}
decodedeventRules, err := DecodeToMap(eventRules)
if err != nil {
return nil, err
}
settings, err := readFile(server.ConfigPath, "settings.json")
if err != nil {
return nil, err
}
decodedsettings, err := DecodeToMap(settings)
if err != nil {
return nil, err
}
return &model.Configurations{
Configuration: decodedconfiguration,
Event: decodedevent,
EventRules: decodedeventRules,
Settings: decodedsettings,
Entrylist: decodedentrylist,
}, nil
}
func readFile(path string, configFile string) ([]byte, error) {
configPath := filepath.Join(path, "\\server\\cfg", configFile)
oldData, err := os.ReadFile(configPath)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
} else if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
return oldData, nil
}
func EncodeUTF16LEBOM(input []byte) ([]byte, error) {
encoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
return transformBytes(encoder.NewEncoder(), input)
}
func DecodeUTF16LEBOM(input []byte) ([]byte, error) {
decoder := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
return transformBytes(decoder.NewDecoder(), input)
}
func DecodeToMap(input []byte) (map[string]interface{}, error) {
if input == nil {
return nil, nil
}
configUTF8 := new(map[string]interface{})
decoded, err := DecodeUTF16LEBOM(input)
if err != nil {
return nil, err
}
err = json.Unmarshal(decoded, configUTF8)
if err != nil {
return nil, err
}
return *configUTF8, nil
}
func transformBytes(t transform.Transformer, input []byte) ([]byte, error) {
var buf bytes.Buffer
w := transform.NewWriter(&buf, t)
if _, err := io.Copy(w, bytes.NewReader(input)); err != nil {
return nil, err
}
if err := w.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

73
local/service/lookup.go Normal file
View File

@@ -0,0 +1,73 @@
package service
import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"github.com/gofiber/fiber/v2"
)
type LookupService struct {
repository *repository.LookupRepository
}
func NewLookupService(repository *repository.LookupRepository) *LookupService {
return &LookupService{
repository: repository,
}
}
// GetTracks
// Gets Tracks rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as LookupService) GetTracks(ctx *fiber.Ctx) *[]model.Track {
return as.repository.GetTracks(ctx.UserContext())
}
// GetCarModels
// Gets CarModels rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupService) GetCarModels(ctx *fiber.Ctx) *[]model.CarModel {
return as.repository.GetCarModels(ctx.UserContext())
}
// GetDriverCategories
// Gets DriverCategories rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupService) GetDriverCategories(ctx *fiber.Ctx) *[]model.DriverCategory {
return as.repository.GetDriverCategories(ctx.UserContext())
}
// GetCupCategories
// Gets CupCategories rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupService) GetCupCategories(ctx *fiber.Ctx) *[]model.CupCategory {
return as.repository.GetCupCategories(ctx.UserContext())
}
// GetSessionTypes
// Gets SessionTypes rows from Lookup table.
//
// Args:
// context.Context: Application context
// Returns:
// model.LookupModel: Lookup object from database.
func (as LookupService) GetSessionTypes(ctx *fiber.Ctx) *[]model.SessionType {
return as.repository.GetSessionTypes(ctx.UserContext())
}

29
local/service/server.go Normal file
View File

@@ -0,0 +1,29 @@
package service
import (
"acc-server-manager/local/model"
"acc-server-manager/local/repository"
"github.com/gofiber/fiber/v2"
)
type ServerService struct {
repository *repository.ServerRepository
}
func NewServerService(repository *repository.ServerRepository) *ServerService {
return &ServerService{
repository: repository,
}
}
// GetAll
// Gets All rows from Server table.
//
// Args:
// context.Context: Application context
// Returns:
// string: Application version
func (as ServerService) GetAll(ctx *fiber.Ctx) *[]model.Server {
return as.repository.GetAll(ctx.UserContext())
}

View File

@@ -15,4 +15,7 @@ func InitializeServices(c *dig.Container) {
repository.InitializeRepositories(c) repository.InitializeRepositories(c)
c.Provide(NewApiService) c.Provide(NewApiService)
c.Provide(NewConfigService)
c.Provide(NewServerService)
c.Provide(NewLookupService)
} }

View File

@@ -14,6 +14,9 @@ import (
type RouteGroups struct { type RouteGroups struct {
Api fiber.Router Api fiber.Router
Server fiber.Router
Config fiber.Router
Lookup fiber.Router
} }
func CheckError(err error) { func CheckError(err error) {
@@ -58,10 +61,10 @@ func Find[T any](lst *[]T, callback func(item *T) bool) *T {
} }
func RunElevatedCommand(command string, service string) (string, error) { func RunElevatedCommand(command string, service string) (string, error) {
cmd := exec.Command("powershell", "-nologo", "-noprofile", "-File", "run_sc.ps1", command, service) cmd := exec.Command("powershell", "-nologo", "-noprofile", ".\\nssm", command, service)
// cmd := exec.Command("powershell", "-nologo", "-noprofile", "-File", "run_sc.ps1", command, service)
output, err := cmd.CombinedOutput() output, err := cmd.CombinedOutput()
if err != nil { if err != nil {
log.Panic("error: %v, output: %s", err, string(output))
return "", fmt.Errorf("error: %v, output: %s", err, string(output)) return "", fmt.Errorf("error: %v, output: %s", err, string(output))
} }
return string(output), nil return string(output), nil

View File

@@ -27,5 +27,173 @@ func Migrate(db *gorm.DB) {
if err != nil { if err != nil {
panic("failed to migrate model.ApiModel") panic("failed to migrate model.ApiModel")
} }
db.FirstOrCreate(&model.ApiModel{Api: "Works"}) err = db.AutoMigrate(&model.Server{})
if err != nil {
panic("failed to migrate model.Server")
}
err = db.AutoMigrate(&model.Config{})
if err != nil {
panic("failed to migrate model.Config")
}
err = db.AutoMigrate(&model.Track{})
if err != nil {
panic("failed to migrate model.Track")
}
err = db.AutoMigrate(&model.CarModel{})
if err != nil {
panic("failed to migrate model.CarModel")
}
err = db.AutoMigrate(&model.CupCategory{})
if err != nil {
panic("failed to migrate model.CupCategory")
}
err = db.AutoMigrate(&model.DriverCategory{})
if err != nil {
panic("failed to migrate model.DriverCategory")
}
err = db.AutoMigrate(&model.SessionType{})
if err != nil {
panic("failed to migrate model.SessionType")
}
db.FirstOrCreate(&model.ApiModel{Api: "Works"})
Seed(db)
}
func Seed(db *gorm.DB) error {
if err := seedTracks(db); err != nil {
return err
}
if err := seedCarModels(db); err != nil {
return err
}
if err := seedDriverCategories(db); err != nil {
return err
}
if err := seedCupCategories(db); err != nil {
return err
}
if err := seedSessionTypes(db); err != nil {
return err
}
if err := seedServers(db); err != nil {
return err
}
return nil
}
func seedServers(db *gorm.DB) error {
servers := []model.Server{
{ID: 1, Name: "ACC Server - Barcelona", ServiceName: "ACC-Barcelona", ConfigPath: "C:\\steamcmd\\acc"},
{ID: 2, Name: "ACC Server - Monza", ServiceName: "ACC-Monza", ConfigPath: "C:\\steamcmd\\acc2"},
{ID: 3, Name: "ACC Server - Spa", ServiceName: "ACC-Spa", ConfigPath: "C:\\steamcmd\\acc3"},
{ID: 4, Name: "ACC Server - League", ServiceName: "ACC-League", ConfigPath: "C:\\steamcmd\\acc-league"},
}
for _, track := range servers {
if err := db.FirstOrCreate(&track).Error; err != nil {
return err
}
}
return nil
}
func seedTracks(db *gorm.DB) error {
tracks := []model.Track{
{Name: "monza", UniquePitBoxes: 29, PrivateServerSlots: 60},
{Name: "zolder", UniquePitBoxes: 34, PrivateServerSlots: 50},
{Name: "brands_hatch", UniquePitBoxes: 32, PrivateServerSlots: 50},
{Name: "silverstone", UniquePitBoxes: 36, PrivateServerSlots: 60},
{Name: "paul_ricard", UniquePitBoxes: 33, PrivateServerSlots: 80},
{Name: "misano", UniquePitBoxes: 30, PrivateServerSlots: 50},
{Name: "spa", UniquePitBoxes: 82, PrivateServerSlots: 82},
{Name: "nurburgring", UniquePitBoxes: 30, PrivateServerSlots: 50},
{Name: "barcelona", UniquePitBoxes: 29, PrivateServerSlots: 50},
{Name: "hungaroring", UniquePitBoxes: 27, PrivateServerSlots: 50},
{Name: "zandvoort", UniquePitBoxes: 25, PrivateServerSlots: 50},
{Name: "kyalami", UniquePitBoxes: 40, PrivateServerSlots: 50},
{Name: "mount_panorama", UniquePitBoxes: 36, PrivateServerSlots: 50},
{Name: "suzuka", UniquePitBoxes: 51, PrivateServerSlots: 105},
{Name: "laguna_seca", UniquePitBoxes: 30, PrivateServerSlots: 50},
{Name: "imola", UniquePitBoxes: 30, PrivateServerSlots: 50},
{Name: "oulton_park", UniquePitBoxes: 28, PrivateServerSlots: 50},
{Name: "donington", UniquePitBoxes: 37, PrivateServerSlots: 50},
{Name: "snetterton", UniquePitBoxes: 26, PrivateServerSlots: 50},
{Name: "cota", UniquePitBoxes: 30, PrivateServerSlots: 70},
{Name: "indianapolis", UniquePitBoxes: 30, PrivateServerSlots: 60},
{Name: "watkins_glen", UniquePitBoxes: 30, PrivateServerSlots: 60},
{Name: "valencia", UniquePitBoxes: 29, PrivateServerSlots: 50},
{Name: "nurburgring_24h", UniquePitBoxes: 50, PrivateServerSlots: 110},
}
for _, track := range tracks {
if err := db.FirstOrCreate(&track).Error; err != nil {
return err
}
}
return nil
}
func seedCarModels(db *gorm.DB) error {
carModels := []model.CarModel{
{Value: 0, CarModel: "Porsche 991 GT3 R"},
{Value: 1, CarModel: "Mercedes-AMG GT3"},
// ... Add all car models from your list
}
for _, cm := range carModels {
if err := db.FirstOrCreate(&cm).Error; err != nil {
return err
}
}
return nil
}
func seedDriverCategories(db *gorm.DB) error {
categories := []model.DriverCategory{
{Value: 3, Category: "Platinum"},
{Value: 2, Category: "Gold"},
{Value: 1, Category: "Silver"},
{Value: 0, Category: "Bronze"},
}
for _, cat := range categories {
if err := db.FirstOrCreate(&cat).Error; err != nil {
return err
}
}
return nil
}
func seedCupCategories(db *gorm.DB) error {
categories := []model.CupCategory{
{Value: 0, Category: "Overall"},
{Value: 1, Category: "ProAm"},
{Value: 2, Category: "Am"},
{Value: 3, Category: "Silver"},
{Value: 4, Category: "National"},
}
for _, cat := range categories {
if err := db.FirstOrCreate(&cat).Error; err != nil {
return err
}
}
return nil
}
func seedSessionTypes(db *gorm.DB) error {
sessionTypes := []model.SessionType{
{Value: 0, SessionType: "Practice"},
{Value: 4, SessionType: "Qualifying"},
{Value: 10, SessionType: "Race"},
}
for _, st := range sessionTypes {
if err := db.FirstOrCreate(&st).Error; err != nil {
return err
}
}
return nil
} }

View File

@@ -1,15 +0,0 @@
param (
[string]$Action,
[string]$ServiceName
)
if ($Action -eq "start") {
sc.exe start $ServiceName
} elseif ($Action -eq "stop") {
sc.exe stop $ServiceName
} elseif ($Action -eq "restart") {
sc.exe stop $ServiceName
sc.exe start $ServiceName
} else {
Write-Error "Invalid action specified. Use 'start', 'stop', or 'restart'."
}