From 6594a0ecb2ef6258d3c4cb8ad30eb2f0de4c51f3 Mon Sep 17 00:00:00 2001 From: Paul Hebble Date: Fri, 27 Sep 2024 11:55:27 -0500 Subject: [PATCH] Skip corrupted .acf files in Steam library --- Core/Extensions/EnumerableExtensions.cs | 16 ++++++++++++++++ Core/SteamLibrary.cs | 11 +++++++++-- Core/Utilities.cs | 14 +++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Core/Extensions/EnumerableExtensions.cs b/Core/Extensions/EnumerableExtensions.cs index 76dd1da99..64a38025b 100644 --- a/Core/Extensions/EnumerableExtensions.cs +++ b/Core/Extensions/EnumerableExtensions.cs @@ -262,6 +262,22 @@ public static IEnumerable WithMatches(this IEnumerable source, Re => source.Select(val => pattern.TryMatch(val, out Match? match) ? match : null) .OfType(); + /// + /// Apply a function to a sequence and handle any exceptions that are thrown + /// + /// Type of source sequence + /// Type of destination sequence + /// Source sequence + /// Function to apply to each item + /// Function to call if there's an exception + /// Sequence of return values of given function + public static IEnumerable SelectWithCatch(this IEnumerable source, + Func func, + Func onThrow) + where TDest : class + => source.Select(item => Utilities.DefaultIfThrows(() => func(item), + exc => onThrow(item, exc))); + } /// diff --git a/Core/SteamLibrary.cs b/Core/SteamLibrary.cs index 284352f82..71531046f 100644 --- a/Core/SteamLibrary.cs +++ b/Core/SteamLibrary.cs @@ -5,6 +5,7 @@ using log4net; using ValveKeyValue; +using CKAN.Extensions; namespace CKAN { @@ -57,8 +58,14 @@ public IEnumerable GameAppURLs(DirectoryInfo gameDir) private static IEnumerable LibraryPathGames(KVSerializer acfParser, string appPath) => Directory.EnumerateFiles(appPath, "*.acf") - .Select(acfFile => acfParser.Deserialize(File.OpenRead(acfFile)) - .NormalizeDir(Path.Combine(appPath, "common"))); + .SelectWithCatch(acfFile => acfParser.Deserialize(File.OpenRead(acfFile)) + .NormalizeDir(Path.Combine(appPath, "common")), + (acfFile, exc) => + { + log.Warn($"Failed to parse {acfFile}:", exc); + return default; + }) + .OfType(); private static IEnumerable ShortcutsFileGames(KVSerializer vdfParser, string path) diff --git a/Core/Utilities.cs b/Core/Utilities.cs index 2d48cf846..c0db6e563 100644 --- a/Core/Utilities.cs +++ b/Core/Utilities.cs @@ -28,15 +28,23 @@ public static class Utilities "nl-NL", }; - public static T? DefaultIfThrows(Func func) where T : class + /// + /// Call a function and take a default action if it throws an exception + /// + /// Return type of the function + /// Function to call + /// Function to call if an exception is thrown + /// Return value of the function + public static T? DefaultIfThrows(Func func, + Func? onThrow = null) where T : class { try { return func(); } - catch + catch (Exception exc) { - return default; + return onThrow?.Invoke(exc) ?? default; } }