diff --git a/LightlessSyncServer/LightlessSyncServer/Services/PruneService.cs b/LightlessSyncServer/LightlessSyncServer/Services/PruneService.cs index b50029d..72c68ac 100644 --- a/LightlessSyncServer/LightlessSyncServer/Services/PruneService.cs +++ b/LightlessSyncServer/LightlessSyncServer/Services/PruneService.cs @@ -2,15 +2,19 @@ using LightlessSyncShared.Data; using LightlessSyncShared.Models; using Microsoft.EntityFrameworkCore; +using StackExchange.Redis.Extensions.Core.Abstractions; namespace LightlessSyncServer.Services { - public class PruneService(LightlessDbContext dbContext) : IPruneService + public class PruneService(LightlessDbContext dbContext, IRedisDatabase redis) : IPruneService { private readonly LightlessDbContext _dbContext = dbContext; + private readonly IRedisDatabase _redis = redis; public async Task CountPrunableUsersAsync(string groupGid, int days, CancellationToken ct) { + var onlineUids = await GetOnlineUidsAsync().ConfigureAwait(false); + var allGroupUsers = await _dbContext.GroupPairs .Include(p => p.GroupUser) .Include(p => p.Group) @@ -20,17 +24,14 @@ namespace LightlessSyncServer.Services var inactivitySpan = GetInactivitySpan(days); var now = DateTime.UtcNow; - var usersToPrune = allGroupUsers.Where(p => - !p.IsPinned && - !p.IsModerator && - !string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) && - p.GroupUser.LastLoggedIn < now - inactivitySpan); - - return usersToPrune.Count(); + var usersToPrune = GetPruneUserList(allGroupUsers, onlineUids, inactivitySpan, now); + return usersToPrune.Count; } public async Task> ExecutePruneAsync(string groupGid, int days, CancellationToken ct) { + var onlineUids = await GetOnlineUidsAsync().ConfigureAwait(false); + var allGroupUsers = await _dbContext.GroupPairs .Include(p => p.GroupUser) .Include(p => p.Group) @@ -40,12 +41,7 @@ namespace LightlessSyncServer.Services var inactivitySpan = GetInactivitySpan(days); var now = DateTime.UtcNow; - var usersToPrune = allGroupUsers.Where(p => - !p.IsPinned && - !p.IsModerator && - !string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) && - p.GroupUser.LastLoggedIn < now - inactivitySpan) - .ToList(); + var usersToPrune = GetPruneUserList(allGroupUsers, onlineUids, inactivitySpan, now); _dbContext.GroupPairs.RemoveRange(usersToPrune); await _dbContext.SaveChangesAsync(ct).ConfigureAwait(false); @@ -53,8 +49,52 @@ namespace LightlessSyncServer.Services return usersToPrune; } - private static TimeSpan GetInactivitySpan(int days) => days == 0 - ? TimeSpan.FromMinutes(15) - : TimeSpan.FromDays(days); + private static List GetPruneUserList( + List allGroupUsers, + HashSet onlineUids, + TimeSpan inactivitySpan, + DateTime now) + { + return + [ + .. allGroupUsers.Where(p => + !p.IsPinned && + !p.IsModerator && + !string.Equals(p.Group.OwnerUID, p.GroupUserUID, StringComparison.Ordinal) && + !onlineUids.Contains(p.GroupUserUID) && + p.GroupUser.LastLoggedIn < now - inactivitySpan), + ]; + } + + private async Task> GetOnlineUidsAsync() + { + var keys = await _redis.SearchKeysAsync("UID:*").ConfigureAwait(false); + + var set = new HashSet(StringComparer.Ordinal); + + foreach (var k in keys) + { + if (string.IsNullOrEmpty(k)) continue; + + const string prefix = "UID:"; + if (k.StartsWith(prefix, StringComparison.Ordinal)) + { + var uid = k.Substring(prefix.Length); + if (!string.IsNullOrEmpty(uid)) + set.Add(uid); + } + else + { + var idx = k.IndexOf(':', StringComparison.Ordinal); + if (idx >= 0 && idx < k.Length - 1) + set.Add(k[(idx + 1)..]); + } + } + + return set; + } + + private static TimeSpan GetInactivitySpan(int days) => + days == 0 ? TimeSpan.FromHours(2) : TimeSpan.FromDays(days); } -} +} \ No newline at end of file diff --git a/LightlessSyncServer/LightlessSyncServer/Worker/AutoPruneWorker.cs b/LightlessSyncServer/LightlessSyncServer/Worker/AutoPruneWorker.cs index 290c014..4680254 100644 --- a/LightlessSyncServer/LightlessSyncServer/Worker/AutoPruneWorker.cs +++ b/LightlessSyncServer/LightlessSyncServer/Worker/AutoPruneWorker.cs @@ -24,7 +24,7 @@ namespace LightlessSyncServer.Worker var hubContext = scope.ServiceProvider.GetRequiredService>(); var groups = await db.Groups - .Where(g => g.AutoPruneEnabled && g.AutoPruneDays > 0) + .Where(g => g.AutoPruneEnabled) .ToListAsync(stoppingToken).ConfigureAwait(false); foreach (var group in groups)