fix-prune (#50)

Co-authored-by: Tsubasahane <wozaiha@gmail.com>
Co-authored-by: cake <admin@cakeandbanana.nl>
Reviewed-on: #50
Co-authored-by: cake <cake@noreply.git.lightless-sync.org>
Co-committed-by: cake <cake@noreply.git.lightless-sync.org>
This commit was merged in pull request #50.
This commit is contained in:
2026-01-04 05:14:22 +00:00
committed by defnotken
parent ca0c548373
commit 9fffaf7df2
2 changed files with 59 additions and 19 deletions

View File

@@ -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<int> 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<IReadOnlyList<GroupPair>> 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<GroupPair> GetPruneUserList(
List<GroupPair> allGroupUsers,
HashSet<string> 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<HashSet<string>> GetOnlineUidsAsync()
{
var keys = await _redis.SearchKeysAsync("UID:*").ConfigureAwait(false);
var set = new HashSet<string>(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);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace LightlessSyncServer.Worker
var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<LightlessHub>>();
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)