2 Commits

Author SHA1 Message Date
ecenshu 9836ccf81b Skip Snapshot Addition if hash and path exists
ci / build_linux (push) Successful in 8m50s
2025-12-14 11:36:37 +10:30
ecenshu eafb28846f feature/bugfix_selflock (#10)
Build & Push Docker image / build-and-push (push) Successful in 5m15s
ci / build_linux (push) Successful in 4m4s
Check lock against base file in multipart scenario
Explicitly close references when using IArchive

Reviewed-on: #10
Co-authored-by: Huy Nguyen <ecenshu@gmail.com>
Co-committed-by: Huy Nguyen <ecenshu@gmail.com>
2025-12-13 23:44:46 +00:00
4 changed files with 38 additions and 14 deletions
+1
View File
@@ -10,3 +10,4 @@ data/*
TinfoilVibeServer/config/prod.keys TinfoilVibeServer/config/prod.keys
TinfoilVibeServer/data/* TinfoilVibeServer/data/*
!TinfoilVibeServer/data/.gitkeep !TinfoilVibeServer/data/.gitkeep
.vs/
+12 -5
View File
@@ -7,6 +7,7 @@ using SharpCompress.Archives;
using SharpCompress.Archives.Rar; using SharpCompress.Archives.Rar;
using SharpCompress.Archives.SevenZip; using SharpCompress.Archives.SevenZip;
using SharpCompress.Common; using SharpCompress.Common;
using SharpCompress.Readers;
using TinfoilVibeServer.Models; using TinfoilVibeServer.Models;
using TinfoilVibeServer.Utilities; using TinfoilVibeServer.Utilities;
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive; 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); _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 else
{ {
throw; throw;
@@ -171,17 +176,19 @@ public sealed class ArchiveHandler : IArchiveHandler
_logger.LogInformation( _logger.LogInformation(
"Failed to open archive with SharpCompress, falling back to SharpSevenZip {Exception}", "Failed to open archive with SharpCompress, falling back to SharpSevenZip {Exception}",
exception.Message); exception.Message);
using var archive = SevenZipArchive.Open(path); using var archive = SevenZipArchive.Open(path, new ReaderOptions { LeaveStreamOpen = false });
foreach (var entry in archive.Entries) foreach (var entry in archive.Entries)
{ {
if (entry is { IsDirectory: false, Key: not null } && IsRomArchive(entry.Key)) if (entry is not { IsDirectory: false, Key: not null } || !IsRomArchive(entry.Key)) continue;
{
var temp = Path.GetTempFileName(); var temp = Path.GetTempFileName();
entry.WriteToFile(temp); entry.WriteToFile(temp);
var title = _nspExtractor.ExtractFromFile(temp); // instance call var title = _nspExtractor.ExtractFromFile(temp); // instance call
File.Delete(temp); File.Delete(temp);
if (title != null) titles.Add((entry.Key, entry.Size, title)); if (title == null) continue;
}
_logger.LogInformation("Extracted title {Key} using SharpSevenZip", entry.Key);
titles.Add((entry.Key, entry.Size, title));
} }
} }
@@ -317,9 +317,12 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
return; return;
} }
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); var lastModified = File.GetLastWriteTimeUtc(entry.Path.Contains(ArchivePathSeparator) ? entry.Path.Split(ArchivePathSeparator)[0] : entry.Path);
var cacheUpdated = _cache.ContainsKey(entry.Path);
_cache[entry.Path] = new SnapshotEntry(entry.Path, entry.Hash, entry.Size, lastModified, entry.Titles); _cache[entry.Path] = new SnapshotEntry(entry.Path, entry.Hash, entry.Size, lastModified, entry.Titles);
_hashCache[entry.Hash] = entry.Path; _hashCache[entry.Hash] = entry.Path;
_sizeLookup[entry.Hash] = entry.Size; _sizeLookup[entry.Hash] = entry.Size;
@@ -864,6 +867,7 @@ public sealed class SnapshotService : IDisposable, ISnapshotService, IHostedServ
{ {
filePath = multiPartBasePathWithExtension; filePath = multiPartBasePathWithExtension;
} }
if (FileLockHelper.IsFileLocked(filePath)) if (FileLockHelper.IsFileLocked(filePath))
{ {
throw new IOException("File is locked"); 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); _logger.LogWarning("Load {Path} failed after {retries} attempts", filePath, attempt + 1);
return null; return null;
} }
catch (Exception exception)
{
_logger.LogError(exception, "Unknown exception: {exception}", exception.Message);
}
} }
return string.Empty; return string.Empty;
@@ -67,7 +67,8 @@ public sealed class RewindableStream : Stream
get get
{ {
EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult(); EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult();
return _length.Value; if (_length != null) return _length.Value;
return -1;
} }
} }
@@ -139,9 +140,16 @@ public sealed class RewindableStream : Stream
{ {
// We need the length first. // We need the length first.
EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult(); EnsureLengthAsync(CancellationToken.None).GetAwaiter().GetResult();
if (_length != null)
{
newPos = _length.Value + offset; newPos = _length.Value + offset;
} }
else else
{
throw new NullReferenceException(nameof(_length));
}
}
else
{ {
throw new ArgumentOutOfRangeException(nameof(origin)); throw new ArgumentOutOfRangeException(nameof(origin));
} }