Compare commits
1 commit
main
...
refactor/d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86ab116af8 |
3 changed files with 110 additions and 23 deletions
|
|
@ -92,28 +92,6 @@ namespace LANCommander.Server.Services
|
|||
await context.UpdateRelationshipAsync(a => a.StorageLocation);
|
||||
});
|
||||
}
|
||||
|
||||
public override async Task DeleteAsync(Archive archive)
|
||||
{
|
||||
FileHelpers.DeleteIfExists(await GetArchiveFileLocationAsync(archive));
|
||||
|
||||
await cache.ExpireGameCacheAsync(archive.GameId);
|
||||
await cache.ExpireArchiveCacheAsync(archive.Id);
|
||||
|
||||
await base.DeleteAsync(archive);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Archive archive, StorageLocation storageLocation = null)
|
||||
{
|
||||
if (storageLocation == null)
|
||||
FileHelpers.DeleteIfExists(await GetArchiveFileLocationAsync(archive));
|
||||
else
|
||||
FileHelpers.DeleteIfExists(GetArchiveFileLocation(archive, storageLocation));
|
||||
|
||||
await cache.ExpireGameCacheAsync(archive.GameId);
|
||||
|
||||
await base.DeleteAsync(archive);
|
||||
}
|
||||
|
||||
public async Task<SDK.Models.Manifest.Game> ReadManifestAsync(string objectKey)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
using LANCommander.Helpers;
|
||||
using LANCommander.Server.Data.Models;
|
||||
using LANCommander.Server.Services.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace LANCommander.Server.Services.Interceptors
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures the file for an archive is deleted whenever dropped from the database
|
||||
/// Also ensures that when games/redistributables are deleted, archives are deleted as well
|
||||
/// </summary>
|
||||
public class DeleteArchiveInterceptor(
|
||||
ArchiveService archiveService,
|
||||
IFusionCache cache) : SaveChangesInterceptor
|
||||
{
|
||||
private readonly List<Archive> _pendingArchives = new();
|
||||
|
||||
public override async ValueTask<int> SavedChangesAsync(SaveChangesCompletedEventData eventData, int result,
|
||||
CancellationToken cancellationToken = new())
|
||||
{
|
||||
foreach (var archive in _pendingArchives)
|
||||
{
|
||||
FileHelpers.DeleteIfExists(await archiveService.GetArchiveFileLocationAsync(archive));
|
||||
|
||||
await cache.ExpireGameCacheAsync(archive.GameId);
|
||||
await cache.ExpireArchiveCacheAsync(archive.Id);
|
||||
}
|
||||
|
||||
return await base.SavedChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
|
||||
public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
|
||||
DbContextEventData eventData,
|
||||
InterceptionResult<int> result,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var context = eventData.Context;
|
||||
|
||||
if (context is null)
|
||||
return await base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
|
||||
var deletedGames = context.ChangeTracker
|
||||
.Entries<Game>()
|
||||
.Where(e => e.State == EntityState.Deleted)
|
||||
.Select(e => e.Entity)
|
||||
.ToList();
|
||||
|
||||
foreach (var game in deletedGames)
|
||||
{
|
||||
var archives = context.Entry(game).Collection(g => g.Archives!);
|
||||
|
||||
if (!archives.IsLoaded)
|
||||
await archives.LoadAsync(cancellationToken);
|
||||
|
||||
if (game.Archives != null)
|
||||
foreach (var archive in game.Archives)
|
||||
{
|
||||
var entry = context.Entry(archive);
|
||||
|
||||
if (entry.State == EntityState.Deleted || entry.State == EntityState.Unchanged)
|
||||
entry.State = EntityState.Deleted;
|
||||
}
|
||||
}
|
||||
|
||||
var deletedRedistributables = context.ChangeTracker
|
||||
.Entries<Redistributable>()
|
||||
.Where(e => e.State == EntityState.Deleted)
|
||||
.Select(e => e.Entity)
|
||||
.ToList();
|
||||
|
||||
foreach (var redistributable in deletedRedistributables)
|
||||
{
|
||||
var archives = context.Entry(redistributable).Collection(r => r.Archives!);
|
||||
|
||||
if (!archives.IsLoaded)
|
||||
await archives.LoadAsync(cancellationToken);
|
||||
|
||||
if (redistributable.Archives != null)
|
||||
foreach (var archive in redistributable.Archives)
|
||||
{
|
||||
var entry = context.Entry(archive);
|
||||
|
||||
if (entry.State == EntityState.Deleted || entry.State == EntityState.Unchanged)
|
||||
entry.State = EntityState.Deleted;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entry in context.ChangeTracker.Entries<Archive>())
|
||||
{
|
||||
var storageLocation = entry.Reference(a => a.StorageLocation);
|
||||
|
||||
if (!storageLocation.IsLoaded)
|
||||
await storageLocation.LoadAsync(cancellationToken);
|
||||
|
||||
if (entry.State == EntityState.Deleted)
|
||||
_pendingArchives.Add(entry.Entity);
|
||||
}
|
||||
|
||||
return await base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using LANCommander.Server.Data;
|
|||
using LANCommander.Server.Data.Enums;
|
||||
using LANCommander.Server.Data.Models;
|
||||
using LANCommander.Server.Services;
|
||||
using LANCommander.Server.Services.Interceptors;
|
||||
using LANCommander.Server.Services.Models;
|
||||
using LANCommander.Server.Settings.Enums;
|
||||
using LANCommander.Server.Settings.Models;
|
||||
|
|
@ -18,7 +19,11 @@ public static class Database
|
|||
{
|
||||
public static WebApplicationBuilder AddDatabase(this WebApplicationBuilder builder, string[] args)
|
||||
{
|
||||
builder.Services.AddDbContextFactory<DatabaseContext>();
|
||||
builder.Services.AddScoped<DeleteArchiveInterceptor>();
|
||||
builder.Services.AddDbContextFactory<DatabaseContext>((sp, options) =>
|
||||
{
|
||||
options.AddInterceptors(sp.GetRequiredService<DeleteArchiveInterceptor>());
|
||||
});
|
||||
builder.Services.AddDbContext<DatabaseContext>();
|
||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue