Skip to content

Commit

Permalink
Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Aragas committed Dec 21, 2023
1 parent 21d5ab8 commit bbb3c7e
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/BUTR.Site.NexusMods.Client/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static WebAssemblyHostBuilder CreateHostBuilder(string[] args)
services.AddTransient<IGOGClient, GOGClient>(sp => ConfigureClient(sp, (http, opt) => new GOGClient(http, opt)));
services.AddTransient<IStatisticsClient, StatisticsClient>(sp => ConfigureClient(sp, (http, opt) => new StatisticsClient(http, opt)));
services.AddTransient<IQuartzClient, QuartzClient>(sp => ConfigureClient(sp, (http, opt) => new QuartzClient(http, opt)));
//services.AddTransient<IRecreateStacktraceClient, RecreateStacktraceClient>(sp => ConfigureClient(sp, (http, opt) => new RecreateStacktraceClient(http, opt)));
services.AddTransient<IRecreateStacktraceClient, RecreateStacktraceClient>(sp => ConfigureClient(sp, (http, opt) => new RecreateStacktraceClient(http, opt)));

services.AddScoped<TenantProvider>();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using BUTR.Authentication.NexusMods.Authentication;
using BUTR.CrashReport.Bannerlord.Parser;
using BUTR.CrashReport.Models;
using BUTR.Site.NexusMods.Server.Extensions;
using BUTR.Site.NexusMods.Server.Models;
using BUTR.Site.NexusMods.Server.Services;
using BUTR.Site.NexusMods.Server.Utils;
Expand Down
136 changes: 127 additions & 9 deletions src/BUTR.Site.NexusMods.Server/Services/NexusModsModFileParser.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using AsmResolver.DotNet;
using AsmResolver.PE;

using Bannerlord.ModuleManager;

using BUTR.Site.NexusMods.Server.Extensions;
using BUTR.Site.NexusMods.Server.Models;
using BUTR.Site.NexusMods.Server.Models.NexusModsAPI;
using BUTR.Site.NexusMods.Server.Utils;
using BUTR.Site.NexusMods.Server.Utils.Http;

using SharpCompress.Archives;
Expand All @@ -23,9 +27,20 @@

namespace BUTR.Site.NexusMods.Server.Services;

public sealed record ModuleInfoExtendedWithPath : ModuleInfoExtended
{
public string Path { get; init; }

public ModuleInfoExtendedWithPath(ModuleInfoExtended moduleInfoExtended, string path) : base(moduleInfoExtended)
{
Path = path;
}
}

public sealed record NexusModsModFileParserResult
{
public required ModuleInfoExtended ModuleInfo { get; init; }
public required GameVersion[] GameVersions { get; init; }
public required NexusModsFileId FileId { get; init; }
public required DateTimeOffset Uploaded { get; init; }
}
Expand Down Expand Up @@ -69,8 +84,19 @@ public async IAsyncEnumerable<NexusModsModFileParserResult> GetModuleInfosAsync(
httpStream.SetBufferSize(LargeBufferSize);
using var reader = ReaderExtensions.OpenOrDefault(httpStream, new ReaderOptions { LeaveStreamOpen = true });
if (reader is null) throw new InvalidOperationException($"Failed to get Reader for file '{fileInfo.FileName}'");
await foreach (var moduleInfo in GetModuleInfosFromReaderAsync(reader, subModuleCount).WithCancellation(ct))
yield return new() { ModuleInfo = moduleInfo, FileId = fileId, Uploaded = uploadedTimestamp };

var moduleInfosReader = await GetModuleInfosFromReaderAsync(reader, subModuleCount).ToListAsync(ct);
var dataReader = await GetGameVersionsFromReaderAsync(reader, moduleInfosReader).ToListAsync(ct);
foreach (var grouping in dataReader.GroupBy(x => new { x.Item1.Id, x.Item1.Version }))
{
yield return new()
{
ModuleInfo = grouping.Select(x => x.Item1).First(),
FileId = fileId,
Uploaded = uploadedTimestamp,
GameVersions = grouping.Select(x => GameVersion.From(x.Item3)).ToArray()
};
}
continue;
}

Expand All @@ -80,12 +106,22 @@ public async IAsyncEnumerable<NexusModsModFileParserResult> GetModuleInfosAsync(
if (archive.Type == ArchiveType.Rar)
httpStream.SetBufferSize(LargeBufferSize);

await foreach (var moduleInfo in GetModuleInfosFromArchiveAsync(archive, subModuleCount).WithCancellation(ct))
yield return new() { ModuleInfo = moduleInfo, FileId = fileId, Uploaded = uploadedTimestamp };
var moduleInfosArchive = await GetModuleInfosFromArchiveAsync(archive, subModuleCount).ToListAsync(ct);
var dataArchive = await GetGameVersionsFromArchiveAsync(archive, moduleInfosArchive).ToListAsync(ct);
foreach (var grouping in dataArchive.GroupBy(x => new { x.Item1.Id, x.Item1.Version }))
{
yield return new()
{
ModuleInfo = grouping.Select(x => x.Item1).First(),
FileId = fileId,
Uploaded = uploadedTimestamp,
GameVersions = grouping.Select(x => GameVersion.From(x.Item3)).ToArray()
};
}
}
}

private static async IAsyncEnumerable<ModuleInfoExtended> GetModuleInfosFromReaderAsync(IReader reader, int subModuleCount)
private static async IAsyncEnumerable<ModuleInfoExtendedWithPath> GetModuleInfosFromReaderAsync(IReader reader, int subModuleCount)
{
while (subModuleCount > 0 && reader.MoveToNextEntry())
{
Expand All @@ -96,16 +132,16 @@ private static async IAsyncEnumerable<ModuleInfoExtended> GetModuleInfosFromRead
await using var stream = reader.OpenEntryStream();
if (GetModuleInfo(stream) is not { } moduleInfo) continue;

yield return moduleInfo;
yield return new ModuleInfoExtendedWithPath(moduleInfo, reader.Entry.Key);
subModuleCount--;
}
}

private static async IAsyncEnumerable<ModuleInfoExtended> GetModuleInfosFromArchiveAsync(IArchive archive, int subModuleCount)
private static async IAsyncEnumerable<ModuleInfoExtendedWithPath> GetModuleInfosFromArchiveAsync(IArchive archive, int subModuleCount)
{
foreach (var entry in archive.Entries)
{
if (subModuleCount > 0) break;
if (subModuleCount <= 0) break;

if (entry.IsDirectory) continue;

Expand All @@ -114,11 +150,93 @@ private static async IAsyncEnumerable<ModuleInfoExtended> GetModuleInfosFromArch
await using var stream = entry.OpenEntryStream();
if (GetModuleInfo(stream) is not { } moduleInfo) continue;

yield return moduleInfo;
yield return new ModuleInfoExtendedWithPath(moduleInfo, entry.Key);
subModuleCount--;
}
}

private static async IAsyncEnumerable<(ModuleInfoExtendedWithPath, SubModuleInfoExtended, string)> GetGameVersionsFromReaderAsync(IReader reader, ICollection<ModuleInfoExtendedWithPath> moduleInfos)
{
// TODO:
foreach (var moduleInfo in moduleInfos)
{
yield return (moduleInfo, null!, string.Empty);
}
yield break;

var count = moduleInfos.SelectMany(x => x.SubModules).Select(x => x.DLLName).Count();

Check warning on line 167 in src/BUTR.Site.NexusMods.Server/Services/NexusModsModFileParser.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected
while (count > 0 && reader.MoveToNextEntry())
{
if (reader.Entry.IsDirectory) continue;

if (!reader.Entry.Key.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) continue;

foreach (var moduleInfo in moduleInfos)
{
var basePath = Path.GetDirectoryName(moduleInfo.Path);
if (string.IsNullOrEmpty(basePath)) continue;
if (!reader.Entry.Key.Contains(basePath)) continue;
foreach (var subModule in moduleInfo.SubModules)
{
if (!reader.Entry.Key.EndsWith(subModule.DLLName)) continue;

await using var stream = reader.OpenEntryStream();
var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var assembly = AssemblyDefinition.FromImage(PEImage.FromDataSource(new StreamDataSource(ms)));
foreach (var gameVersion in GetGameVersions(assembly))
yield return (moduleInfo, subModule, gameVersion);
count--;
}
}
}
}

private static async IAsyncEnumerable<(ModuleInfoExtendedWithPath, SubModuleInfoExtended, string)> GetGameVersionsFromArchiveAsync(IArchive archive, ICollection<ModuleInfoExtendedWithPath> moduleInfos)
{
// TODO:
foreach (var moduleInfo in moduleInfos)
{
yield return (moduleInfo, null!, string.Empty);
}
yield break;

var count = moduleInfos.SelectMany(x => x.SubModules).Select(x => x.DLLName).Count();

Check warning on line 204 in src/BUTR.Site.NexusMods.Server/Services/NexusModsModFileParser.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected
foreach (var entry in archive.Entries)
{
if (count <= 0) break;

if (entry.IsDirectory) continue;

if (!entry.Key.Contains(".dll", StringComparison.OrdinalIgnoreCase)) continue;

foreach (var moduleInfo in moduleInfos)
{
var basePath = Path.GetDirectoryName(moduleInfo.Path);
if (string.IsNullOrEmpty(basePath)) continue;
if (!entry.Key.Contains(basePath)) continue;
foreach (var subModule in moduleInfo.SubModules)
{
if (!entry.Key.EndsWith(subModule.DLLName)) continue;

await using var stream = entry.OpenEntryStream();
var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var assembly = AssemblyDefinition.FromImage(PEImage.FromDataSource(new StreamDataSource(ms)));
foreach (var gameVersion in GetGameVersions(assembly))
yield return (moduleInfo, subModule, gameVersion);
count--;
}
}
}
}

private static IEnumerable<string> GetGameVersions(AssemblyDefinition assemblyDefinition)
{
// TODO:
yield break;
}

private async Task<int> SubModuleXmlCountAsync(NexusModsModFilesResponse.File fileInfo)
{
static int ContainsSubModuleFile(IReadOnlyList<NexusModsModFileContentResponse.ContentEntry>? entries)
Expand Down

0 comments on commit bbb3c7e

Please sign in to comment.