response handlers fix

This commit is contained in:
Timerix 2025-03-20 19:57:29 +05:00
parent 60f24d6907
commit 0e122adcff
7 changed files with 73 additions and 47 deletions

1
.gitignore vendored
View File

@ -9,6 +9,7 @@
[Ll]og/
[Ll]ogs/
[Pp]ublish/
data/
# IDE files
.vs/

View File

@ -6,8 +6,4 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@ -4,9 +4,9 @@ namespace ParadoxSaveParser.WebAPI;
public static class PathHelper
{
public const string DATA_DIR = "data";
public static string SAVES_DIR = Path.Join(DATA_DIR, "saves");
public static string GetMetaFilePath(string save_id) => Path.Join(SAVES_DIR, save_id + ".meta.json");
public static string GetEU4SaveFilePath(string save_id) => Path.Join(SAVES_DIR, save_id + ".eu4");
public static string GetParsedSaveFilePath(string save_id) => Path.Join(SAVES_DIR, save_id + ".parsed.json");
}

View File

@ -1,13 +1,14 @@
global using System;
global using System.IO;
global using System.Text.Json;
global using System.Threading.Tasks;
global using DTLib.Demystifier;
global using ParadoxSaveParser.Lib;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Text.Json;
using DTLib.Demystifier;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using ParadoxSaveParser.Lib;
namespace ParadoxSaveParser.WebAPI;
@ -21,6 +22,8 @@ public class Program
var builder = WebApplication.CreateBuilder(args);
_app = builder.Build();
Directory.CreateDirectory(PathHelper.DATA_DIR);
Directory.CreateDirectory(PathHelper.SAVES_DIR);
foreach (var metaFilePath in Directory.GetFiles(PathHelper.SAVES_DIR, "*.meta.json", SearchOption.TopDirectoryOnly))
{
using var metaFile = File.Open(metaFilePath, FileMode.Open, FileAccess.Read);
@ -35,40 +38,53 @@ public class Program
}
_app.UseHttpsRedirection();
_app.MapPost("/parse/eu4", (HttpContext httpContext) =>
{
var remoteFile = httpContext.Request.Form.Files.FirstOrDefault();
if(remoteFile is null || !remoteFile.FileName.EndsWith(".eu4"))
throw new Exception($"Invalid file format: {remoteFile?.FileName}");
string saveId = Guid.NewGuid().ToString();
string metaFilePath = PathHelper.GetMetaFilePath(saveId);
if (File.Exists(metaFilePath))
{
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
throw new Exception($"Guid collision! file {metaFilePath} already exists.");
}
var meta = new SaveFileMetadata
{
id = saveId,
game = Game.EU4,
status = SaveFileProcessingStatus.Initialized,
};
if (!_saveMetadataStorage.TryAdd(saveId, meta))
{
throw new Exception($"Guid collision! Can't create metadata with id {saveId}");
}
BeginEU4SaveParse(remoteFile, meta);
return meta;
});
_app.MapGet("/getSaveStatus", GetSaveStatusHandler);
_app.MapPost("/parseSave/eu4", ParseSaveEU4Handler);
_app.Run();
}
private static async void BeginEU4SaveParse(IFormFile remoteFile, SaveFileMetadata meta)
private static async Task GetSaveStatusHandler(HttpContext httpContext)
{
httpContext.Request.Query.TryGetValue("id", out var ids);
string? id = ids.FirstOrDefault();
if (string.IsNullOrEmpty(id))
{
throw new BadHttpRequestException("No id provided",
StatusCodes.Status400BadRequest);
}
if (!_saveMetadataStorage.TryGetValue(id, out var meta))
{
throw new BadHttpRequestException($"Save with {id} not found",
StatusCodes.Status400BadRequest);
}
await httpContext.Response.WriteAsJsonAsync(meta);
}
private static async Task ParseSaveEU4Handler(HttpContext httpContext)
{
var remoteFile = httpContext.Request.Form.Files.FirstOrDefault();
if (remoteFile is null || !remoteFile.FileName.EndsWith(".eu4"))
{
throw new BadHttpRequestException($"Invalid file format: {remoteFile?.FileName}",
StatusCodes.Status400BadRequest);
}
string saveId = Guid.NewGuid().ToString();
string metaFilePath = PathHelper.GetMetaFilePath(saveId);
if (File.Exists(metaFilePath))
{
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
throw new BadHttpRequestException($"Guid collision! file {metaFilePath} already exists.", StatusCodes.Status500InternalServerError);
}
var meta = new SaveFileMetadata { id = saveId, game = Game.EU4, status = SaveFileProcessingStatus.Initialized, };
if (!_saveMetadataStorage.TryAdd(saveId, meta))
{
throw new BadHttpRequestException($"Guid collision! Can't create metadata with id {saveId}", StatusCodes.Status500InternalServerError);
}
try
{
meta.status = SaveFileProcessingStatus.Uploading;
@ -76,22 +92,29 @@ public class Program
await using var saveFile = File.Open(saveFilePath, FileMode.CreateNew, FileAccess.ReadWrite);
await using (var remoteStream = remoteFile.OpenReadStream())
{
await Task.Delay(50000);
await remoteStream.CopyToAsync(saveFile);
}
meta.status = SaveFileProcessingStatus.Parsing;
saveFile.Seek(0, SeekOrigin.Begin);
var parser = new ParserEU4(saveFile);
//var result = parser.Parse();
var result = parser.Parse();
meta.status = SaveFileProcessingStatus.SavingResults;
// save
string resultFilePath = PathHelper.GetParsedSaveFilePath(meta.id);
await using var resultFile = File.Open(resultFilePath, FileMode.CreateNew, FileAccess.Write);
await JsonSerializer.SerializeAsync(resultFile, result);
meta.status = SaveFileProcessingStatus.Done;
meta.SaveToFile();
}
catch (Exception ex)
{
meta.status = SaveFileProcessingStatus.Error;
string errorMesage = ex.ToStringDemystified();
meta.errorMesage = errorMesage;
_app.Logger.Log(LogLevel.Error, "EU4SaveParse Error: {errorMesage}", errorMesage);
}
await httpContext.Response.WriteAsJsonAsync(meta);
}
}

View File

@ -12,8 +12,6 @@
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "/",
"applicationUrl": "http://localhost:5226",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
@ -22,8 +20,6 @@
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "/",
"applicationUrl": "https://localhost:7032;http://localhost:5226",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
@ -31,8 +27,6 @@
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}

View File

@ -1,5 +1,6 @@
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ParadoxSaveParser.WebAPI;
@ -16,9 +17,15 @@ public enum Game
public class SaveFileMetadata
{
public required string id { get; init; }
[JsonConverter(typeof(JsonStringEnumConverter))]
public required Game game { get; init; }
[JsonConverter(typeof(JsonStringEnumConverter))]
public required SaveFileProcessingStatus status { get; set; }
[JsonIgnore]
public string? errorMesage { get; set; }
private static readonly JsonSerializerOptions _jsonOptions = new() { WriteIndented = true };

View File

@ -4,6 +4,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParadoxSaveParser.WebAPI",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParadoxSaveParser.Lib", "ParadoxSaveParser.Lib\ParadoxSaveParser.Lib.csproj", "{53ED0135-9513-4DE2-9187-CF2899F179B3}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionFolder", "SolutionFolder", "{F1D312F1-0620-4E35-8D78-9A2808CDE12C}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU