Files
MSCO-Dedicated-Server/ConfigEditor.cs
T

109 lines
5.8 KiB
C#

namespace MSCO.Server;
/// <summary>
/// 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).
/// </summary>
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"
};
/// <summary>Einstellungen ändern. Schlüssel (Lizenz, Steam Web API) nur als Owner; leer = unverändert.</summary>
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<string>();
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)" : "");
}
}