namespace MSCO.Server; /// /// server.json im Web-Panel lesen und ändern - bei laufendem Server (dann sofort wirksam) und wenn er aus ist /// (z.B. Lizenzschlüssel eintragen, damit er überhaupt starten kann). /// public static class ConfigEditor { public static object Build(ServerConfig config) => new { name = config.Name, description = config.Description, maxPlayers = config.MaxPlayers, isPublic = config.Public, requireSteam = config.RequireSteam, publicAddress = config.PublicAddress, saveSyncMinutes = config.SaveSyncMinutes, licenseGraceHours = config.LicenseGraceHours, autosaveSeconds = config.AutosaveSeconds, port = config.Port, panelEnabled = config.PanelEnabled, panelPort = config.PanelPort, panelBindAddress = config.PanelBindAddress, panelTrustProxy = config.PanelTrustProxy, panelBasePath = config.PanelBasePath, licenseKeySet = !string.IsNullOrWhiteSpace(config.LicenseKey), steamWebApiKeySet = !string.IsNullOrWhiteSpace(config.SteamWebApiKey), environmentOverrides = config.EnvironmentOverrides, // In Docker muss ein anderer Port zusätzlich in docker-compose.yml freigegeben werden (Warnung im Panel) inDocker = Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true" }; /// Einstellungen ändern. Schlüssel (Lizenz, Steam Web API) nur als Owner; leer = unverändert. public static string Apply(ServerConfig config, string configPath, System.Text.Json.JsonElement b, bool owner, string by) { if (b.ValueKind != System.Text.Json.JsonValueKind.Object) return "Invalid settings"; var changed = new List(); bool restartNeeded = false; string Text(string name, string current, int max) { if (!b.TryGetProperty(name, out var v) || v.ValueKind != System.Text.Json.JsonValueKind.String) return current; string s = v.GetString().Trim(); if (s.Length > max) s = s[..max]; if (s != current) changed.Add(name); return s; } int Number(string name, int current, int min, int max) { if (!b.TryGetProperty(name, out var v) || !v.TryGetInt32(out int n)) return current; n = Math.Clamp(n, min, max); if (n != current) changed.Add(name); return n; } bool Flag(string name, bool current) { if (!b.TryGetProperty(name, out var v) || (v.ValueKind != System.Text.Json.JsonValueKind.True && v.ValueKind != System.Text.Json.JsonValueKind.False)) return current; bool f = v.GetBoolean(); if (f != current) changed.Add(name); return f; } string name = Text("name", config.Name, 60); if (name.Length == 0) return "The server name cannot be empty"; config.Name = name; config.Description = Text("description", config.Description, 300); config.MaxPlayers = Number("maxPlayers", config.MaxPlayers, 1, 64); config.Public = Flag("isPublic", config.Public); config.RequireSteam = Flag("requireSteam", config.RequireSteam); config.PublicAddress = Text("publicAddress", config.PublicAddress, 200); config.SaveSyncMinutes = Number("saveSyncMinutes", config.SaveSyncMinutes, 0, 240); config.AutosaveSeconds = Number("autosaveSeconds", config.AutosaveSeconds, 10, 3600); config.LicenseGraceHours = Number("licenseGraceHours", config.LicenseGraceHours, 1, 720); int before = changed.Count; int oldPort = config.Port, oldPanelPort = config.PanelPort; config.Port = Number("port", config.Port, 1, 65535); config.PanelEnabled = Flag("panelEnabled", config.PanelEnabled); config.PanelPort = Number("panelPort", config.PanelPort, 0, 65535); config.PanelBindAddress = Text("panelBindAddress", config.PanelBindAddress, 60); config.PanelTrustProxy = Flag("panelTrustProxy", config.PanelTrustProxy); config.PanelBasePath = Text("panelBasePath", config.PanelBasePath, 60); if (changed.Count > before) restartNeeded = true; // Ports gehören dem Programm, nicht dem Gameserver: "Restart" im Panel reicht dafür nicht bool portChanged = config.Port != oldPort || config.PanelPort != oldPanelPort; foreach (string secret in new[] { "licenseKey", "steamWebApiKey" }) { if (!b.TryGetProperty(secret, out var v) || v.ValueKind != System.Text.Json.JsonValueKind.String || v.GetString().Trim().Length == 0) continue; if (!owner) return "Only the owner can change keys"; string value = v.GetString().Trim(); if (value.Length > 200) return "Key too long"; if (secret == "licenseKey") config.LicenseKey = value; else config.SteamWebApiKey = value; changed.Add(secret); restartNeeded = true; } if (changed.Count == 0) return "Nothing changed"; try { config.Save(configPath); } catch (Exception e) { return "Could not save server.json: " + e.Message; } GameServer.Log($"Settings changed by {by}: {string.Join(", ", changed)}"); var overridden = changed.Where(c => config.EnvironmentOverrides.Any(e => e.Replace("_", "").Contains(c.ToUpperInvariant().Replace("ISPUBLIC", "PUBLIC")))).ToList(); return "Settings saved" + (portChanged ? " - the new port only applies after the whole program restarts (docker compose restart); in Docker publish it in docker-compose.yml first" : restartNeeded ? " - some changes need a restart" : "") + (overridden.Count > 0 ? " (note: " + string.Join(", ", overridden) + " is also set by an environment variable, which wins on restart)" : ""); } }