LANCommander/LANCommander.Server.Services/RedistributableService.cs

135 lines
5.7 KiB
C#

using System.IO.Compression;
using LANCommander.Server.Data;
using LANCommander.Server.Data.Models;
using LANCommander.Server.Services.Extensions;
using AutoMapper;
using LANCommander.SDK.Enums;
using LANCommander.SDK.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using ZiggyCreatures.Caching.Fusion;
namespace LANCommander.Server.Services
{
public sealed class RedistributableService(
ILogger<SDK.Services.RedistributableClient> logger,
ArchiveService archiveService,
StorageLocationService storageLocationService,
SettingsProvider<Settings.Settings> settingsProvider,
ScriptClient scriptClient,
IFusionCache cache,
IMapper mapper,
IHttpContextAccessor httpContextAccessor,
IDbContextFactory<DatabaseContext> contextFactory) : BaseDatabaseService<Redistributable>(logger, settingsProvider, cache, mapper, httpContextAccessor, contextFactory)
{
public override async Task<Redistributable> AddAsync(Redistributable entity)
{
await cache.ExpireGameCacheAsync();
return await base.AddAsync(entity, async context =>
{
await context.UpdateRelationshipAsync(r => r.Archives);
await context.UpdateRelationshipAsync(r => r.Games);
await context.UpdateRelationshipAsync(r => r.Pages);
await context.UpdateRelationshipAsync(r => r.Scripts);
});
}
public override async Task<Redistributable> UpdateAsync(Redistributable entity)
{
if (entity.Games != null && entity.Games.Any())
{
foreach (var game in entity.Games)
{
await cache.ExpireGameCacheAsync(game?.Id);
}
}
return await base.UpdateAsync(entity, async context =>
{
await context.UpdateRelationshipAsync(r => r.Archives);
await context.UpdateRelationshipAsync(r => r.Games);
await context.UpdateRelationshipAsync(r => r.Pages);
await context.UpdateRelationshipAsync(r => r.Scripts);
});
}
public async Task<SDK.Models.Manifest.Redistributable> GetManifestAsync(Guid manifestId)
{
var redistributable = await AsNoTracking()
.AsSplitQuery()
.Query(q =>
{
return q
.Include(r => r.Archives)
.Include(r => r.Scripts);
})
.GetAsync(manifestId);
return mapper.Map<SDK.Models.Manifest.Redistributable>(redistributable);
}
public async Task PackageAsync(Guid id)
{
var redistributable = await AsNoTracking()
.AsSplitQuery()
.Include(r => r.Archives)
.Include(r => r.Scripts)
.Include(r => r.Games)
.GetAsync(id);
logger?.LogInformation("Packaging redistributable {RedistributableName}", redistributable.Name);
var latestArchive = redistributable.Archives?.OrderByDescending(r => r.CreatedOn).FirstOrDefault();
var storageLocation = await storageLocationService.GetOrDefaultAsync(latestArchive?.StorageLocationId, StorageLocationType.Archive);
if (redistributable.Scripts?.Any(s => s.Type == ScriptType.Package) ?? false)
{
foreach (var script in redistributable.Scripts.Where(s => s.Type == ScriptType.Package))
{
var package = await scriptClient.Redistributable_RunPackageScriptAsync(mapper.Map<SDK.Models.Script>(script), mapper.Map<SDK.Models.Redistributable>(redistributable));
if (package == null)
{
var message = $"Could not package redistributable {redistributable.Name}, the package script did not return a result";
logger?.LogError(message);
throw new Exception(message);
}
if (String.IsNullOrWhiteSpace(package.Path) || !Directory.Exists(package.Path))
{
var message = $"Could not package redistributable {redistributable.Name}, the path {package.Path} could not be found";
logger?.LogError(message);
throw new Exception(message);
}
var archive = new Archive
{
Version = package.Version,
RedistributableId = redistributable.Id,
ObjectKey = Guid.NewGuid().ToString(),
LastVersion = latestArchive,
StorageLocationId = storageLocation.Id,
};
archive = await archiveService.AddAsync(archive);
var destination = await archiveService.GetArchiveFileLocationAsync(archive);
ZipFile.CreateFromDirectory(package.Path, destination);
await archiveService.RecalculateFileSizeArchiveAsync(archive);
logger?.LogInformation("Successfully packaged {RedistributableName} and created new archive with version number {RedistributableVersion}", redistributable.Name, archive.Version);
}
}
else
{
var message = $"Could not package redistributable {redistributable.Name}, no packaging scripts are defined";
logger?.LogWarning(message);
throw new Exception(message);
}
}
}
}