diff --git a/local/controller/api.go b/local/controller/api.go index c8fc6f1..a8489fe 100644 --- a/local/controller/api.go +++ b/local/controller/api.go @@ -3,6 +3,7 @@ package controller import ( "acc-server-manager/local/service" "acc-server-manager/local/utl/common" + "strings" "github.com/gofiber/fiber/v2" ) @@ -54,19 +55,19 @@ func (ac *ApiController) getFirst(c *fiber.Ctx) error { // @Success 200 {array} string // @Router /v1/api/{service} [get] func (ac *ApiController) getStatus(c *fiber.Ctx) error { - serverId, err := c.ParamsInt("serverId") - if err != nil { - return c.Status(400).SendString(err.Error()) - } - if serverId == 0 { - service := c.Params("service") - c.Locals("service", service) - } else { + service := c.Params("service") + if service == "" { + serverId, err := c.ParamsInt("service") + if err != nil { + return c.Status(400).SendString(err.Error()) + } c.Locals("serverId", serverId) + } else { + c.Locals("service", service) } apiModel, err := ac.service.GetStatus(c) if err != nil { - return c.Status(400).SendString(err.Error()) + return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", "")) } return c.SendString(apiModel) } @@ -88,7 +89,7 @@ func (ac *ApiController) startServer(c *fiber.Ctx) error { c.Locals("serverId", model.ServerId) apiModel, err := ac.service.ApiStartServer(c) if err != nil { - return c.Status(400).SendString(err.Error()) + return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", "")) } return c.SendString(apiModel) } @@ -110,7 +111,7 @@ func (ac *ApiController) stopServer(c *fiber.Ctx) error { c.Locals("serverId", model.ServerId) apiModel, err := ac.service.ApiStopServer(c) if err != nil { - return c.Status(400).SendString(err.Error()) + return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", "")) } return c.SendString(apiModel) } @@ -132,7 +133,7 @@ func (ac *ApiController) restartServer(c *fiber.Ctx) error { c.Locals("serverId", model.ServerId) apiModel, err := ac.service.ApiRestartServer(c) if err != nil { - return c.Status(400).SendString(err.Error()) + return c.Status(400).SendString(strings.ReplaceAll(err.Error(), "\x00", "")) } return c.SendString(apiModel) } diff --git a/local/controller/config.go b/local/controller/config.go index 43099b4..eb76c99 100644 --- a/local/controller/config.go +++ b/local/controller/config.go @@ -58,7 +58,11 @@ func (ac *ConfigController) updateConfig(c *fiber.Ctx) error { return c.Status(400).SendString(err.Error()) } if restart { - ac.apiService.RestartServer(c) + serviceName, err := ac.apiService.GetServiceName(c) + if err != nil { + return c.Status(400).JSON(fiber.Map{"error": "Unable to restart service"}) + } + ac.apiService.RestartServer(serviceName) } return c.JSON(ConfigModel) diff --git a/local/controller/server.go b/local/controller/server.go index 99865d3..16055b5 100644 --- a/local/controller/server.go +++ b/local/controller/server.go @@ -25,6 +25,7 @@ func NewServerController(as *service.ServerService, routeGroups *common.RouteGro } routeGroups.Server.Get("/", ac.getAll) + routeGroups.Server.Get("/:id", ac.getById) return ac } @@ -40,3 +41,16 @@ func (ac *ServerController) getAll(c *fiber.Ctx) error { ServerModel := ac.service.GetAll(c) return c.JSON(ServerModel) } + +// getById returns Servers +// +// @Summary Return Servers +// @Description Return Servers +// @Tags Server +// @Success 200 {array} string +// @Router /v1/server [get] +func (ac *ServerController) getById(c *fiber.Ctx) error { + serverID, _ := c.ParamsInt("id") + ServerModel := ac.service.GetById(c, serverID) + return c.JSON(ServerModel) +} diff --git a/local/model/config.go b/local/model/config.go index 2b8d8c3..e60db2c 100644 --- a/local/model/config.go +++ b/local/model/config.go @@ -4,76 +4,76 @@ 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"` + ID uint `json:"id" gorm:"primaryKey"` + ServerID uint `json:"serverId" gorm:"not null"` + ConfigFile string `json:"configFile" gorm:"not null"` // e.g. "settings.json" + OldConfig string `json:"oldConfig" gorm:"type:text"` + NewConfig string `json:"newConfig" gorm:"type:text"` + ChangedAt time.Time `json:"changedAt" 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{} + Configuration map[string]interface{} `json:"configuration"` + Entrylist map[string]interface{} `json:"entrylist"` + Event map[string]interface{} `json:"event"` + EventRules map[string]interface{} `json:"eventRules"` + Settings map[string]interface{} `json:"settings"` } type ServerSettings struct { - ServerName string `json:"serverName"` - AdminPassword string `json:"adminPassword"` - CarGroup string `json:"carGroup"` - TrackMedalsRequirement int `json:"trackMedalsRequirement"` - SafetyRatingRequirement int `json:"safetyRatingRequirement"` - RacecraftRatingRequirement int `json:"racecraftRatingRequirement"` - Password string `json:"password"` - SpectatorPassword string `json:"spectatorPassword"` - MaxCarSlots int `json:"maxCarSlots"` - DumpLeaderboards int `json:"dumpLeaderboards"` - IsRaceLocked int `json:"isRaceLocked"` - RandomizeTrackWhenEmpty int `json:"randomizeTrackWhenEmpty"` - CentralEntryListPath string `json:"centralEntryListPath"` - AllowAutoDQ int `json:"allowAutoDQ"` - ShortFormationLap int `json:"shortFormationLap"` - FormationLapType int `json:"formationLapType"` - IgnorePrematureDisconnects int `json:"ignorePrematureDisconnects"` + ServerName string `json:"serverName"` + AdminPassword string `json:"adminPassword"` + CarGroup string `json:"carGroup"` + TrackMedalsRequirement int `json:"trackMedalsRequirement"` + SafetyRatingRequirement int `json:"safetyRatingRequirement"` + RacecraftRatingRequirement int `json:"racecraftRatingRequirement"` + Password string `json:"password"` + SpectatorPassword string `json:"spectatorPassword"` + MaxCarSlots int `json:"maxCarSlots"` + DumpLeaderboards int `json:"dumpLeaderboards"` + IsRaceLocked int `json:"isRaceLocked"` + RandomizeTrackWhenEmpty int `json:"randomizeTrackWhenEmpty"` + CentralEntryListPath string `json:"centralEntryListPath"` + AllowAutoDQ int `json:"allowAutoDQ"` + ShortFormationLap int `json:"shortFormationLap"` + FormationLapType int `json:"formationLapType"` + IgnorePrematureDisconnects int `json:"ignorePrematureDisconnects"` } type EventConfig struct { - Track string `json:"track"` - PreRaceWaitingTimeSeconds int `json:"preRaceWaitingTimeSeconds"` - SessionOverTimeSeconds int `json:"sessionOverTimeSeconds"` - AmbientTemp int `json:"ambientTemp"` - CloudLevel float64 `json:"cloudLevel"` - Rain float64 `json:"rain"` - WeatherRandomness int `json:"weatherRandomness"` - PostQualySeconds int `json:"postQualySeconds"` - PostRaceSeconds int `json:"postRaceSeconds"` - SimracerWeatherConditions int `json:"simracerWeatherConditions"` - IsFixedConditionQualification int `json:"isFixedConditionQualification"` - - Sessions []Session `json:"sessions"` + Track string `json:"track"` + PreRaceWaitingTimeSeconds int `json:"preRaceWaitingTimeSeconds"` + SessionOverTimeSeconds int `json:"sessionOverTimeSeconds"` + AmbientTemp int `json:"ambientTemp"` + CloudLevel float64 `json:"cloudLevel"` + Rain float64 `json:"rain"` + WeatherRandomness int `json:"weatherRandomness"` + PostQualySeconds int `json:"postQualySeconds"` + PostRaceSeconds int `json:"postRaceSeconds"` + SimracerWeatherConditions int `json:"simracerWeatherConditions"` + IsFixedConditionQualification int `json:"isFixedConditionQualification"` + + Sessions []Session `json:"sessions"` } type Session struct { - HourOfDay int `json:"hourOfDay"` - DayOfWeekend int `json:"dayOfWeekend"` - TimeMultiplier int `json:"timeMultiplier"` - SessionType string `json:"sessionType"` - SessionDurationMinutes int `json:"sessionDurationMinutes"` + HourOfDay int `json:"hourOfDay"` + DayOfWeekend int `json:"dayOfWeekend"` + TimeMultiplier int `json:"timeMultiplier"` + SessionType string `json:"sessionType"` + SessionDurationMinutes int `json:"sessionDurationMinutes"` } type EventRules struct { - QualifyStandingType int `json:"qualifyStandingType"` - PitWindowLengthSec int `json:"pitWindowLengthSec"` - DriverStintTimeSec int `json:"driverStintTimeSec"` - MandatoryPitstopCount int `json:"mandatoryPitstopCount"` - MaxTotalDrivingTime int `json:"maxTotalDrivingTime"` - IsRefuellingAllowedInRace bool `json:"isRefuellingAllowedInRace"` - IsRefuellingTimeFixed bool `json:"isRefuellingTimeFixed"` - IsMandatoryPitstopRefuellingRequired bool `json:"isMandatoryPitstopRefuellingRequired"` - IsMandatoryPitstopTyreChangeRequired bool `json:"isMandatoryPitstopTyreChangeRequired"` - IsMandatoryPitstopSwapDriverRequired bool `json:"isMandatoryPitstopSwapDriverRequired"` - TyreSetCount int `json:"tyreSetCount"` -} \ No newline at end of file + QualifyStandingType int `json:"qualifyStandingType"` + PitWindowLengthSec int `json:"pitWindowLengthSec"` + DriverStintTimeSec int `json:"driverStintTimeSec"` + MandatoryPitstopCount int `json:"mandatoryPitstopCount"` + MaxTotalDrivingTime int `json:"maxTotalDrivingTime"` + IsRefuellingAllowedInRace bool `json:"isRefuellingAllowedInRace"` + IsRefuellingTimeFixed bool `json:"isRefuellingTimeFixed"` + IsMandatoryPitstopRefuellingRequired bool `json:"isMandatoryPitstopRefuellingRequired"` + IsMandatoryPitstopTyreChangeRequired bool `json:"isMandatoryPitstopTyreChangeRequired"` + IsMandatoryPitstopSwapDriverRequired bool `json:"isMandatoryPitstopSwapDriverRequired"` + TyreSetCount int `json:"tyreSetCount"` +} diff --git a/local/model/server.go b/local/model/server.go index 14ed096..d3a33a2 100644 --- a/local/model/server.go +++ b/local/model/server.go @@ -2,10 +2,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 + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"not null" json:"name"` + Status string `json:"status"` + IP string `gorm:"not null" json:"-"` + Port int `gorm:"not null" json:"-"` + ConfigPath string `gorm:"not null" json:"-"` // e.g. "/acc/servers/server1/" + ServiceName string `gorm:"not null" json:"-"` // Windows service name } diff --git a/local/service/api.go b/local/service/api.go index ca78439..d85a122 100644 --- a/local/service/api.go +++ b/local/service/api.go @@ -5,6 +5,7 @@ import ( "acc-server-manager/local/repository" "acc-server-manager/local/utl/common" "errors" + "strings" "github.com/gofiber/fiber/v2" ) @@ -34,38 +35,65 @@ func (as ApiService) GetFirst(ctx *fiber.Ctx) *model.ApiModel { } func (as ApiService) GetStatus(ctx *fiber.Ctx) (string, error) { - return as.StatusServer(ctx) + serviceName, err := as.GetServiceName(ctx) + if err != nil { + return "", err + } + status, err := as.StatusServer(serviceName) + + return status, err } func (as ApiService) ApiStartServer(ctx *fiber.Ctx) (string, error) { - return as.StartServer(ctx) + serviceName, err := as.GetServiceName(ctx) + if err != nil { + return "", err + } + return as.StartServer(serviceName) } func (as ApiService) ApiStopServer(ctx *fiber.Ctx) (string, error) { - return as.StopServer(ctx) + serviceName, err := as.GetServiceName(ctx) + if err != nil { + return "", err + } + return as.StopServer(serviceName) } func (as ApiService) ApiRestartServer(ctx *fiber.Ctx) (string, error) { - return as.RestartServer(ctx) + serviceName, err := as.GetServiceName(ctx) + if err != nil { + return "", err + } + return as.RestartServer(serviceName) } -func (as ApiService) StatusServer(ctx *fiber.Ctx) (string, error) { - return as.ManageService(ctx, "status") +func (as ApiService) StatusServer(serviceName string) (string, error) { + return ManageService(serviceName, "status") } -func (as ApiService) StartServer(ctx *fiber.Ctx) (string, error) { - return as.ManageService(ctx, "start") +func (as ApiService) StartServer(serviceName string) (string, error) { + return ManageService(serviceName, "start") } -func (as ApiService) StopServer(ctx *fiber.Ctx) (string, error) { - return as.ManageService(ctx, "stop") +func (as ApiService) StopServer(serviceName string) (string, error) { + return ManageService(serviceName, "stop") } -func (as ApiService) RestartServer(ctx *fiber.Ctx) (string, error) { - return as.ManageService(ctx, "restart") +func (as ApiService) RestartServer(serviceName string) (string, error) { + return ManageService(serviceName, "restart") } -func (as ApiService) ManageService(ctx *fiber.Ctx, action string) (string, error) { +func ManageService(serviceName string, action string) (string, error) { + output, err := common.RunElevatedCommand(action, serviceName) + if err != nil { + return "", err + } + + return strings.ReplaceAll(output, "\x00", ""), nil +} + +func (as ApiService) GetServiceName(ctx *fiber.Ctx) (string, error) { var server *model.Server serviceName, ok := ctx.Locals("service").(string) if !ok || serviceName == "" { @@ -80,10 +108,5 @@ func (as ApiService) ManageService(ctx *fiber.Ctx, action string) (string, error if server == nil { return "", fiber.NewError(404, "Server not found") } - - output, err := common.RunElevatedCommand(action, server.ServiceName) - if err != nil { - return "", err - } - return output, nil + return server.ServiceName, nil } diff --git a/local/service/server.go b/local/service/server.go index 84d847f..bd67394 100644 --- a/local/service/server.go +++ b/local/service/server.go @@ -9,11 +9,13 @@ import ( type ServerService struct { repository *repository.ServerRepository + apiService *ApiService } -func NewServerService(repository *repository.ServerRepository) *ServerService { +func NewServerService(repository *repository.ServerRepository, apiService *ApiService) *ServerService { return &ServerService{ repository: repository, + apiService: apiService, } } @@ -25,5 +27,27 @@ func NewServerService(repository *repository.ServerRepository) *ServerService { // Returns: // string: Application version func (as ServerService) GetAll(ctx *fiber.Ctx) *[]model.Server { - return as.repository.GetAll(ctx.UserContext()) + servers := as.repository.GetAll(ctx.UserContext()) + + for i, server := range *servers { + status, _ := as.apiService.StatusServer(server.ServiceName) + (*servers)[i].Status = status + } + + return servers } + +// GetById +// Gets rows by ID from Server table. +// +// Args: +// context.Context: Application context +// Returns: +// string: Application version +func (as ServerService) GetById(ctx *fiber.Ctx, serverID int) *model.Server { + server := as.repository.GetFirst(ctx.UserContext(), serverID) + server.Status, _ = as.apiService.StatusServer(server.ServiceName); + + return server +} +