Partial roll-up to reduce code divergence

Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
Loporrit
2025-02-15 23:07:46 +00:00
parent 324288652d
commit 7a8de7add6
41 changed files with 963 additions and 464 deletions

View File

@@ -5,7 +5,7 @@ using MareSynchronos.Services.Mediator;
using MareSynchronos.Utils;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Collections.Immutable;
namespace MareSynchronos.FileCache;
@@ -20,13 +20,12 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
private long _currentFileProgress = 0;
private CancellationTokenSource _scanCancellationTokenSource = new();
private readonly CancellationTokenSource _periodicCalculationTokenSource = new();
private readonly string[] _allowedExtensions = [".mdl", ".tex", ".mtrl", ".tmb", ".pap", ".avfx", ".atex", ".sklb", ".eid", ".phyb", ".pbd", ".scd", ".skp", ".shpk"];
public static readonly IImmutableList<string> AllowedFileExtensions = [".mdl", ".tex", ".mtrl", ".tmb", ".pap", ".avfx", ".atex", ".sklb", ".eid", ".phyb", ".pbd", ".scd", ".skp", ".shpk"];
public CacheMonitor(ILogger<CacheMonitor> logger, IpcManager ipcManager, MareConfigService configService,
FileCacheManager fileDbManager, MareMediator mediator, PerformanceCollectorService performanceCollector, DalamudUtilService dalamudUtil,
FileCompactor fileCompactor) : base(logger, mediator)
{
Logger.LogInformation("Creating CacheMonitor from {trace}", Environment.StackTrace);
_ipcManager = ipcManager;
_configService = configService;
_fileDbManager = fileDbManager;
@@ -153,7 +152,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
{
Logger.LogTrace("Mare FSW: FileChanged: {change} => {path}", e.ChangeType, e.FullPath);
if (!_allowedExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
lock (_watcherChanges)
{
@@ -197,7 +196,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
private void Fs_Changed(object sender, FileSystemEventArgs e)
{
if (Directory.Exists(e.FullPath)) return;
if (!_allowedExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
if (e.ChangeType is not (WatcherChangeTypes.Changed or WatcherChangeTypes.Deleted or WatcherChangeTypes.Created))
return;
@@ -221,7 +220,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
{
foreach (var file in directoryFiles)
{
if (!_allowedExtensions.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) continue;
if (!AllowedFileExtensions.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) continue;
var oldPath = file.Replace(e.FullPath, e.OldFullPath, StringComparison.OrdinalIgnoreCase);
_watcherChanges.Remove(oldPath);
@@ -233,7 +232,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
}
else
{
if (!_allowedExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
lock (_watcherChanges)
{
@@ -499,7 +498,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
[
.. Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories)
.AsParallel()
.Where(f => _allowedExtensions.Any(e => f.EndsWith(e, StringComparison.OrdinalIgnoreCase))
.Where(f => AllowedFileExtensions.Any(e => f.EndsWith(e, StringComparison.OrdinalIgnoreCase))
&& !f.Contains(@"\bg\", StringComparison.OrdinalIgnoreCase)
&& !f.Contains(@"\bgcommon\", StringComparison.OrdinalIgnoreCase)
&& !f.Contains(@"\ui\", StringComparison.OrdinalIgnoreCase)),

View File

@@ -139,18 +139,7 @@ public sealed class FileCacheManager : IHostedService
return Path.Combine(_configService.Current.CacheFolder, hash + "." + extension);
}
public async Task<long> GetCompressedFileLength(string fileHash, CancellationToken uploadToken)
{
var fileCache = GetFileCacheByHash(fileHash)!.ResolvedFilepath;
using var fs = File.OpenRead(fileCache);
var cs = new CountedStream(Stream.Null);
using var encstream = LZ4Stream.Encode(cs, new LZ4EncoderSettings(){CompressionLevel=K4os.Compression.LZ4.LZ4Level.L09_HC});
await fs.CopyToAsync(encstream, uploadToken).ConfigureAwait(false);
encstream.Close();
return uploadToken.IsCancellationRequested ? 0 : cs.BytesWritten;
}
public async Task<byte[]> GetCompressedFileData(string fileHash, CancellationToken uploadToken)
public async Task<(string, byte[])> GetCompressedFileData(string fileHash, CancellationToken uploadToken)
{
var fileCache = GetFileCacheByHash(fileHash)!.ResolvedFilepath;
using var fs = File.OpenRead(fileCache);
@@ -158,7 +147,7 @@ public sealed class FileCacheManager : IHostedService
using var encstream = LZ4Stream.Encode(ms, new LZ4EncoderSettings(){CompressionLevel=K4os.Compression.LZ4.LZ4Level.L09_HC});
await fs.CopyToAsync(encstream, uploadToken).ConfigureAwait(false);
encstream.Close();
return ms.ToArray();
return (fileHash, ms.ToArray());
}
public FileCacheEntity? GetFileCacheByHash(string hash)
@@ -428,6 +417,13 @@ public sealed class FileCacheManager : IHostedService
if (File.Exists(_csvPath))
{
if (!_ipcManager.Penumbra.APIAvailable || string.IsNullOrEmpty(_ipcManager.Penumbra.ModDirectory))
{
_mareMediator.Publish(new NotificationMessage("Penumbra not connected",
"Could not load local file cache data. Penumbra is not connected or not properly set up. Please enable and/or configure Penumbra properly to use Loporrit. After, reload Loporrit in the Plugin installer.",
MareConfiguration.Models.NotificationType.Error));
}
_logger.LogInformation("{csvPath} found, parsing", _csvPath);
bool success = false;

View File

@@ -11,13 +11,13 @@ namespace MareSynchronos.FileCache;
public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
{
private readonly object _cacheAdditionLock = new();
private readonly HashSet<string> _cachedHandledPaths = new(StringComparer.Ordinal);
private readonly TransientConfigService _configurationService;
private readonly DalamudUtilService _dalamudUtil;
private readonly string[] _fileTypesToHandle = ["tmb", "pap", "avfx", "atex", "sklb", "eid", "phyb", "scd", "skp", "shpk"];
private readonly HashSet<GameObjectHandler> _playerRelatedPointers = [];
private HashSet<IntPtr> _cachedFrameAddresses = [];
private readonly object _cacheAdditionLock = new();
private ConcurrentDictionary<IntPtr, ObjectKind> _cachedFrameAddresses = [];
public TransientResourceManager(ILogger<TransientResourceManager> logger, TransientConfigService configurationService,
DalamudUtilService dalamudUtil, MareMediator mediator) : base(logger, mediator)
@@ -162,7 +162,13 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
{
if (TransientResources.TryGetValue(ptr, out var set))
{
set.RemoveWhere(p => list.Contains(p, StringComparer.OrdinalIgnoreCase));
foreach (var file in set.Where(p => list.Contains(p, StringComparer.OrdinalIgnoreCase)))
{
Logger.LogTrace("Removing From Transient: {file}", file);
}
int removed = set.RemoveWhere(p => list.Contains(p, StringComparer.OrdinalIgnoreCase));
Logger.LogInformation("Removed {removed} previously existing transient paths", removed);
}
}
@@ -189,7 +195,7 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
private void DalamudUtil_FrameworkUpdate()
{
_cachedFrameAddresses = _playerRelatedPointers.Select(c => c.CurrentAddress()).ToHashSet();
_cachedFrameAddresses = _cachedFrameAddresses = new ConcurrentDictionary<nint, ObjectKind>(_playerRelatedPointers.Where(k => k.Address != nint.Zero).ToDictionary(c => c.CurrentAddress(), c => c.ObjectKind));
lock (_cacheAdditionLock)
{
_cachedHandledPaths.Clear();
@@ -250,7 +256,7 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
}
// ignore files not belonging to anything player related
if (!_cachedFrameAddresses.Contains(gameObject))
if (!_cachedFrameAddresses.TryGetValue(gameObject, out var objectKind))
{
lock (_cacheAdditionLock)
{
@@ -272,9 +278,18 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
}
else
{
var thing = _playerRelatedPointers.FirstOrDefault(f => f.Address == gameObject);
value.Add(replacedGamePath);
Logger.LogDebug("Adding {replacedGamePath} for {gameObject} ({filePath})", replacedGamePath, gameObject.ToString("X"), filePath);
Mediator.Publish(new TransientResourceChangedMessage(gameObject));
Logger.LogDebug("Adding {replacedGamePath} for {gameObject} ({filePath})", replacedGamePath, thing?.ToString() ?? gameObject.ToString("X"), filePath);
_ = Task.Run(async () =>
{
_sendTransientCts?.Cancel();
_sendTransientCts?.Dispose();
_sendTransientCts = new();
var token = _sendTransientCts.Token;
await Task.Delay(TimeSpan.FromSeconds(2), token).ConfigureAwait(false);
Mediator.Publish(new TransientResourceChangedMessage(gameObject));
});
}
}
@@ -287,4 +302,6 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase
_configurationService.Save();
}
}
private CancellationTokenSource _sendTransientCts = new();
}