mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
2.4.2.2
This commit is contained in:
parent
44f697427e
commit
df68a5e2a4
@ -1,5 +1,9 @@
|
|||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
|
#### Version - 2.4.2.2 - 2/6/2020
|
||||||
|
* Better Origin game detection
|
||||||
|
* Don't check the download whitelist for files that are already downloaded
|
||||||
|
|
||||||
#### Version - 2.4.2.1 - 2/4/2020
|
#### Version - 2.4.2.1 - 2/4/2020
|
||||||
* HOTFIX - fix for the download path sometimes being empty
|
* HOTFIX - fix for the download path sometimes being empty
|
||||||
* HOTFIX - fix for some drive types not being detected (e.g. RAID drives)
|
* HOTFIX - fix for some drive types not being detected (e.g. RAID drives)
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<AssemblyName>wabbajack-cli</AssemblyName>
|
<AssemblyName>wabbajack-cli</AssemblyName>
|
||||||
<Company>Wabbajack</Company>
|
<Company>Wabbajack</Company>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<AssemblyVersion>2.4.2.1</AssemblyVersion>
|
<AssemblyVersion>2.4.2.2</AssemblyVersion>
|
||||||
<FileVersion>2.4.2.1</FileVersion>
|
<FileVersion>2.4.2.2</FileVersion>
|
||||||
<Copyright>Copyright © 2019-2020</Copyright>
|
<Copyright>Copyright © 2019-2020</Copyright>
|
||||||
<Description>An automated ModList installer</Description>
|
<Description>An automated ModList installer</Description>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
@ -132,6 +132,7 @@ namespace Wabbajack.Common
|
|||||||
public static RelativePath SettingsIni = (RelativePath)"settings.ini";
|
public static RelativePath SettingsIni = (RelativePath)"settings.ini";
|
||||||
public static byte SettingsVersion => 2;
|
public static byte SettingsVersion => 2;
|
||||||
public static TimeSpan MaxVerifyTime => TimeSpan.FromMinutes(10);
|
public static TimeSpan MaxVerifyTime => TimeSpan.FromMinutes(10);
|
||||||
|
public static readonly string WabbajackAuthoredFilesPrefix = "https://wabbajack.b-cdn.net/";
|
||||||
|
|
||||||
public static RelativePath NativeSettingsJson = (RelativePath)"native_compiler_settings.json";
|
public static RelativePath NativeSettingsJson = (RelativePath)"native_compiler_settings.json";
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0-windows</TargetFramework>
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<AssemblyVersion>2.4.2.1</AssemblyVersion>
|
<AssemblyVersion>2.4.2.2</AssemblyVersion>
|
||||||
<FileVersion>2.4.2.1</FileVersion>
|
<FileVersion>2.4.2.2</FileVersion>
|
||||||
<Copyright>Copyright © 2019-2020</Copyright>
|
<Copyright>Copyright © 2019-2020</Copyright>
|
||||||
<Description>Wabbajack Application Launcher</Description>
|
<Description>Wabbajack Application Launcher</Description>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
using Wabbajack.Lib.Downloaders;
|
using Wabbajack.Lib.Downloaders;
|
||||||
|
using Wabbajack.Lib.Validation;
|
||||||
using Wabbajack.VirtualFileSystem;
|
using Wabbajack.VirtualFileSystem;
|
||||||
using Path = Alphaleonis.Win32.Filesystem.Path;
|
using Path = Alphaleonis.Win32.Filesystem.Path;
|
||||||
|
|
||||||
@ -194,7 +195,9 @@ namespace Wabbajack.Lib
|
|||||||
|
|
||||||
Info("Getting Nexus API Key, if a browser appears, please accept");
|
Info("Getting Nexus API Key, if a browser appears, please accept");
|
||||||
|
|
||||||
var dispatchers = missing.Select(m => m.State.GetDownloader()).Distinct();
|
var dispatchers = missing.Select(m => m.State.GetDownloader())
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
await Task.WhenAll(dispatchers.Select(d => d.Prepare()));
|
await Task.WhenAll(dispatchers.Select(d => d.Prepare()));
|
||||||
|
|
||||||
@ -204,6 +207,14 @@ namespace Wabbajack.Lib
|
|||||||
throw new Exception($"Not enough Nexus API calls to download this list, please try again after midnight GMT when your API limits reset");
|
throw new Exception($"Not enough Nexus API calls to download this list, please try again after midnight GMT when your API limits reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var validationData = new ValidateModlist();
|
||||||
|
await validationData.LoadListsFromGithub();
|
||||||
|
|
||||||
|
foreach (var archive in missing.Where(archive => !archive.State.IsWhitelisted(validationData.ServerWhitelist)))
|
||||||
|
{
|
||||||
|
throw new Exception($"File {archive.State.PrimaryKeyString} failed validation");
|
||||||
|
}
|
||||||
|
|
||||||
await DownloadMissingArchives(missing);
|
await DownloadMissingArchives(missing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,6 +275,7 @@ namespace Wabbajack.Lib
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
var tsk = Metrics.Send("failed_download", archive.State.PrimaryKeyString);
|
||||||
Utils.Log($"Download error for file {archive.Name}");
|
Utils.Log($"Download error for file {archive.Name}");
|
||||||
Utils.Log(ex.ToString());
|
Utils.Log(ex.ToString());
|
||||||
return false;
|
return false;
|
||||||
|
@ -103,8 +103,7 @@ namespace Wabbajack.Lib
|
|||||||
await ValidateGameESMs();
|
await ValidateGameESMs();
|
||||||
|
|
||||||
if (cancel.IsCancellationRequested) return false;
|
if (cancel.IsCancellationRequested) return false;
|
||||||
UpdateTracker.NextStep("Validating Modlist");
|
UpdateTracker.NextStep("Creating Output Folders");
|
||||||
await ValidateModlist.RunValidation(ModList);
|
|
||||||
|
|
||||||
OutputFolder.CreateDirectory();
|
OutputFolder.CreateDirectory();
|
||||||
DownloadFolder.CreateDirectory();
|
DownloadFolder.CreateDirectory();
|
||||||
|
@ -57,7 +57,7 @@ namespace Wabbajack.Lib.Validation
|
|||||||
|
|
||||||
public async Task<IEnumerable<string>> Validate(ModList modlist)
|
public async Task<IEnumerable<string>> Validate(ModList modlist)
|
||||||
{
|
{
|
||||||
ConcurrentStack<string> ValidationErrors = new ConcurrentStack<string>();
|
ConcurrentStack<string> ValidationErrors = new();
|
||||||
modlist.Archives
|
modlist.Archives
|
||||||
.Where(m => !m.State.IsWhitelisted(ServerWhitelist))
|
.Where(m => !m.State.IsWhitelisted(ServerWhitelist))
|
||||||
.Do(m =>
|
.Do(m =>
|
||||||
|
@ -84,7 +84,11 @@ namespace Wabbajack.BuildServer.Test
|
|||||||
|
|
||||||
public T GetService<T>()
|
public T GetService<T>()
|
||||||
{
|
{
|
||||||
return (T)_host.Services.GetService(typeof(T));
|
var result = (T)_host.Services.GetService(typeof(T));
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
throw new Exception($"Service {typeof(T)} not found in configuration");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@ namespace Wabbajack.BuildServer.Test
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task CanUploadDownloadAndDeleteAuthoredFiles()
|
public async Task CanUploadDownloadAndDeleteAuthoredFiles()
|
||||||
{
|
{
|
||||||
|
var cleanup = Fixture.GetService<AuthoredFilesCleanup>();
|
||||||
|
var sql = Fixture.GetService<SqlService>();
|
||||||
|
|
||||||
|
var toDelete = await cleanup.FindFilesToDelete();
|
||||||
|
|
||||||
await using var file = new TempFile();
|
await using var file = new TempFile();
|
||||||
await file.Path.WriteAllBytesAsync(RandomData(Consts.UPLOADED_FILE_BLOCK_SIZE * 4 + Consts.UPLOADED_FILE_BLOCK_SIZE / 3));
|
await file.Path.WriteAllBytesAsync(RandomData(Consts.UPLOADED_FILE_BLOCK_SIZE * 4 + Consts.UPLOADED_FILE_BLOCK_SIZE / 3));
|
||||||
var originalHash = await file.Path.FileHashAsync();
|
var originalHash = await file.Path.FileHashAsync();
|
||||||
@ -30,9 +35,23 @@ namespace Wabbajack.BuildServer.Test
|
|||||||
using var queue = new WorkQueue(2);
|
using var queue = new WorkQueue(2);
|
||||||
var uri = await client.UploadFile(queue, file.Path, (s, percent) => Utils.Log($"({percent}) {s}"));
|
var uri = await client.UploadFile(queue, file.Path, (s, percent) => Utils.Log($"({percent}) {s}"));
|
||||||
|
|
||||||
var data = await Fixture.GetService<SqlService>().AllAuthoredFiles();
|
var data = (await Fixture.GetService<SqlService>().AllAuthoredFiles()).ToArray();
|
||||||
Assert.Contains((string)file.Path.FileName, data.Select(f => f.OriginalFileName));
|
Assert.Contains((string)file.Path.FileName, data.Select(f => f.OriginalFileName));
|
||||||
|
|
||||||
|
var listing = await cleanup.GetCDNMungedNames();
|
||||||
|
foreach (var d in data)
|
||||||
|
{
|
||||||
|
Assert.Contains(d.MungedName, listing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just uploaded it, so it shouldn't be marked for deletion
|
||||||
|
toDelete = await cleanup.FindFilesToDelete();
|
||||||
|
foreach (var d in data)
|
||||||
|
{
|
||||||
|
Assert.DoesNotContain(d.MungedName, toDelete.CDNDelete);
|
||||||
|
Assert.DoesNotContain(d.ServerAssignedUniqueId, toDelete.SQLDelete);
|
||||||
|
}
|
||||||
|
|
||||||
var result = await _client.GetStringAsync(MakeURL("authored_files"));
|
var result = await _client.GetStringAsync(MakeURL("authored_files"));
|
||||||
Assert.Contains((string)file.Path.FileName, result);
|
Assert.Contains((string)file.Path.FileName, result);
|
||||||
|
|
||||||
@ -42,6 +61,27 @@ namespace Wabbajack.BuildServer.Test
|
|||||||
await state.Download(new Archive(state) {Name = (string)file.Path.FileName}, file.Path);
|
await state.Download(new Archive(state) {Name = (string)file.Path.FileName}, file.Path);
|
||||||
Assert.Equal(originalHash, await file.Path.FileHashAsync());
|
Assert.Equal(originalHash, await file.Path.FileHashAsync());
|
||||||
|
|
||||||
|
// Mark it as old
|
||||||
|
foreach (var d in data)
|
||||||
|
{
|
||||||
|
await sql.TouchAuthoredFile(await sql.GetCDNFileDefinition(d.ServerAssignedUniqueId), DateTime.Now - TimeSpan.FromDays(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now it should be marked for deletion
|
||||||
|
toDelete = await cleanup.FindFilesToDelete();
|
||||||
|
foreach (var d in data)
|
||||||
|
{
|
||||||
|
Assert.Contains(d.MungedName, toDelete.CDNDelete);
|
||||||
|
Assert.Contains(d.ServerAssignedUniqueId, toDelete.SQLDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
await cleanup.Execute();
|
||||||
|
|
||||||
|
toDelete = await cleanup.FindFilesToDelete();
|
||||||
|
|
||||||
|
Assert.Empty(toDelete.CDNDelete);
|
||||||
|
Assert.Empty(toDelete.SQLDelete);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using FluentFTP;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
|
|
||||||
namespace Wabbajack.Server.DTOs
|
namespace Wabbajack.Server.DTOs
|
||||||
@ -21,5 +23,12 @@ namespace Wabbajack.Server.DTOs
|
|||||||
{
|
{
|
||||||
return (await Utils.FromEncryptedJson<Dictionary<string, BunnyCdnFtpInfo>>("bunnycdn"))[space.ToString()];
|
return (await Utils.FromEncryptedJson<Dictionary<string, BunnyCdnFtpInfo>>("bunnycdn"))[space.ToString()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<FtpClient> GetClient()
|
||||||
|
{
|
||||||
|
var ftpClient = new FtpClient(Hostname, new NetworkCredential(Username, Password));
|
||||||
|
await ftpClient.ConnectAsync();
|
||||||
|
return ftpClient;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,21 @@ namespace Wabbajack.Server.DataLayer
|
|||||||
{
|
{
|
||||||
public partial class SqlService
|
public partial class SqlService
|
||||||
{
|
{
|
||||||
public async Task TouchAuthoredFile(CDNFileDefinition definition)
|
public async Task TouchAuthoredFile(CDNFileDefinition definition, DateTime? date = null)
|
||||||
{
|
{
|
||||||
await using var conn = await Open();
|
await using var conn = await Open();
|
||||||
await conn.ExecuteAsync("UPDATE AuthoredFiles SET LastTouched = GETUTCDATE() WHERE ServerAssignedUniqueId = @Uid",
|
if (date == null)
|
||||||
new {
|
{
|
||||||
Uid = definition.ServerAssignedUniqueId
|
await conn.ExecuteAsync(
|
||||||
});
|
"UPDATE AuthoredFiles SET LastTouched = GETUTCDATE() WHERE ServerAssignedUniqueId = @Uid",
|
||||||
|
new {Uid = definition.ServerAssignedUniqueId});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await conn.ExecuteAsync(
|
||||||
|
"UPDATE AuthoredFiles SET LastTouched = @Date WHERE ServerAssignedUniqueId = @Uid",
|
||||||
|
new {Uid = definition.ServerAssignedUniqueId, Date = date});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CDNFileDefinition> CreateAuthoredFile(CDNFileDefinition definition, string login)
|
public async Task<CDNFileDefinition> CreateAuthoredFile(CDNFileDefinition definition, string login)
|
||||||
@ -55,12 +63,13 @@ namespace Wabbajack.Server.DataLayer
|
|||||||
new {Uid = serverAssignedUniqueId})).First();
|
new {Uid = serverAssignedUniqueId})).First();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CDNFileDefinition> DeleteFileDefinition(CDNFileDefinition definition)
|
public async Task DeleteFileDefinition(CDNFileDefinition definition)
|
||||||
{
|
{
|
||||||
await using var conn = await Open();
|
await using var conn = await Open();
|
||||||
return (await conn.QueryAsync<CDNFileDefinition>(
|
await conn.ExecuteAsync(
|
||||||
"DELETE FROM dbo.AuthoredFiles WHERE ServerAssignedUniqueID = @Uid",
|
"DELETE FROM dbo.AuthoredFiles WHERE ServerAssignedUniqueID = @Uid",
|
||||||
new {Uid = definition.ServerAssignedUniqueId})).First();
|
new {Uid = definition.ServerAssignedUniqueId});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<AuthoredFilesSummary>> AllAuthoredFiles()
|
public async Task<IEnumerable<AuthoredFilesSummary>> AllAuthoredFiles()
|
||||||
@ -68,7 +77,6 @@ namespace Wabbajack.Server.DataLayer
|
|||||||
await using var conn = await Open();
|
await using var conn = await Open();
|
||||||
var results = await conn.QueryAsync<AuthoredFilesSummary>("SELECT CONVERT(NVARCHAR(50), ServerAssignedUniqueId) as ServerAssignedUniqueId, Size, OriginalFileName, Author, LastTouched, Finalized, MungedName from dbo.AuthoredFilesSummaries ORDER BY LastTouched DESC");
|
var results = await conn.QueryAsync<AuthoredFilesSummary>("SELECT CONVERT(NVARCHAR(50), ServerAssignedUniqueId) as ServerAssignedUniqueId, Size, OriginalFileName, Author, LastTouched, Finalized, MungedName from dbo.AuthoredFilesSummaries ORDER BY LastTouched DESC");
|
||||||
return results;
|
return results;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
139
Wabbajack.Server/Services/AuthoredFilesCleanup.cs
Normal file
139
Wabbajack.Server/Services/AuthoredFilesCleanup.cs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using FluentFTP;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Wabbajack.BuildServer;
|
||||||
|
using Wabbajack.Common;
|
||||||
|
using Wabbajack.Lib.AuthorApi;
|
||||||
|
using Wabbajack.Lib.Downloaders;
|
||||||
|
using Wabbajack.Lib.ModListRegistry;
|
||||||
|
using Wabbajack.Server.DataLayer;
|
||||||
|
using Wabbajack.Server.DTOs;
|
||||||
|
using WebSocketSharp;
|
||||||
|
|
||||||
|
namespace Wabbajack.Server.Services
|
||||||
|
{
|
||||||
|
public class AuthoredFilesCleanup : AbstractService<AuthoredFilesCleanup, int>
|
||||||
|
{
|
||||||
|
private SqlService _sql;
|
||||||
|
private DiscordWebHook _discord;
|
||||||
|
|
||||||
|
public AuthoredFilesCleanup(ILogger<AuthoredFilesCleanup> logger, AppSettings settings, QuickSync quickSync, SqlService sql, DiscordWebHook discord) : base(logger, settings, quickSync, TimeSpan.FromHours(6))
|
||||||
|
{
|
||||||
|
_sql = sql;
|
||||||
|
_discord = discord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<int> Execute()
|
||||||
|
{
|
||||||
|
|
||||||
|
var toDelete = await FindFilesToDelete();
|
||||||
|
|
||||||
|
var log = new[] {$"CDNDelete ({toDelete.CDNDelete.Length}):\n\n"}
|
||||||
|
.Concat(toDelete.CDNDelete)
|
||||||
|
.Concat(new[] {$"SQLDelete ({toDelete.SQLDelete.Length}"})
|
||||||
|
.Concat(toDelete.SQLDelete)
|
||||||
|
.Concat(new[] {$"CDNRemain ({toDelete.CDNNotDeleted.Length}"})
|
||||||
|
.Concat(toDelete.CDNNotDeleted)
|
||||||
|
.Concat(new[] {$"SQLRemain ({toDelete.SQLNotDeleted.Length}"})
|
||||||
|
.Concat(toDelete.SQLNotDeleted)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
//await AbsolutePath.EntryPoint.Combine("cdn_delete_log.txt").WriteAllLinesAsync(log);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var sqlFile in toDelete.SQLDelete)
|
||||||
|
{
|
||||||
|
Utils.Log($"Deleting {sqlFile} from SQL");
|
||||||
|
await _sql.DeleteFileDefinition(await _sql.GetCDNFileDefinition(sqlFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using var queue = new WorkQueue(6);
|
||||||
|
await toDelete.CDNDelete.Select((d, idx) => (d, idx)).PMap(queue, async cdnFile =>
|
||||||
|
{
|
||||||
|
using var conn = await (await BunnyCdnFtpInfo.GetCreds(StorageSpace.AuthoredFiles)).GetClient();
|
||||||
|
Utils.Log($"Deleting {cdnFile} from CDN");
|
||||||
|
await _discord.Send(Channel.Ham,
|
||||||
|
new DiscordMessage
|
||||||
|
{
|
||||||
|
Content =
|
||||||
|
$"({cdnFile.idx}/{toDelete.CDNDelete.Length}) {cdnFile.d} is no longer referenced by any modlist and will be removed from the CDN"
|
||||||
|
});
|
||||||
|
if (await conn.DirectoryExistsAsync(cdnFile.d))
|
||||||
|
await conn.DeleteDirectoryAsync(cdnFile.d);
|
||||||
|
|
||||||
|
if (await conn.FileExistsAsync(cdnFile.d))
|
||||||
|
await conn.DeleteFileAsync(cdnFile.d);
|
||||||
|
});
|
||||||
|
return toDelete.CDNDelete.Length + toDelete.SQLDelete.Length;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(string[] CDNDelete, string[] SQLDelete, string[] CDNNotDeleted, string[] SQLNotDeleted)> FindFilesToDelete()
|
||||||
|
{
|
||||||
|
var cdnNames = (await GetCDNMungedNames()).ToHashSet();
|
||||||
|
var usedNames = (await GetUsedCDNFiles()).ToHashSet();
|
||||||
|
var sqlFiles = (await _sql.AllAuthoredFiles()).ToDictionary(f => f.MungedName);
|
||||||
|
var keep = GetKeepList(cdnNames, usedNames, sqlFiles).ToHashSet();
|
||||||
|
|
||||||
|
var cdnDelete = cdnNames.Where(h => !keep.Contains(h)).ToArray();
|
||||||
|
var sqlDelete = sqlFiles.Where(s => !keep.Contains(s.Value.MungedName))
|
||||||
|
.Select(s => s.Value.ServerAssignedUniqueId)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var cdnhs = cdnDelete.ToHashSet();
|
||||||
|
var notDeletedCDN = cdnNames.Where(f => !cdnhs.Contains(f)).ToArray();
|
||||||
|
var sqlhs = sqlDelete.ToHashSet();
|
||||||
|
var sqlNotDeleted = sqlFiles.Where(f => !sqlDelete.Contains(f.Value.ServerAssignedUniqueId))
|
||||||
|
.Select(f => f.Value.MungedName)
|
||||||
|
.ToArray();
|
||||||
|
return (cdnDelete, sqlDelete, notDeletedCDN, sqlNotDeleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<string> GetKeepList(HashSet<string> cdnNames, HashSet<string> usedNames, Dictionary<string, AuthoredFilesSummary> sqlFiles)
|
||||||
|
{
|
||||||
|
var cutOff = DateTime.UtcNow - TimeSpan.FromDays(7);
|
||||||
|
foreach (var file in sqlFiles.Where(f => f.Value.LastTouched > cutOff))
|
||||||
|
yield return file.Value.MungedName;
|
||||||
|
|
||||||
|
foreach (var file in usedNames)
|
||||||
|
yield return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string[]> GetCDNMungedNames()
|
||||||
|
{
|
||||||
|
using var client = await (await BunnyCdnFtpInfo.GetCreds(StorageSpace.AuthoredFiles)).GetClient();
|
||||||
|
var lst = await client.GetListingAsync(@"\");
|
||||||
|
return lst.Select(l => l.Name).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string[]> GetUsedCDNFiles()
|
||||||
|
{
|
||||||
|
var modlists = (await ModlistMetadata.LoadFromGithub())
|
||||||
|
.Concat((await ModlistMetadata.LoadUnlistedFromGithub()))
|
||||||
|
.Select(f => f.Links.Download)
|
||||||
|
.Where(f => f.StartsWith(Consts.WabbajackAuthoredFilesPrefix))
|
||||||
|
.Select(f => f.Substring(Consts.WabbajackAuthoredFilesPrefix.Length));
|
||||||
|
|
||||||
|
var files = (await _sql.ModListArchives())
|
||||||
|
.Select(a => a.State)
|
||||||
|
.OfType<WabbajackCDNDownloader.State>()
|
||||||
|
.Select(s => s.Url.ToString().Substring(Consts.WabbajackAuthoredFilesPrefix.Length));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var names = modlists.Concat(files).Distinct().ToArray();
|
||||||
|
var namesBoth = names.Concat(names.Select(HttpUtility.UrlDecode))
|
||||||
|
.Concat(names.Select(HttpUtility.UrlEncode))
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
return namesBoth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -75,6 +75,7 @@ namespace Wabbajack.Server
|
|||||||
services.AddSingleton<MirrorQueueService>();
|
services.AddSingleton<MirrorQueueService>();
|
||||||
services.AddSingleton<Watchdog>();
|
services.AddSingleton<Watchdog>();
|
||||||
services.AddSingleton<DiscordFrontend>();
|
services.AddSingleton<DiscordFrontend>();
|
||||||
|
services.AddSingleton<AuthoredFilesCleanup>();
|
||||||
|
|
||||||
services.AddMvc();
|
services.AddMvc();
|
||||||
services.AddControllers()
|
services.AddControllers()
|
||||||
@ -135,6 +136,7 @@ namespace Wabbajack.Server
|
|||||||
app.UseService<MirrorQueueService>();
|
app.UseService<MirrorQueueService>();
|
||||||
app.UseService<Watchdog>();
|
app.UseService<Watchdog>();
|
||||||
app.UseService<DiscordFrontend>();
|
app.UseService<DiscordFrontend>();
|
||||||
|
app.UseService<AuthoredFilesCleanup>();
|
||||||
|
|
||||||
app.Use(next =>
|
app.Use(next =>
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net5.0-windows</TargetFramework>
|
<TargetFramework>net5.0-windows</TargetFramework>
|
||||||
<AssemblyVersion>2.4.2.1</AssemblyVersion>
|
<AssemblyVersion>2.4.2.2</AssemblyVersion>
|
||||||
<FileVersion>2.4.2.1</FileVersion>
|
<FileVersion>2.4.2.2</FileVersion>
|
||||||
<Copyright>Copyright © 2019-2020</Copyright>
|
<Copyright>Copyright © 2019-2020</Copyright>
|
||||||
<Description>Wabbajack Server</Description>
|
<Description>Wabbajack Server</Description>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
@ -33,6 +33,11 @@
|
|||||||
<canvas id="started_wabbajack_chart" width="800" height="600"></canvas>
|
<canvas id="started_wabbajack_chart" width="800" height="600"></canvas>
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
|
<h2>Exceptions</h2>
|
||||||
|
<canvas id="exceptions_chart" width="800" height="600"></canvas>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -101,6 +106,7 @@
|
|||||||
makeChart("begin_install_chart", "begin_install");
|
makeChart("begin_install_chart", "begin_install");
|
||||||
makeChart("finished_install_chart", "finish_install");
|
makeChart("finished_install_chart", "finish_install");
|
||||||
makeChart("started_wabbajack_chart", "started_wabbajack");
|
makeChart("started_wabbajack_chart", "started_wabbajack");
|
||||||
|
makeChart("exceptions_chart", "Exception");
|
||||||
makePieChart("finished_install_count", "finish_install");
|
makePieChart("finished_install_count", "finish_install");
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
|
||||||
<AssemblyVersion>2.4.2.1</AssemblyVersion>
|
<AssemblyVersion>2.4.2.2</AssemblyVersion>
|
||||||
<FileVersion>2.4.2.1</FileVersion>
|
<FileVersion>2.4.2.2</FileVersion>
|
||||||
<Copyright>Copyright © 2019-2020</Copyright>
|
<Copyright>Copyright © 2019-2020</Copyright>
|
||||||
<Description>An automated ModList installer</Description>
|
<Description>An automated ModList installer</Description>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
Loading…
Reference in New Issue
Block a user