101 lines
3.2 KiB
C#
101 lines
3.2 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using MediatR;
|
|
using Knot.Shared.Kernel;
|
|
using Knot.Shared.Kernel.Storage;
|
|
using Knot.Modules.Identity.Infrastructure.Persistence;
|
|
using Knot.Modules.Chats.Infrastructure.Persistence;
|
|
using Knot.Modules.Chats.Domain;
|
|
using MongoDB.Driver;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Host.Models;
|
|
|
|
namespace Host.Application.Admin.Queries;
|
|
|
|
public record CleanDryRunQuery(IFileStorageService FileStorage, IdentityDbContext IdentityDb) : IQuery<CleanupDryRunResultDto>;
|
|
|
|
internal sealed class CleanDryRunQueryHandler : IQueryHandler<CleanDryRunQuery, CleanupDryRunResultDto>
|
|
{
|
|
private readonly ChatsDbContext _chatsDbContext;
|
|
private readonly IMongoCollection<Message> _messages;
|
|
|
|
public CleanDryRunQueryHandler(ChatsDbContext chatsDbContext, IMongoDatabase mongoDb)
|
|
{
|
|
_chatsDbContext = chatsDbContext;
|
|
_messages = mongoDb.GetCollection<Message>("Messages");
|
|
}
|
|
|
|
public async Task<Result<CleanupDryRunResultDto>> Handle(CleanDryRunQuery request, CancellationToken cancellationToken)
|
|
{
|
|
var allChats = await _chatsDbContext.Chats.AsNoTracking().ToListAsync(cancellationToken);
|
|
var activeChatIds = allChats.Select(c => c.Id).ToHashSet();
|
|
|
|
var allMessages = await _messages.Find(_ => true).ToListAsync(cancellationToken);
|
|
|
|
var orphanedMessages = allMessages
|
|
.Where(m => !activeChatIds.Contains(m.ChatId))
|
|
.ToList();
|
|
|
|
var keptMessages = allMessages
|
|
.Where(m => activeChatIds.Contains(m.ChatId))
|
|
.ToList();
|
|
|
|
var orphanedMessagesCount = orphanedMessages.Count;
|
|
|
|
var allMinioFiles = (await request.FileStorage.ListFilesAsync()).ToList();
|
|
|
|
var allUsers = await request.IdentityDb.Users.AsNoTracking().ToListAsync(cancellationToken);
|
|
|
|
var validUrls = new HashSet<string>();
|
|
|
|
var activeMessageUrls = keptMessages.OfType<MediaMessage>()
|
|
.Where(m => m.Media != null)
|
|
.SelectMany(m => m.Media)
|
|
.Select(me => me.Url)
|
|
.Where(u => !string.IsNullOrEmpty(u));
|
|
|
|
var activeChatUrls = allChats
|
|
.Where(c => !string.IsNullOrEmpty(c.Avatar))
|
|
.Select(c => c.Avatar!);
|
|
|
|
var activeUserUrls = allUsers
|
|
.Where(u => !string.IsNullOrEmpty(u.Avatar))
|
|
.Select(u => u.Avatar!);
|
|
|
|
foreach (var u in activeMessageUrls)
|
|
{
|
|
validUrls.Add(u!);
|
|
}
|
|
foreach (var u in activeChatUrls)
|
|
{
|
|
validUrls.Add(u);
|
|
}
|
|
foreach (var u in activeUserUrls)
|
|
{
|
|
validUrls.Add(u);
|
|
}
|
|
|
|
var validFileIds = validUrls
|
|
.Where(u => u.Contains("/api/files/"))
|
|
.Select(u => u.Split('/').Last())
|
|
.ToHashSet();
|
|
|
|
long safeBytes = 0;
|
|
foreach (var file in allMinioFiles)
|
|
{
|
|
if (!validFileIds.Contains(file.FileId))
|
|
{
|
|
safeBytes += file.Size;
|
|
}
|
|
}
|
|
|
|
return Result.Success(new CleanupDryRunResultDto
|
|
{
|
|
OrphanedMessagesCount = orphanedMessagesCount,
|
|
OrphanedMediaBytes = safeBytes
|
|
});
|
|
}
|
|
} |