From 4d1018b7a58e604972a0f59de72d22ebd7312e58 Mon Sep 17 00:00:00 2001 From: compujuckel Date: Sun, 21 Jan 2024 19:40:38 +0100 Subject: [PATCH] - do not override minimum CSP version if version in server_cfg is higher than extra_cfg - always print file path on config file parsing errors - improve exception messages --- AssettoServer/ExceptionHelper.cs | 34 ++++-- .../Configuration/ACServerConfiguration.cs | 106 ++++++++++++------ .../ConfigurationParsingException.cs | 18 +++ AssettoServer/Utils/ProcessHelper.cs | 5 + 4 files changed, 119 insertions(+), 44 deletions(-) create mode 100644 AssettoServer/Server/Configuration/ConfigurationParsingException.cs diff --git a/AssettoServer/ExceptionHelper.cs b/AssettoServer/ExceptionHelper.cs index cd5a85db..8b34c20f 100644 --- a/AssettoServer/ExceptionHelper.cs +++ b/AssettoServer/ExceptionHelper.cs @@ -30,23 +30,33 @@ or another Discord server. public static void PrintExceptionHelp(Exception ex, bool isContentManager, string? crashReportPath) { string? helpLink = null; + string? configPath = null; while (ex is DependencyResolutionException && ex.InnerException != null) { ex = ex.InnerException; } + + if (ex is ConfigurationParsingException cfgEx) + { + configPath = cfgEx.Path; + if (ex.InnerException != null) + { + ex = ex.InnerException; + } + } Console.WriteLine(); switch (ex) { case YamlException yamlException: - WrapText(YamlExceptionHelp(yamlException), isContentManager); + WrapText(YamlExceptionHelp(yamlException, configPath), isContentManager); break; case ParsingException when ex.InnerException is FileNotFoundException fnfException: WrapText(fnfException.Message, isContentManager); break; case ParsingException iniException: - WrapText(IniExceptionHelp(iniException), isContentManager); + WrapText(IniExceptionHelp(iniException, configPath), isContentManager); break; case IOException { InnerException: AddressInUseException } or SocketException { ErrorCode: 10048 }: WrapText(AddressInUseExceptionHelp(), isContentManager); @@ -72,6 +82,11 @@ public static void PrintExceptionHelp(Exception ex, bool isContentManager, strin { Console.WriteLine("Press I to get more info on this error"); } + + if (configPath != null) + { + Console.WriteLine("Press F to show the faulty configuration file"); + } if (crashReportPath != null) { Console.WriteLine("Press C to show the crash report"); @@ -97,7 +112,11 @@ public static void PrintExceptionHelp(Exception ex, bool isContentManager, strin } else if (crashReportPath != null && key.Key == ConsoleKey.C) { - Process.Start("explorer.exe", $"/select, \"{crashReportPath}\""); + ProcessHelper.ShowInExplorer(crashReportPath); + } + else if (configPath != null && key.Key == ConsoleKey.F) + { + ProcessHelper.ShowInExplorer(configPath); } } @@ -127,19 +146,18 @@ private static void WrapText(string text, bool isContentManager) Console.ForegroundColor = old; } - private static string YamlExceptionHelp(YamlException ex) + private static string YamlExceptionHelp(YamlException ex, string? path = null) { return $""" -YAML error. Check your extra_cfg.yml around line {ex.Start.Line}. -When copying plugin configuration, make sure to copy EVERYTHING, including the "---". +YAML error in {path ?? "unknown file"} around line {ex.Start.Line}. {ex.Message} """; } - private static string IniExceptionHelp(ParsingException ex) + private static string IniExceptionHelp(ParsingException ex, string? path = null) { return $""" -INI error. Check your server_cfg.ini or entry_list.ini around line {ex.LineNumber}. +INI error in {path ?? "unknown file"} around line {ex.LineNumber}. {ex.Message} """; } diff --git a/AssettoServer/Server/Configuration/ACServerConfiguration.cs b/AssettoServer/Server/Configuration/ACServerConfiguration.cs index 5d31eb1f..1440cadb 100644 --- a/AssettoServer/Server/Configuration/ACServerConfiguration.cs +++ b/AssettoServer/Server/Configuration/ACServerConfiguration.cs @@ -70,7 +70,8 @@ public ACServerConfiguration(string? preset, ConfigurationLocations locations, b $"AssettoServer {ThisAssembly.AssemblyInformationalVersion}"); var parsedTrackOptions = CSPTrackOptions = CSPTrackOptions.Parse(Server.Track); - if (Extra.MinimumCSPVersion.HasValue) + if (Extra.MinimumCSPVersion.HasValue + && (!CSPTrackOptions.MinimumCSPVersion.HasValue || Extra.MinimumCSPVersion.Value > CSPTrackOptions.MinimumCSPVersion.Value)) { CSPTrackOptions = new CSPTrackOptions { @@ -95,27 +96,45 @@ public ACServerConfiguration(string? preset, ConfigurationLocations locations, b private ServerConfiguration LoadServerConfiguration(string path) { Log.Debug("Loading server_cfg.ini from {Path}", path); - if (!File.Exists(path)) + try + { + if (!File.Exists(path)) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + using var serverCfg = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("AssettoServer.Assets.server_cfg.ini")!; + using var outFile = File.Create(path); + serverCfg.CopyTo(outFile); + } + + return ServerConfiguration.FromFile(path); + } + catch (Exception ex) { - Directory.CreateDirectory(Path.GetDirectoryName(path)!); - using var serverCfg = Assembly.GetExecutingAssembly().GetManifestResourceStream("AssettoServer.Assets.server_cfg.ini")!; - using var outFile = File.Create(path); - serverCfg.CopyTo(outFile); + throw new ConfigurationParsingException(path, ex); } - return ServerConfiguration.FromFile(path); } private EntryList LoadEntryList(string path) { Log.Debug("Loading entry_list.ini from {Path}", path); - if (!File.Exists(path)) + try { - Directory.CreateDirectory(Path.GetDirectoryName(path)!); - using var entryList = Assembly.GetExecutingAssembly().GetManifestResourceStream("AssettoServer.Assets.entry_list.ini")!; - using var outFile = File.Create(path); - entryList.CopyTo(outFile); + if (!File.Exists(path)) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + using var entryList = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("AssettoServer.Assets.entry_list.ini")!; + using var outFile = File.Create(path); + entryList.CopyTo(outFile); + } + + return EntryList.FromFile(path); + } + catch (Exception ex) + { + throw new ConfigurationParsingException(path, ex); } - return EntryList.FromFile(path); } private string LoadWelcomeMessage() @@ -213,26 +232,34 @@ internal void LoadPluginConfiguration(ACPluginLoader loader, ContainerBuilder bu { if (!plugin.HasConfiguration) continue; - var schemaPath = ConfigurationSchemaGenerator.WritePluginConfigurationSchema(plugin); - ReferenceConfigurationHelper.WriteReferenceConfiguration(plugin.ReferenceConfigurationFileName, schemaPath, plugin.ReferenceConfiguration, plugin.Name); - var configPath = Path.Join(BaseFolder, plugin.ConfigurationFileName); - if (File.Exists(configPath)) + try { - var deserializer = new DeserializerBuilder().Build(); - using var file = File.OpenText(configPath); - var configObj = deserializer.Deserialize(file, plugin.ConfigurationType)!; + var schemaPath = ConfigurationSchemaGenerator.WritePluginConfigurationSchema(plugin); + ReferenceConfigurationHelper.WriteReferenceConfiguration(plugin.ReferenceConfigurationFileName, + schemaPath, plugin.ReferenceConfiguration, plugin.Name); + + if (File.Exists(configPath)) + { + var deserializer = new DeserializerBuilder().Build(); + using var file = File.OpenText(configPath); + var configObj = deserializer.Deserialize(file, plugin.ConfigurationType)!; - ValidatePluginConfiguration(plugin, configObj); - builder.RegisterInstance(configObj).AsSelf(); + ValidatePluginConfiguration(plugin, configObj); + builder.RegisterInstance(configObj).AsSelf(); + } + else + { + var serializer = new SerializerBuilder().Build(); + using var file = File.CreateText(configPath); + ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath); + var configObj = Activator.CreateInstance(plugin.ConfigurationType)!; + serializer.Serialize(file, configObj, plugin.ConfigurationType); + } } - else + catch (Exception ex) { - var serializer = new SerializerBuilder().Build(); - using var file = File.CreateText(configPath); - ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath); - var configObj = Activator.CreateInstance(plugin.ConfigurationType)!; - serializer.Serialize(file, configObj, plugin.ConfigurationType); + throw new ConfigurationParsingException(configPath, ex); } } @@ -263,17 +290,24 @@ private static void ValidatePluginConfiguration(LoadedPlugin plugin, object conf private void LoadExtraConfig(string path, string schemaPath) { Log.Debug("Loading extra_cfg.yml from {Path}", path); - - if (!File.Exists(path)) + + try { - using var file = File.CreateText(path); - ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath); - new ACExtraConfiguration().ToStream(file); + if (!File.Exists(path)) + { + using var file = File.CreateText(path); + ConfigurationSchemaGenerator.WriteModeLine(file, BaseFolder, schemaPath); + new ACExtraConfiguration().ToStream(file); + } + + Extra = ACExtraConfiguration.FromFile(path); + } + catch (Exception ex) + { + throw new ConfigurationParsingException(path, ex); } - - Extra = ACExtraConfiguration.FromFile(path); - if (Regex.IsMatch(Server.Name, @"x:\w+$")) + if (Regex.IsMatch(Server.Name, @"x:\w+$")) // TODO remove { const string errorMsg = "Server details are configured via ID in server name. This interferes with native AssettoServer server details. More info: https://assettoserver.org/docs/common-configuration-errors#wrong-server-details"; diff --git a/AssettoServer/Server/Configuration/ConfigurationParsingException.cs b/AssettoServer/Server/Configuration/ConfigurationParsingException.cs new file mode 100644 index 00000000..0de34174 --- /dev/null +++ b/AssettoServer/Server/Configuration/ConfigurationParsingException.cs @@ -0,0 +1,18 @@ +using System; + +namespace AssettoServer.Server.Configuration; + +public class ConfigurationParsingException : Exception +{ + public string? Path { get; } + + public ConfigurationParsingException() + { + } + + public ConfigurationParsingException(string? path, Exception? inner = null) + : base($"Error parsing configuration file {path}", inner) + { + Path = path; + } +} diff --git a/AssettoServer/Utils/ProcessHelper.cs b/AssettoServer/Utils/ProcessHelper.cs index 66803f39..5584d6db 100644 --- a/AssettoServer/Utils/ProcessHelper.cs +++ b/AssettoServer/Utils/ProcessHelper.cs @@ -9,4 +9,9 @@ public static void OpenURL(string url) url = url.Replace("&", "^&"); Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); } + + public static void ShowInExplorer(string path) + { + Process.Start("explorer.exe", $"/select, \"{path}\""); + } }