Can get the names/hashes for stock game files

This commit is contained in:
Timothy Baldridge 2020-04-30 16:35:16 -06:00
parent 895bdb15a6
commit a1c5cfad82
6 changed files with 130 additions and 2 deletions

View File

@ -86,6 +86,52 @@ namespace Wabbajack.BuildServer.Test
Assert.Null(await SQL.GetJob());
}
[Fact]
public async Task CanGetGameFiles()
{
var sql = Fixture.GetService<SqlService>();
await sql.AddDownloadState(Hash.FromLong(1),
new GameFileSourceDownloader.State("1.2.3.4")
{
Game = Game.SkyrimSpecialEdition,
Hash = Hash.FromLong(1),
GameFile = (RelativePath)@"Data\foo.bsa",
});
await sql.AddDownloadState(Hash.FromLong(2),
new GameFileSourceDownloader.State("1.2.3.4")
{
Game = Game.SkyrimSpecialEdition,
Hash = Hash.FromLong(2),
GameFile = (RelativePath)@"Data\foo - Textures.bsa",
});
await sql.AddDownloadState(Hash.FromLong(3),
new GameFileSourceDownloader.State("1.2.3.4")
{
Game = Game.Skyrim,
Hash = Hash.FromLong(3),
GameFile = (RelativePath)@"Data\foo - Textures.bsa",
});
await sql.AddDownloadState(Hash.FromLong(4),
new GameFileSourceDownloader.State("1.9.3.4")
{
Game = Game.SkyrimSpecialEdition,
Hash = Hash.FromLong(4),
GameFile = (RelativePath)@"Data\foo - Textures.bsa",
});
var results = await ClientAPI.GetGameFiles(Game.SkyrimSpecialEdition, Version.Parse("1.2.3.4"));
Assert.Equal(new Dictionary<RelativePath, Hash>
{
{(RelativePath)@"Data\foo.bsa", Hash.FromLong(1)},
{(RelativePath)@"Data\foo - Textures.bsa", Hash.FromLong(2)},
}, results);
}
public IndexedFilesTests(ITestOutputHelper output, SingletonAdaptor<BuildServerFixture> fixture) : base(output, fixture)
{

View File

@ -460,6 +460,33 @@ CREATE NONCLUSTERED INDEX [ByHash] ON [dbo].[DownloadStates]
INCLUDE([IniState]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
/****** Object: View [dbo].[GameFiles] Script Date: 4/30/2020 4:23:25 PM ******/
CREATE VIEW [dbo].[GameFiles]
WITH SCHEMABINDING
AS
Select
Id,
CONVERT(NVARCHAR(20), JSON_VALUE(JsonState,'$.GameVersion')) as GameVersion,
CONVERT(NVARCHAR(32),JSON_VALUE(JsonState,'$.Game')) as Game,
JSON_VALUE(JsonState,'$.GameFile') as Path,
Hash as Hash
FROM dbo.DownloadStates
WHERE PrimaryKey like 'GameFileSourceDownloader+State|%'
AND JSON_VALUE(JsonState,'$.GameFile') NOT LIKE '%.xxhash'
GO
CREATE UNIQUE CLUSTERED INDEX [ByGameAndVersion] ON [dbo].[GameFiles]
(
[Game] ASC,
[GameVersion] ASC,
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
/****** Object: Index [IX_Child] Script Date: 3/28/2020 4:58:59 PM ******/
CREATE NONCLUSTERED INDEX [IX_Child] ON [dbo].[AllFilesInArchive]
(

View File

@ -131,6 +131,14 @@ namespace Wabbajack.BuildServer.Controllers
return Ok(result);
}
[HttpGet]
[Route("/game_files/{game}/{version}")]
public async Task<IActionResult> GetGameFiles(string game, string version)
{
var result = await _sql.GameFiles(GameRegistry.GetByFuzzyName(game).Game, Version.Parse(version));
return Ok(result.ToDictionary(k => k.Item1, k => k.Item2));
}
public class TreeResult : IndexedFile
{
public List<TreeResult> ChildFiles { get; set; }

View File

@ -86,7 +86,7 @@ namespace Wabbajack.BuildServer
while (true)
{
await KillOrphanedJobs();
//await ScheduledJob<GetNexusUpdatesJob>(TimeSpan.FromHours(1), Job.JobPriority.High);
await ScheduledJob<GetNexusUpdatesJob>(TimeSpan.FromHours(1), Job.JobPriority.High);
//await ScheduledJob<UpdateModLists>(TimeSpan.FromMinutes(30), Job.JobPriority.High);
//await ScheduledJob<EnqueueAllArchives>(TimeSpan.FromHours(2), Job.JobPriority.Low);
//await ScheduledJob<EnqueueAllGameFiles>(TimeSpan.FromHours(24), Job.JobPriority.High);

View File

@ -138,6 +138,17 @@ namespace Wabbajack.BuildServer.Model.Models
return Build(0).FirstOrDefault();
}
public async Task<IEnumerable<(RelativePath, Hash)>> GameFiles(Game game, Version version)
{
await using var conn = await Open();
var files = await conn.QueryAsync<(RelativePath, Hash)>(
@"SELECT Path, Hash FROM dbo.GameFiles where Game = @Game AND GameVersion = @GameVersion",
new {Game = game.ToString(), GameVersion = version});
return files;
}
public async Task IngestAllMetrics(IEnumerable<Metric> allMetrics)
{
await using var conn = await Open();
@ -287,6 +298,8 @@ namespace Wabbajack.BuildServer.Model.Models
SqlMapper.AddTypeHandler(new JsonMapper<AJobPayload>());
SqlMapper.AddTypeHandler(new JsonMapper<JobResult>());
SqlMapper.AddTypeHandler(new JsonMapper<Job>());
SqlMapper.AddTypeHandler(new VersionMapper());
SqlMapper.AddTypeHandler(new GameMapper());
}
public class JsonMapper<T> : SqlMapper.TypeHandler<T>
@ -328,6 +341,32 @@ namespace Wabbajack.BuildServer.Model.Models
}
}
class VersionMapper : SqlMapper.TypeHandler<Version>
{
public override void SetValue(IDbDataParameter parameter, Version value)
{
parameter.Value = value.ToString();
}
public override Version Parse(object value)
{
return Version.Parse((string)value);
}
}
class GameMapper : SqlMapper.TypeHandler<Game>
{
public override void SetValue(IDbDataParameter parameter, Game value)
{
parameter.Value = value.ToString();
}
public override Game Parse(object value)
{
return GameRegistry.GetByFuzzyName((string)value).Game;
}
}
#endregion

View File

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Wabbajack.Common;
using Wabbajack.Lib.Exceptions;
@ -59,5 +61,11 @@ namespace Wabbajack.Lib
return await GetClient()
.GetJsonAsync<NexusCacheStats>($"{Consts.WabbajackBuildServerUri}nexus_cache/stats");
}
public static async Task<Dictionary<RelativePath, Hash>> GetGameFiles(Game game, Version version)
{
return await GetClient()
.GetJsonAsync<Dictionary<RelativePath, Hash>>($"{Consts.WabbajackBuildServerUri}game_files/{game}/{version}");
}
}
}