Warning cleansing process

This commit is contained in:
cake
2025-11-15 00:46:14 +01:00
parent acc8593996
commit e4a28c70eb
5 changed files with 80 additions and 63 deletions

View File

@@ -85,7 +85,7 @@ public sealed partial class FileCompactor : IDisposable
int workerId = i;
_workers.Add(Task.Factory.StartNew(
() => ProcessQueueWorkerAsync(_compactionCts.Token, workerId),
() => ProcessQueueWorkerAsync(workerId, _compactionCts.Token),
_compactionCts.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).Unwrap());
@@ -120,7 +120,8 @@ public sealed partial class FileCompactor : IDisposable
var folder = _lightlessConfigService.Current.CacheFolder;
if (string.IsNullOrWhiteSpace(folder) || !Directory.Exists(folder))
{
_logger.LogWarning("Filecompacator couldnt find your Cache folder: {folder}", folder);
if (_logger.IsEnabled(LogLevel.Warning))
_logger.LogWarning("Filecompacator couldnt find your Cache folder: {folder}", folder);
Progress = "0/0";
return;
}
@@ -281,12 +282,15 @@ public sealed partial class FileCompactor : IDisposable
return (flowControl: false, value: blocks * 512L);
}
_logger.LogDebug("Btrfs size probe failed for {linux} (exit {code}). stdout='{so}' stderr='{se}'. Falling back to Length.", linuxPath, res.code, outTrim, (res.se ?? "").Trim());
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug("Btrfs size probe failed for {linux} (exit {code}). stdout='{so}' stderr='{se}'. Falling back to Length.", linuxPath, res.code, outTrim, (res.se ?? "").Trim());
return (flowControl: false, value: fileInfo.Length);
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed Btrfs size probe for {file}, using Length", fileInfo.FullName);
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug(ex, "Failed Btrfs size probe for {file}, using Length", fileInfo.FullName);
return (flowControl: true, value: fileInfo.Length);
}
}
@@ -307,7 +311,8 @@ public sealed partial class FileCompactor : IDisposable
}
catch (Exception ex)
{
_logger.LogDebug(ex, "Failed stat size for {file}, fallback to Length", fileInfo.FullName);
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug(ex, "Failed stat size for {file}, fallback to Length", fileInfo.FullName);
}
return (flowControl: true, value: default);
@@ -323,7 +328,8 @@ public sealed partial class FileCompactor : IDisposable
var fi = new FileInfo(filePath);
if (!fi.Exists)
{
_logger.LogTrace("[W{worker}] Skip compaction: missing {file}", workerId, filePath);
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("[W{worker}] Skip compaction: missing {file}", workerId, filePath);
return;
}
@@ -338,7 +344,8 @@ public sealed partial class FileCompactor : IDisposable
if (oldSize < minSizeBytes)
{
_logger.LogTrace("[W{worker}] Skip compaction: {file} ({size} B) < threshold ({th} B)", workerId, filePath, oldSize, minSizeBytes);
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("[W{worker}] Skip compaction: {file} ({size} B) < threshold ({th} B)", workerId, filePath, oldSize, minSizeBytes);
return;
}
@@ -358,7 +365,8 @@ public sealed partial class FileCompactor : IDisposable
}
else
{
_logger.LogTrace("[W{worker}] Already NTFS-compressed with XPRESS8K: {file}", workerId, filePath);
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("[W{worker}] Already NTFS-compressed with XPRESS8K: {file}", workerId, filePath);
}
return;
}
@@ -379,12 +387,14 @@ public sealed partial class FileCompactor : IDisposable
}
else
{
_logger.LogTrace("[W{worker}] Already Btrfs-compressed with clzo: {file}", workerId, filePath);
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("[W{worker}] Already Btrfs-compressed with clzo: {file}", workerId, filePath);
}
return;
}
_logger.LogTrace("[W{worker}] Skip compact: unsupported FS for {file}", workerId, filePath);
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("[W{worker}] Skip compact: unsupported FS for {file}", workerId, filePath);
}
/// <summary>
@@ -1045,10 +1055,10 @@ public sealed partial class FileCompactor : IDisposable
}
/// <summary>
/// Process the queue with, meant for a worker/thread
/// Process the queue, meant for a worker/thread
/// </summary>
/// <param name="token">Cancellation token for the worker whenever it needs to be stopped</param>
private async Task ProcessQueueWorkerAsync(CancellationToken token, int workerId)
private async Task ProcessQueueWorkerAsync(int workerId, CancellationToken token)
{
try
{
@@ -1139,17 +1149,18 @@ public sealed partial class FileCompactor : IDisposable
{
try
{
if (_isWindows)
{
using var _ = new FileStream(winePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
else
{
using var _ = new FileStream(linuxPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
var pathToOpen = _isWindows ? winePath : linuxPath;
if (string.IsNullOrEmpty(pathToOpen) || !File.Exists(pathToOpen))
return false;
using var _ = new FileStream(pathToOpen, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return true;
}
catch { return false; }
catch
{
return false;
}
}
/// <summary>

View File

@@ -227,7 +227,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<ConfigurationMigrator>();
collection.AddSingleton<ConfigurationSaveService>();
collection.AddSingleton<HubFactory>();
collection.AddSingleton(s => new BroadcastScannerService( s.GetRequiredService<ILogger<BroadcastScannerService>>(), clientState, objectTable, framework, s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<NameplateHandler>(), s.GetRequiredService<DalamudUtilService>(), s.GetRequiredService<LightlessConfigService>()));
collection.AddSingleton(s => new BroadcastScannerService(s.GetRequiredService<ILogger<BroadcastScannerService>>(), objectTable, framework, s.GetRequiredService<BroadcastService>(), s.GetRequiredService<LightlessMediator>(), s.GetRequiredService<NameplateHandler>()));
// add scoped services

View File

@@ -1,14 +1,13 @@
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Plugin.Services;
using LightlessSync.API.Dto.User;
using LightlessSync.LightlessConfiguration;
using LightlessSync.Services.Mediator;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
namespace LightlessSync.Services;
public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDisposable
public class BroadcastScannerService : DisposableMediatorSubscriberBase
{
private readonly ILogger<BroadcastScannerService> _logger;
private readonly IObjectTable _objectTable;
@@ -17,20 +16,19 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
private readonly BroadcastService _broadcastService;
private readonly NameplateHandler _nameplateHandler;
private readonly ConcurrentDictionary<string, BroadcastEntry> _broadcastCache = new();
private readonly ConcurrentDictionary<string, BroadcastEntry> _broadcastCache = new(StringComparer.Ordinal);
private readonly Queue<string> _lookupQueue = new();
private readonly HashSet<string> _lookupQueuedCids = new();
private readonly HashSet<string> _syncshellCids = new();
private readonly HashSet<string> _lookupQueuedCids = [];
private readonly HashSet<string> _syncshellCids = [];
private static readonly TimeSpan MaxAllowedTtl = TimeSpan.FromMinutes(4);
private static readonly TimeSpan RetryDelay = TimeSpan.FromMinutes(1);
private readonly CancellationTokenSource _cleanupCts = new();
private Task? _cleanupTask;
private readonly Task? _cleanupTask;
private readonly int _checkEveryFrames = 20;
private int _frameCounter = 0;
private int _lookupsThisFrame = 0;
private const int MaxLookupsPerFrame = 30;
private const int MaxQueueSize = 100;
@@ -40,14 +38,11 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID);
public BroadcastScannerService(ILogger<BroadcastScannerService> logger,
IClientState clientState,
IObjectTable objectTable,
IFramework framework,
BroadcastService broadcastService,
LightlessMediator mediator,
NameplateHandler nameplateHandler,
DalamudUtilService dalamudUtil,
LightlessConfigService configService) : base(logger, mediator)
NameplateHandler nameplateHandler) : base(logger, mediator)
{
_logger = logger;
_objectTable = objectTable;
@@ -69,7 +64,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
public void Update()
{
_frameCounter++;
_lookupsThisFrame = 0;
var lookupsThisFrame = 0;
if (!_broadcastService.IsBroadcasting)
return;
@@ -91,12 +86,12 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
if (_frameCounter % _checkEveryFrames == 0 && _lookupQueue.Count > 0)
{
var cidsToLookup = new List<string>();
while (_lookupQueue.Count > 0 && _lookupsThisFrame < MaxLookupsPerFrame)
while (_lookupQueue.Count > 0 && lookupsThisFrame < MaxLookupsPerFrame)
{
var cid = _lookupQueue.Dequeue();
_lookupQueuedCids.Remove(cid);
cidsToLookup.Add(cid);
_lookupsThisFrame++;
lookupsThisFrame++;
}
if (cidsToLookup.Count > 0 && !_batchRunning)
@@ -156,7 +151,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
var newSet = _broadcastCache
.Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID))
.Select(e => e.Key)
.ToHashSet();
.ToHashSet(StringComparer.Ordinal);
if (!_syncshellCids.SetEquals(newSet))
{
@@ -172,7 +167,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
{
var now = DateTime.UtcNow;
return _broadcastCache
return [.. _broadcastCache
.Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID))
.Select(e => new BroadcastStatusInfoDto
{
@@ -180,8 +175,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
IsBroadcasting = true,
TTL = e.Value.ExpiryTime - now,
GID = e.Value.GID
})
.ToList();
})];
}
private async Task ExpiredBroadcastCleanupLoop()
@@ -192,7 +186,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
{
while (!token.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(10), token);
await Task.Delay(TimeSpan.FromSeconds(10), token).ConfigureAwait(false);
var now = DateTime.UtcNow;
foreach (var (cid, entry) in _broadcastCache.ToArray())
@@ -202,7 +196,10 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
}
}
}
catch (OperationCanceledException) { }
catch (OperationCanceledException)
{
// No action needed when cancelled
}
catch (Exception ex)
{
_logger.LogError(ex, "Broadcast cleanup loop crashed");
@@ -235,8 +232,14 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos
{
base.Dispose(disposing);
_framework.Update -= OnFrameworkUpdate;
if (_cleanupTask != null)
{
_cleanupTask?.Wait(100, _cleanupCts.Token);
}
_cleanupCts.Cancel();
_cleanupTask?.Wait(100);
_cleanupCts.Dispose();
_nameplateHandler.Uninit();
}
}

View File

@@ -41,8 +41,8 @@ public class EditProfileUi : WindowMediatorSubscriberBase
private Vector4 textColor;
private Vector4 glowColor;
private record VanityState(bool TextEnabled, bool GlowEnabled, Vector4 TextColor, Vector4 GlowColor);
private VanityState _savedVanity;
private sealed record VanityState(bool TextEnabled, bool GlowEnabled, Vector4 TextColor, Vector4 GlowColor);
private VanityState? _savedVanity;
public EditProfileUi(ILogger<EditProfileUi> logger, LightlessMediator mediator,
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
@@ -189,25 +189,28 @@ public class EditProfileUi : WindowMediatorSubscriberBase
if (!success) return;
_ = Task.Run(async () =>
{
var fileContent = File.ReadAllBytes(file);
using MemoryStream ms = new(fileContent);
var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false);
if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase))
var fileContent = await File.ReadAllBytesAsync(file).ConfigureAwait(false);
MemoryStream ms = new(fileContent);
await using (ms.ConfigureAwait(false))
{
_showFileDialogError = true;
return;
}
using var image = Image.Load<Rgba32>(fileContent);
var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false);
if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase))
{
_showFileDialogError = true;
return;
}
using var image = Image.Load<Rgba32>(fileContent);
if (image.Width > 256 || image.Height > 256 || (fileContent.Length > 250 * 1024))
{
_showFileDialogError = true;
return;
}
if (image.Width > 256 || image.Height > 256 || (fileContent.Length > 250 * 1024))
{
_showFileDialogError = true;
return;
}
_showFileDialogError = false;
await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, Convert.ToBase64String(fileContent), BannerPictureBase64: null, Description: null, Tags: null))
.ConfigureAwait(false);
_showFileDialogError = false;
await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, Convert.ToBase64String(fileContent), BannerPictureBase64: null, Description: null, Tags: null))
.ConfigureAwait(false);
}
});
});
}

View File

@@ -114,9 +114,9 @@ public static class VariousExtensions
.OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList();
var newTail = newFileReplacements.Where(g => g.GamePaths.Any(p => p.Contains("/tail/", StringComparison.OrdinalIgnoreCase)))
.OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList();
var existingTransients = existingFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl") && !g.EndsWith("tex") && !g.EndsWith("mtrl")))
var existingTransients = existingFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl", StringComparison.Ordinal) && !g.EndsWith("tex", StringComparison.Ordinal) && !g.EndsWith("mtrl", StringComparison.Ordinal)))
.OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList();
var newTransients = newFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl") && !g.EndsWith("tex") && !g.EndsWith("mtrl")))
var newTransients = newFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl", StringComparison.Ordinal) && !g.EndsWith("tex", StringComparison.Ordinal) && !g.EndsWith("mtrl", StringComparison.Ordinal)))
.OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList();
logger.LogTrace("[BASE-{appbase}] ExistingFace: {of}, NewFace: {fc}; ExistingHair: {eh}, NewHair: {nh}; ExistingTail: {et}, NewTail: {nt}; ExistingTransient: {etr}, NewTransient: {ntr}", applicationBase,