add step list for server creation
This commit is contained in:
@@ -99,6 +99,62 @@ func (as *ConfigService) UpdateConfig(ctx *fiber.Ctx, body *map[string]interface
|
||||
return as.updateConfigInternal(ctx.UserContext(), serverID, configFile, body, override)
|
||||
}
|
||||
|
||||
func (as *ConfigService) updateConfigFiles(ctx context.Context, server *model.Server, configFile string, body *map[string]interface{}, override bool) ([]byte, []byte, error) {
|
||||
if server == nil {
|
||||
logging.Error("Server not found")
|
||||
return nil, nil, fmt.Errorf("server not found")
|
||||
}
|
||||
|
||||
configPath := filepath.Join(server.GetConfigPath(), configFile)
|
||||
oldData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
dir := filepath.Dir(configPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := os.WriteFile(configPath, []byte("{}"), 0644); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
oldData = []byte("{}")
|
||||
} else {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
oldDataUTF8, err := DecodeUTF16LEBOM(oldData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
newData, err := json.Marshal(&body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !override {
|
||||
newData, err = jsons.Merge(oldDataUTF8, newData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
newData, err = common.IndentJson(newData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
newDataUTF16, err := EncodeUTF16LEBOM(newData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(configPath, newDataUTF16, 0644); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return oldDataUTF8, newData, nil
|
||||
}
|
||||
|
||||
func (as *ConfigService) updateConfigInternal(ctx context.Context, serverID string, configFile string, body *map[string]interface{}, override bool) (*model.Config, error) {
|
||||
serverUUID, err := uuid.Parse(serverID)
|
||||
if err != nil {
|
||||
@@ -112,50 +168,8 @@ func (as *ConfigService) updateConfigInternal(ctx context.Context, serverID stri
|
||||
return nil, fmt.Errorf("server not found")
|
||||
}
|
||||
|
||||
configPath := filepath.Join(server.GetConfigPath(), configFile)
|
||||
oldData, err := os.ReadFile(configPath)
|
||||
oldDataUTF8, newData, err := as.updateConfigFiles(ctx, server, configFile, body, override)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
dir := filepath.Dir(configPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.WriteFile(configPath, []byte("{}"), 0644); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oldData = []byte("{}")
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
oldDataUTF8, err := DecodeUTF16LEBOM(oldData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newData, err := json.Marshal(&body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !override {
|
||||
newData, err = jsons.Merge(oldDataUTF8, newData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
newData, err = common.IndentJson(newData)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -181,42 +195,47 @@ func (as *ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
|
||||
logging.Debug("Getting config for server ID: %s, file: %s", serverIDStr, configFile)
|
||||
|
||||
server, err := as.serverRepository.GetByID(ctx.UserContext(), serverIDStr)
|
||||
|
||||
if err != nil {
|
||||
logging.Error("Server not found")
|
||||
return nil, fiber.NewError(404, "Server not found")
|
||||
}
|
||||
return as.getConfigFile(server, configFile)
|
||||
}
|
||||
|
||||
func (as *ConfigService) getConfigFile(server *model.Server, configFile string) (interface{}, error) {
|
||||
serverIDStr := server.ID.String()
|
||||
switch configFile {
|
||||
case ConfigurationJson:
|
||||
if cached, ok := as.configCache.GetConfiguration(serverIDStr); ok {
|
||||
logging.Debug("Returning cached configuration for server ID: %s", serverIDStr)
|
||||
return cached, nil
|
||||
return *cached, nil
|
||||
}
|
||||
case AssistRulesJson:
|
||||
if cached, ok := as.configCache.GetAssistRules(serverIDStr); ok {
|
||||
logging.Debug("Returning cached assist rules for server ID: %s", serverIDStr)
|
||||
return cached, nil
|
||||
return *cached, nil
|
||||
}
|
||||
case EventJson:
|
||||
if cached, ok := as.configCache.GetEvent(serverIDStr); ok {
|
||||
logging.Debug("Returning cached event config for server ID: %s", serverIDStr)
|
||||
return cached, nil
|
||||
return *cached, nil
|
||||
}
|
||||
case EventRulesJson:
|
||||
if cached, ok := as.configCache.GetEventRules(serverIDStr); ok {
|
||||
logging.Debug("Returning cached event rules for server ID: %s", serverIDStr)
|
||||
return cached, nil
|
||||
return *cached, nil
|
||||
}
|
||||
case SettingsJson:
|
||||
if cached, ok := as.configCache.GetSettings(serverIDStr); ok {
|
||||
logging.Debug("Returning cached settings for server ID: %s", serverIDStr)
|
||||
return cached, nil
|
||||
return *cached, nil
|
||||
}
|
||||
}
|
||||
|
||||
logging.Debug("Cache miss for server ID: %s, file: %s - loading from disk", serverIDStr, configFile)
|
||||
|
||||
configPath := filepath.Join(server.GetConfigPath(), configFile)
|
||||
configPath := server.GetConfigPath()
|
||||
decoder := DecodeFileName(configFile)
|
||||
if decoder == nil {
|
||||
return nil, errors.New("invalid config file")
|
||||
@@ -228,15 +247,15 @@ func (as *ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
|
||||
logging.Debug("Config file not found, creating default for server ID: %s, file: %s", serverIDStr, configFile)
|
||||
switch configFile {
|
||||
case ConfigurationJson:
|
||||
return &model.Configuration{}, nil
|
||||
return model.Configuration{}, nil
|
||||
case AssistRulesJson:
|
||||
return &model.AssistRules{}, nil
|
||||
return model.AssistRules{}, nil
|
||||
case EventJson:
|
||||
return &model.EventConfig{}, nil
|
||||
return model.EventConfig{}, nil
|
||||
case EventRulesJson:
|
||||
return &model.EventRules{}, nil
|
||||
return model.EventRules{}, nil
|
||||
case SettingsJson:
|
||||
return &model.ServerSettings{}, nil
|
||||
return model.ServerSettings{}, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
@@ -244,15 +263,15 @@ func (as *ConfigService) GetConfig(ctx *fiber.Ctx) (interface{}, error) {
|
||||
|
||||
switch configFile {
|
||||
case ConfigurationJson:
|
||||
as.configCache.UpdateConfiguration(serverIDStr, *config.(*model.Configuration))
|
||||
as.configCache.UpdateConfiguration(serverIDStr, config.(model.Configuration))
|
||||
case AssistRulesJson:
|
||||
as.configCache.UpdateAssistRules(serverIDStr, *config.(*model.AssistRules))
|
||||
as.configCache.UpdateAssistRules(serverIDStr, config.(model.AssistRules))
|
||||
case EventJson:
|
||||
as.configCache.UpdateEvent(serverIDStr, *config.(*model.EventConfig))
|
||||
as.configCache.UpdateEvent(serverIDStr, config.(model.EventConfig))
|
||||
case EventRulesJson:
|
||||
as.configCache.UpdateEventRules(serverIDStr, *config.(*model.EventRules))
|
||||
as.configCache.UpdateEventRules(serverIDStr, config.(model.EventRules))
|
||||
case SettingsJson:
|
||||
as.configCache.UpdateSettings(serverIDStr, *config.(*model.ServerSettings))
|
||||
as.configCache.UpdateSettings(serverIDStr, config.(model.ServerSettings))
|
||||
}
|
||||
|
||||
logging.Debug("Successfully loaded and cached config for server ID: %s, file: %s", serverIDStr, configFile)
|
||||
@@ -274,77 +293,33 @@ func (as *ConfigService) GetConfigs(ctx *fiber.Ctx) (*model.Configurations, erro
|
||||
func (as *ConfigService) LoadConfigs(server *model.Server) (*model.Configurations, error) {
|
||||
serverIDStr := server.ID.String()
|
||||
logging.Info("Loading configs for server ID: %s at path: %s", serverIDStr, server.GetConfigPath())
|
||||
configs := &model.Configurations{}
|
||||
|
||||
if cached, ok := as.configCache.GetConfiguration(serverIDStr); ok {
|
||||
logging.Debug("Using cached configuration for server %s", serverIDStr)
|
||||
configs.Configuration = *cached
|
||||
} else {
|
||||
logging.Debug("Loading configuration from disk for server %s", serverIDStr)
|
||||
config, err := mustDecode[model.Configuration](ConfigurationJson, server.GetConfigPath())
|
||||
if err != nil {
|
||||
logging.Error("Failed to load configuration for server %s: %v", serverIDStr, err)
|
||||
return nil, fmt.Errorf("failed to load configuration: %v", err)
|
||||
}
|
||||
configs.Configuration = config
|
||||
as.configCache.UpdateConfiguration(serverIDStr, config)
|
||||
settingsConf, err := as.getConfigFile(server, SettingsJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cached, ok := as.configCache.GetAssistRules(serverIDStr); ok {
|
||||
logging.Debug("Using cached assist rules for server %s", serverIDStr)
|
||||
configs.AssistRules = *cached
|
||||
} else {
|
||||
logging.Debug("Loading assist rules from disk for server %s", serverIDStr)
|
||||
rules, err := mustDecode[model.AssistRules](AssistRulesJson, server.GetConfigPath())
|
||||
if err != nil {
|
||||
logging.Error("Failed to load assist rules for server %s: %v", serverIDStr, err)
|
||||
return nil, fmt.Errorf("failed to load assist rules: %v", err)
|
||||
}
|
||||
configs.AssistRules = rules
|
||||
as.configCache.UpdateAssistRules(serverIDStr, rules)
|
||||
eventRulesConf, err := as.getConfigFile(server, EventRulesJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cached, ok := as.configCache.GetEvent(serverIDStr); ok {
|
||||
logging.Debug("Using cached event config for server %s", serverIDStr)
|
||||
configs.Event = *cached
|
||||
} else {
|
||||
logging.Debug("Loading event config from disk for server %s", serverIDStr)
|
||||
event, err := mustDecode[model.EventConfig](EventJson, server.GetConfigPath())
|
||||
if err != nil {
|
||||
logging.Error("Failed to load event config for server %s: %v", serverIDStr, err)
|
||||
return nil, fmt.Errorf("failed to load event config: %v", err)
|
||||
}
|
||||
configs.Event = event
|
||||
logging.Debug("Updating event config for server %s with track: %s", serverIDStr, event.Track)
|
||||
as.configCache.UpdateEvent(serverIDStr, event)
|
||||
eventConf, err := as.getConfigFile(server, EventJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cached, ok := as.configCache.GetEventRules(serverIDStr); ok {
|
||||
logging.Debug("Using cached event rules for server %s", serverIDStr)
|
||||
configs.EventRules = *cached
|
||||
} else {
|
||||
logging.Debug("Loading event rules from disk for server %s", serverIDStr)
|
||||
rules, err := mustDecode[model.EventRules](EventRulesJson, server.GetConfigPath())
|
||||
if err != nil {
|
||||
logging.Error("Failed to load event rules for server %s: %v", serverIDStr, err)
|
||||
return nil, fmt.Errorf("failed to load event rules: %v", err)
|
||||
}
|
||||
configs.EventRules = rules
|
||||
as.configCache.UpdateEventRules(serverIDStr, rules)
|
||||
assistRulesConf, err := as.getConfigFile(server, AssistRulesJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cached, ok := as.configCache.GetSettings(serverIDStr); ok {
|
||||
logging.Debug("Using cached settings for server %s", serverIDStr)
|
||||
configs.Settings = *cached
|
||||
} else {
|
||||
logging.Debug("Loading settings from disk for server %s", serverIDStr)
|
||||
settings, err := mustDecode[model.ServerSettings](SettingsJson, server.GetConfigPath())
|
||||
if err != nil {
|
||||
logging.Error("Failed to load settings for server %s: %v", serverIDStr, err)
|
||||
return nil, fmt.Errorf("failed to load settings: %v", err)
|
||||
}
|
||||
configs.Settings = settings
|
||||
as.configCache.UpdateSettings(serverIDStr, settings)
|
||||
configurationConf, err := as.getConfigFile(server, ConfigurationJson)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configs := &model.Configurations{
|
||||
Settings: settingsConf.(model.ServerSettings),
|
||||
EventRules: eventRulesConf.(model.EventRules),
|
||||
Event: eventConf.(model.EventConfig),
|
||||
AssistRules: assistRulesConf.(model.AssistRules),
|
||||
Configuration: configurationConf.(model.Configuration),
|
||||
}
|
||||
|
||||
logging.Info("Successfully loaded all configs for server %s", serverIDStr)
|
||||
@@ -369,9 +344,6 @@ func readFile(path string, configFile string) ([]byte, error) {
|
||||
configPath := filepath.Join(path, configFile)
|
||||
oldData, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil, fmt.Errorf("config file %s does not exist at %s", configFile, configPath)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return oldData, nil
|
||||
@@ -458,6 +430,6 @@ func (as *ConfigService) SaveConfiguration(server *model.Server, config *model.C
|
||||
return fmt.Errorf("failed to unmarshal configuration: %v", err)
|
||||
}
|
||||
|
||||
_, err = as.updateConfigInternal(context.Background(), server.ID.String(), ConfigurationJson, &configMap, true)
|
||||
_, _, err = as.updateConfigFiles(context.Background(), server, ConfigurationJson, &configMap, true)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -308,7 +308,9 @@ func (as *ServerService) GetById(ctx *fiber.Ctx, serverID uuid.UUID) (*model.Ser
|
||||
}
|
||||
|
||||
func (s *ServerService) CreateServerAsync(ctx *fiber.Ctx, server *model.Server) error {
|
||||
logging.Info("create server start")
|
||||
if err := server.Validate(); err != nil {
|
||||
logging.Info("create server validation failed")
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -317,6 +319,7 @@ func (s *ServerService) CreateServerAsync(ctx *fiber.Ctx, server *model.Server)
|
||||
bgCtx := context.Background()
|
||||
|
||||
go func() {
|
||||
logging.Info("create server start background")
|
||||
if err := s.createServerBackground(bgCtx, server); err != nil {
|
||||
logging.Error("Async server creation failed for server %s: %v", server.ID, err)
|
||||
s.webSocketService.BroadcastError(server.ID, "Server creation failed", err.Error())
|
||||
@@ -327,105 +330,126 @@ func (s *ServerService) CreateServerAsync(ctx *fiber.Ctx, server *model.Server)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerService) CreateServer(ctx *fiber.Ctx, server *model.Server) error {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepValidation), "")
|
||||
type createServerStep struct {
|
||||
stepType model.ServerCreationStep
|
||||
important bool
|
||||
callback func() (string, error)
|
||||
description string
|
||||
}
|
||||
|
||||
if err := server.Validate(); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusFailed,
|
||||
"", fmt.Sprintf("Validation failed: %v", err))
|
||||
return err
|
||||
func (s *ServerService) createServerBackground(ctx context.Context, server *model.Server) error {
|
||||
var serverPort int
|
||||
var tcpPorts, udpPorts []int
|
||||
|
||||
steps := []createServerStep{
|
||||
{
|
||||
stepType: model.StepValidation,
|
||||
important: true,
|
||||
description: "Server configuration validated successfully",
|
||||
callback: func() (string, error) {
|
||||
if err := server.Validate(); err != nil {
|
||||
return "", fmt.Errorf("validation failed: %v", err)
|
||||
}
|
||||
return "Server configuration validated successfully", nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepDirectoryCreation,
|
||||
important: true,
|
||||
description: "Server directories prepared",
|
||||
callback: func() (string, error) {
|
||||
return "Server directories prepared", nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepSteamDownload,
|
||||
important: true,
|
||||
description: "Server files downloaded successfully",
|
||||
callback: func() (string, error) {
|
||||
if err := s.steamService.InstallServerWithWebSocket(ctx, server.Path, &server.ID, s.webSocketService); err != nil {
|
||||
return "", fmt.Errorf("failed to install server: %v", err)
|
||||
}
|
||||
return "Server files downloaded successfully", nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepConfigGeneration,
|
||||
important: true,
|
||||
description: "",
|
||||
callback: func() (string, error) {
|
||||
ports, err := network.FindAvailablePortRange(DefaultStartPort, RequiredPortCount)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find available ports: %v", err)
|
||||
}
|
||||
|
||||
serverPort = ports[0]
|
||||
|
||||
if err := s.updateServerPort(server, serverPort); err != nil {
|
||||
return "", fmt.Errorf("failed to update server configuration: %v", err)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Server configuration generated (Port: %d)", serverPort), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepServiceCreation,
|
||||
important: true,
|
||||
description: "",
|
||||
callback: func() (string, error) {
|
||||
execPath := filepath.Join(server.GetServerPath(), "accServer.exe")
|
||||
serverWorkingDir := filepath.Join(server.GetServerPath(), "server")
|
||||
if err := s.windowsService.CreateService(ctx, server.ServiceName, execPath, serverWorkingDir, nil); err != nil {
|
||||
return "", fmt.Errorf("failed to create Windows service: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("Windows service '%s' created successfully", server.ServiceName), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepFirewallRules,
|
||||
important: false,
|
||||
description: "",
|
||||
callback: func() (string, error) {
|
||||
s.configureFirewall(server)
|
||||
tcpPorts = []int{serverPort}
|
||||
udpPorts = []int{serverPort}
|
||||
if err := s.firewallService.CreateServerRules(server.ServiceName, tcpPorts, udpPorts); err != nil {
|
||||
return "", fmt.Errorf("failed to create firewall rules: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("Firewall rules created for port %d", serverPort), nil
|
||||
},
|
||||
},
|
||||
{
|
||||
stepType: model.StepDatabaseSave,
|
||||
important: true,
|
||||
description: "Server saved to database successfully",
|
||||
callback: func() (string, error) {
|
||||
if err := s.repository.Insert(ctx, server); err != nil {
|
||||
return "", fmt.Errorf("failed to insert server into database: %v", err)
|
||||
}
|
||||
return "Server saved to database successfully", nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusCompleted,
|
||||
"Server configuration validated successfully", "")
|
||||
for i, step := range steps {
|
||||
s.webSocketService.BroadcastStep(server.ID, step.stepType, model.StatusInProgress,
|
||||
model.GetStepDescription(step.stepType), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDirectoryCreation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepDirectoryCreation), "")
|
||||
successMessage, err := step.callback()
|
||||
if err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, step.stepType, model.StatusFailed,
|
||||
"", err.Error())
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDirectoryCreation, model.StatusCompleted,
|
||||
"Server directories prepared", "")
|
||||
if step.important {
|
||||
s.rollbackSteps(ctx, server, steps[:i], tcpPorts, udpPorts)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepSteamDownload), "")
|
||||
|
||||
if err := s.steamService.InstallServerWithWebSocket(ctx.UserContext(), server.Path, &server.ID, s.webSocketService); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusFailed,
|
||||
"", fmt.Sprintf("Steam installation failed: %v", err))
|
||||
return fmt.Errorf("failed to install server: %v", err)
|
||||
s.webSocketService.BroadcastStep(server.ID, step.stepType, model.StatusCompleted,
|
||||
successMessage, "")
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusCompleted,
|
||||
"Server files downloaded successfully", "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepConfigGeneration), "")
|
||||
|
||||
ports, err := network.FindAvailablePortRange(DefaultStartPort, RequiredPortCount)
|
||||
if err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to find available ports: %v", err))
|
||||
return fmt.Errorf("failed to find available ports: %v", err)
|
||||
}
|
||||
|
||||
serverPort := ports[0]
|
||||
|
||||
if err := s.updateServerPort(server, serverPort); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to update server configuration: %v", err))
|
||||
return fmt.Errorf("failed to update server configuration: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusCompleted,
|
||||
fmt.Sprintf("Server configuration generated (Port: %d)", serverPort), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepServiceCreation), "")
|
||||
|
||||
execPath := filepath.Join(server.GetServerPath(), "accServer.exe")
|
||||
serverWorkingDir := filepath.Join(server.GetServerPath(), "server")
|
||||
if err := s.windowsService.CreateService(ctx.UserContext(), server.ServiceName, execPath, serverWorkingDir, nil); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to create Windows service: %v", err))
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to create Windows service: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusCompleted,
|
||||
fmt.Sprintf("Windows service '%s' created successfully", server.ServiceName), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepFirewallRules), "")
|
||||
|
||||
s.configureFirewall(server)
|
||||
tcpPorts := []int{serverPort}
|
||||
udpPorts := []int{serverPort}
|
||||
if err := s.firewallService.CreateServerRules(server.ServiceName, tcpPorts, udpPorts); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to create firewall rules: %v", err))
|
||||
s.windowsService.DeleteService(ctx.UserContext(), server.ServiceName)
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to create firewall rules: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusCompleted,
|
||||
fmt.Sprintf("Firewall rules created for port %d", serverPort), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepDatabaseSave), "")
|
||||
|
||||
if err := s.repository.Insert(ctx.UserContext(), server); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to save server to database: %v", err))
|
||||
s.firewallService.DeleteServerRules(server.ServiceName, tcpPorts, udpPorts)
|
||||
s.windowsService.DeleteService(ctx.UserContext(), server.ServiceName)
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to insert server into database: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusCompleted,
|
||||
"Server saved to database successfully", "")
|
||||
|
||||
s.StartAccServerRuntime(server)
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepCompleted, model.StatusCompleted,
|
||||
@@ -437,114 +461,22 @@ func (s *ServerService) CreateServer(ctx *fiber.Ctx, server *model.Server) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerService) createServerBackground(ctx context.Context, server *model.Server) error {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepValidation), "")
|
||||
|
||||
if err := server.Validate(); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusFailed,
|
||||
"", fmt.Sprintf("Validation failed: %v", err))
|
||||
return err
|
||||
func (s *ServerService) rollbackSteps(ctx context.Context, server *model.Server, completedSteps []createServerStep, tcpPorts, udpPorts []int) {
|
||||
for i := len(completedSteps) - 1; i >= 0; i-- {
|
||||
step := completedSteps[i]
|
||||
switch step.stepType {
|
||||
case model.StepDatabaseSave:
|
||||
s.repository.Delete(ctx, server.ID)
|
||||
case model.StepFirewallRules:
|
||||
if len(tcpPorts) > 0 && len(udpPorts) > 0 {
|
||||
s.firewallService.DeleteServerRules(server.ServiceName, tcpPorts, udpPorts)
|
||||
}
|
||||
case model.StepServiceCreation:
|
||||
s.windowsService.DeleteService(ctx, server.ServiceName)
|
||||
case model.StepSteamDownload:
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
}
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepValidation, model.StatusCompleted,
|
||||
"Server configuration validated successfully", "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDirectoryCreation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepDirectoryCreation), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDirectoryCreation, model.StatusCompleted,
|
||||
"Server directories prepared", "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepSteamDownload), "")
|
||||
|
||||
if err := s.steamService.InstallServerWithWebSocket(ctx, server.Path, &server.ID, s.webSocketService); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusFailed,
|
||||
"", fmt.Sprintf("Steam installation failed: %v", err))
|
||||
return fmt.Errorf("failed to install server: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepSteamDownload, model.StatusCompleted,
|
||||
"Server files downloaded successfully", "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepConfigGeneration), "")
|
||||
|
||||
ports, err := network.FindAvailablePortRange(DefaultStartPort, RequiredPortCount)
|
||||
if err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to find available ports: %v", err))
|
||||
return fmt.Errorf("failed to find available ports: %v", err)
|
||||
}
|
||||
|
||||
serverPort := ports[0]
|
||||
|
||||
if err := s.updateServerPort(server, serverPort); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to update server configuration: %v", err))
|
||||
return fmt.Errorf("failed to update server configuration: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepConfigGeneration, model.StatusCompleted,
|
||||
fmt.Sprintf("Server configuration generated (Port: %d)", serverPort), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepServiceCreation), "")
|
||||
|
||||
execPath := filepath.Join(server.GetServerPath(), "accServer.exe")
|
||||
serverWorkingDir := filepath.Join(server.GetServerPath(), "server")
|
||||
if err := s.windowsService.CreateService(ctx, server.ServiceName, execPath, serverWorkingDir, nil); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to create Windows service: %v", err))
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to create Windows service: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepServiceCreation, model.StatusCompleted,
|
||||
fmt.Sprintf("Windows service '%s' created successfully", server.ServiceName), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepFirewallRules), "")
|
||||
|
||||
s.configureFirewall(server)
|
||||
tcpPorts := []int{serverPort}
|
||||
udpPorts := []int{serverPort}
|
||||
if err := s.firewallService.CreateServerRules(server.ServiceName, tcpPorts, udpPorts); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to create firewall rules: %v", err))
|
||||
s.windowsService.DeleteService(ctx, server.ServiceName)
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to create firewall rules: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepFirewallRules, model.StatusCompleted,
|
||||
fmt.Sprintf("Firewall rules created for port %d", serverPort), "")
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusInProgress,
|
||||
model.GetStepDescription(model.StepDatabaseSave), "")
|
||||
|
||||
if err := s.repository.Insert(ctx, server); err != nil {
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusFailed,
|
||||
"", fmt.Sprintf("Failed to save server to database: %v", err))
|
||||
s.firewallService.DeleteServerRules(server.ServiceName, tcpPorts, udpPorts)
|
||||
s.windowsService.DeleteService(ctx, server.ServiceName)
|
||||
s.steamService.UninstallServer(server.Path)
|
||||
return fmt.Errorf("failed to insert server into database: %v", err)
|
||||
}
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepDatabaseSave, model.StatusCompleted,
|
||||
"Server saved to database successfully", "")
|
||||
|
||||
s.StartAccServerRuntime(server)
|
||||
|
||||
s.webSocketService.BroadcastStep(server.ID, model.StepCompleted, model.StatusCompleted,
|
||||
model.GetStepDescription(model.StepCompleted), "")
|
||||
|
||||
s.webSocketService.BroadcastComplete(server.ID, true,
|
||||
fmt.Sprintf("Server '%s' created successfully on port %d", server.Name, serverPort))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerService) DeleteServer(ctx *fiber.Ctx, serverID uuid.UUID) error {
|
||||
|
||||
Reference in New Issue
Block a user