From 9836ccf81b903338f6ebad36da11a30b4dcef1ae Mon Sep 17 00:00:00 2001 From: Huy Nguyen Date: Sun, 14 Dec 2025 11:36:37 +1030 Subject: [PATCH] Skip Snapshot Addition if hash and path exists --- .gitignore | 1 + TinfoilVibeServer/Services/ArchiveHandler.cs | 25 ++++++++++++------- TinfoilVibeServer/Services/SnapshotService.cs | 14 ++++++++--- .../Utilities/RewindableStream.cs | 12 +++++++-- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index bc60e7b..0fa94aa 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ data/* TinfoilVibeServer/config/prod.keys TinfoilVibeServer/data/* !TinfoilVibeServer/data/.gitkeep +.vs/ diff --git a/TinfoilVibeServer/Services/ArchiveHandler.cs b/TinfoilVibeServer/Services/ArchiveHandler.cs index c3fbe96..ad7de82 100644 --- a/TinfoilVibeServer/Services/ArchiveHandler.cs +++ b/TinfoilVibeServer/Services/ArchiveHandler.cs @@ -7,6 +7,7 @@ using SharpCompress.Archives; using SharpCompress.Archives.Rar; using SharpCompress.Archives.SevenZip; using SharpCompress.Common; +using SharpCompress.Readers; using TinfoilVibeServer.Models; using TinfoilVibeServer.Utilities; using ZipArchive = SharpCompress.Archives.Zip.ZipArchive; @@ -151,6 +152,10 @@ public sealed class ArchiveHandler : IArchiveHandler { _logger.LogError("Failed to extract title info from archive {Archive}: {Exception}", path, e.Message); } + else if (e.Message.StartsWith("Unable to decrypt NCA section")) + { + _logger.LogError("Unable to decrypt NCA section, try updating prod.keys"); + } else { throw; @@ -171,17 +176,19 @@ public sealed class ArchiveHandler : IArchiveHandler _logger.LogInformation( "Failed to open archive with SharpCompress, falling back to SharpSevenZip {Exception}", exception.Message); - using var archive = SevenZipArchive.Open(path); + using var archive = SevenZipArchive.Open(path, new ReaderOptions { LeaveStreamOpen = false }); foreach (var entry in archive.Entries) { - if (entry is { IsDirectory: false, Key: not null } && IsRomArchive(entry.Key)) - { - var temp = Path.GetTempFileName(); - entry.WriteToFile(temp); - var title = _nspExtractor.ExtractFromFile(temp); // instance call - File.Delete(temp); - if (title != null) titles.Add((entry.Key, entry.Size, title)); - } + if (entry is not { IsDirectory: false, Key: not null } || !IsRomArchive(entry.Key)) continue; + + var temp = Path.GetTempFileName(); + entry.WriteToFile(temp); + var title = _nspExtractor.ExtractFromFile(temp); // instance call + File.Delete(temp); + if (title == null) continue; + + _logger.LogInformation("Extracted title {Key} using SharpSevenZip", entry.Key); + titles.Add((entry.Key, entry.Size, title)); } } diff --git a/TinfoilVibeServer/Services/SnapshotService.cs b/TinfoilVibeServer/Services/SnapshotService.cs index 7c246a8..aa0912b 100644 --- a/TinfoilVibeServer/Services/SnapshotService.cs +++ b/TinfoilVibeServer/Services/SnapshotService.cs @@ -317,9 +317,12 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ return; } - var lastModified = File.GetLastWriteTimeUtc(entry.Path.Contains(ArchivePathSeparator) ? entry.Path.Split(ArchivePathSeparator)[0] : entry.Path); - var cacheUpdated = _cache.ContainsKey(entry.Path); + var hashMatch = _hashCache.ContainsKey(entry.Hash) && _hashCache[entry.Hash] == entry.Path; + if (cacheUpdated && hashMatch) return; + + var lastModified = File.GetLastWriteTimeUtc(entry.Path.Contains(ArchivePathSeparator) ? entry.Path.Split(ArchivePathSeparator)[0] : entry.Path); + _cache[entry.Path] = new SnapshotEntry(entry.Path, entry.Hash, entry.Size, lastModified, entry.Titles); _hashCache[entry.Hash] = entry.Path; _sizeLookup[entry.Hash] = entry.Size; @@ -858,12 +861,13 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ try { var ext = Path.GetExtension(filePath).ToLowerInvariant(); - + var multiPartBasePathWithExtension = $"{MultiPartRarHelper.GetBaseNameForRarVolume(filePath)}{ext}"; if (string.CompareOrdinal(multiPartBasePathWithExtension, filePath) != 0) { filePath = multiPartBasePathWithExtension; } + if (FileLockHelper.IsFileLocked(filePath)) { throw new IOException("File is locked"); @@ -907,6 +911,10 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ _logger.LogWarning("Load {Path} failed after {retries} attempts", filePath, attempt + 1); return null; } + catch (Exception exception) + { + _logger.LogError(exception, "Unknown exception: {exception}", exception.Message); + } } return string.Empty; diff --git a/TinfoilVibeServer/Utilities/RewindableStream.cs b/TinfoilVibeServer/Utilities/RewindableStream.cs index 52dd87a..0c11f1a 100644 --- a/TinfoilVibeServer/Utilities/RewindableStream.cs +++ b/TinfoilVibeServer/Utilities/RewindableStream.cs @@ -67,7 +67,8 @@ public sealed class RewindableStream : Stream get { EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult(); - return _length.Value; + if (_length != null) return _length.Value; + return -1; } } @@ -139,7 +140,14 @@ public sealed class RewindableStream : Stream { // We need the length first. EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult(); - newPos = _length.Value + offset; + if (_length != null) + { + newPos = _length.Value + offset; + } + else + { + throw new NullReferenceException(nameof(_length)); + } } else {