From 93acc778b213a21948d9da60ad01f423b42dec7b Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Mon, 16 Dec 2024 14:12:50 +0200 Subject: [PATCH] Added the ability to ingest files in WASM --- .../{ => Extensions}/TextExtensions.cs | 2 +- .../ZipArchiveEntryExtensions.cs | 2 +- .../Program.cs | 1 + .../Extensions/ZipArchiveEntryExtensions.cs | 18 ++++ .../Program.cs | 97 +++++++++++++++---- .../wwwroot/index.html | 6 +- .../wwwroot/js/init.js | 52 ++++++++-- .../wwwroot/js/main.js | 62 +++++++----- 8 files changed, 183 insertions(+), 57 deletions(-) rename src/BUTR.CrashReport.Renderer.ImGui.Tool/{ => Extensions}/TextExtensions.cs (93%) rename src/BUTR.CrashReport.Renderer.ImGui.Tool/{ => Extensions}/ZipArchiveEntryExtensions.cs (85%) create mode 100644 src/BUTR.CrashReport.Renderer.ImGui.WASM/Extensions/ZipArchiveEntryExtensions.cs diff --git a/src/BUTR.CrashReport.Renderer.ImGui.Tool/TextExtensions.cs b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/TextExtensions.cs similarity index 93% rename from src/BUTR.CrashReport.Renderer.ImGui.Tool/TextExtensions.cs rename to src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/TextExtensions.cs index 0431de1..38ae854 100644 --- a/src/BUTR.CrashReport.Renderer.ImGui.Tool/TextExtensions.cs +++ b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/TextExtensions.cs @@ -2,7 +2,7 @@ using System.IO; using System.Text; -namespace BUTR.CrashReport.Renderer.ImGui.Tool; +namespace BUTR.CrashReport.Renderer.ImGui.Tool.Extensions; internal static class TextExtensions { diff --git a/src/BUTR.CrashReport.Renderer.ImGui.Tool/ZipArchiveEntryExtensions.cs b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/ZipArchiveEntryExtensions.cs similarity index 85% rename from src/BUTR.CrashReport.Renderer.ImGui.Tool/ZipArchiveEntryExtensions.cs rename to src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/ZipArchiveEntryExtensions.cs index 99928f0..3ab115f 100644 --- a/src/BUTR.CrashReport.Renderer.ImGui.Tool/ZipArchiveEntryExtensions.cs +++ b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Extensions/ZipArchiveEntryExtensions.cs @@ -2,7 +2,7 @@ using System.IO; using System.IO.Compression; -namespace BUTR.CrashReport.Renderer.ImGui.Tool; +namespace BUTR.CrashReport.Renderer.ImGui.Tool.Extensions; public static class ZipArchiveEntryExtensions { diff --git a/src/BUTR.CrashReport.Renderer.ImGui.Tool/Program.cs b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Program.cs index ccf7403..d36b247 100644 --- a/src/BUTR.CrashReport.Renderer.ImGui.Tool/Program.cs +++ b/src/BUTR.CrashReport.Renderer.ImGui.Tool/Program.cs @@ -1,5 +1,6 @@ using BUTR.CrashReport.Models; using BUTR.CrashReport.Renderer.ImGui.Implementation.CImGui; +using BUTR.CrashReport.Renderer.ImGui.Tool.Extensions; using HtmlAgilityPack; diff --git a/src/BUTR.CrashReport.Renderer.ImGui.WASM/Extensions/ZipArchiveEntryExtensions.cs b/src/BUTR.CrashReport.Renderer.ImGui.WASM/Extensions/ZipArchiveEntryExtensions.cs new file mode 100644 index 0000000..37d10b5 --- /dev/null +++ b/src/BUTR.CrashReport.Renderer.ImGui.WASM/Extensions/ZipArchiveEntryExtensions.cs @@ -0,0 +1,18 @@ +using System.IO.Compression; + +namespace BUTR.CrashReport.Renderer.ImGui.WASM.Extensions; + +public static class ZipArchiveEntryExtensions +{ + public static Stream TryOpen(this ZipArchiveEntry? entry) + { + try + { + return entry?.Open() ?? Stream.Null; + } + catch (Exception) + { + return Stream.Null; + } + } +} \ No newline at end of file diff --git a/src/BUTR.CrashReport.Renderer.ImGui.WASM/Program.cs b/src/BUTR.CrashReport.Renderer.ImGui.WASM/Program.cs index 3d0c214..9aef440 100644 --- a/src/BUTR.CrashReport.Renderer.ImGui.WASM/Program.cs +++ b/src/BUTR.CrashReport.Renderer.ImGui.WASM/Program.cs @@ -3,6 +3,7 @@ using BUTR.CrashReport.Native; using BUTR.CrashReport.Renderer.ImGui.Renderer; using BUTR.CrashReport.Renderer.ImGui.WASM.Controller; +using BUTR.CrashReport.Renderer.ImGui.WASM.Extensions; using Emscripten; @@ -11,11 +12,13 @@ using OpenGLES3; +using System.IO.Compression; using System.Net.Http.Headers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.JavaScript; using System.Text.Json; +using System.Text.Json.Serialization.Metadata; [assembly: PInvokeDelegateLoader(typeof(CmGui), "cimgui")] @@ -27,6 +30,22 @@ namespace BUTR.CrashReport.Renderer.ImGui.WASM; public static partial class Program { + public enum ArgType + { + JsonLink, + JsonFile, + ZipFile, + } + + [JSImport("getArgType", "interop")] + private static partial string GetArgType(); + + [JSImport("getArgUrl", "interop")] + private static partial string GetArgUrl(); + + [JSImport("getArgData", "interop")] + private static partial byte[] GetArgData(); + [JSImport("finishedLoading", "interop")] private static partial void FinishedLoading(); @@ -39,13 +58,50 @@ private static void SetDarkMode(bool isDarkMode) // https://localhost:7211/?arg=http%3A%2F%2Flocalhost%3A65530%2Fcrashreport.json internal static async Task Main(string[] args) { - var url = args.Length > 0 ? args[0] : throw new ArgumentException("URL to Crash Report JSON is required"); - var cr = await FetchAsync(url); + if (!Enum.TryParse(GetArgType(), out var argType)) + { + Console.WriteLine("Invalid argument type."); + return; + } _emscripten = CreateEmscripten(); _imgui = CreateCmGui(); - _renderer = CreateImGuiRenderer(cr, [], _imgui); + + switch (argType) + { + case ArgType.JsonLink: + { + var url = GetArgUrl(); + var cr = await FetchJsonAsync(url); + _renderer = CreateImGuiRenderer(cr, [], _imgui); + break; + } + case ArgType.JsonFile: + { + var jsonBlob = GetArgData(); + var cr = JsonSerializer.Deserialize(jsonBlob, CustomJsonSerializerContext.Default.CrashReportModel)!; + _renderer = CreateImGuiRenderer(cr, [], _imgui); + break; + } + case ArgType.ZipFile: + { + var zipBlob = new MemoryStream(GetArgData()); + using var archive = new ZipArchive(zipBlob, ZipArchiveMode.Read, false); + + await using var jsonStream = archive.GetEntry("crashreport.json").TryOpen(); + await using var logsStream = archive.GetEntry("logs.json").TryOpen(); + if (jsonStream == Stream.Null) return; + + var crashReport = await TryDeserializeAsync(jsonStream, CustomJsonSerializerContext.Default.CrashReportModel); + var logs = await TryDeserializeAsync(logsStream, CustomJsonSerializerContext.Default.LogSourceModelArray) ?? []; + + _renderer = CreateImGuiRenderer(crashReport!, logs, _imgui); + break; + } + default: + throw new ArgumentOutOfRangeException(); + } _window = CreateWindow("BUTR Crash Report Renderer"u8, 800, 600); _gl = CreateGL(_window); @@ -56,24 +112,25 @@ internal static async Task Main(string[] args) SetMainLoop(); } - //private static readonly HttpRequestOptionsKey> FetchRequestOptionsKey = new("WebAssemblyFetchOptions"); - private static async Task FetchAsync(string url) + private static async Task TryDeserializeAsync(Stream stream, JsonTypeInfo typeInfo) + { + try + { + return await JsonSerializer.DeserializeAsync(stream, typeInfo); + } + catch (JsonException) + { + return default; + } + } + + private static async Task FetchJsonAsync(string url) { using var client = new HttpClient(); using var request = new HttpRequestMessage(HttpMethod.Get, url); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - /* - if (!request.Options.TryGetValue(FetchRequestOptionsKey, out var fetchOptions)) - { - fetchOptions = new Dictionary(StringComparer.Ordinal); - request.Options.Set(FetchRequestOptionsKey, fetchOptions); - } - - fetchOptions["mode"] = "no-cors"; - */ - using var response = await client.SendAsync(request); return JsonSerializer.Deserialize(await response.Content.ReadAsStreamAsync(), CustomJsonSerializerContext.Default.CrashReportModel)!; @@ -84,12 +141,12 @@ private static unsafe void SetMainLoop() _emscripten.emscripten_set_main_loop(&MainLoop, 0, 0); } - private static Emscripten.Emscripten _emscripten = default!; - private static CmGui _imgui = default!; - private static ImGuiController _controller = default!; - private static ImGuiRenderer _renderer = default!; + private static Emscripten.Emscripten _emscripten = null!; + private static CmGui _imgui = null!; + private static ImGuiController _controller = null!; + private static ImGuiRenderer _renderer = null!; private static IntPtr _window = default!; - private static GL _gl = default!; + private static GL _gl = null!; [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] private static void MainLoop() diff --git a/src/BUTR.CrashReport.Renderer.ImGui.WASM/wwwroot/index.html b/src/BUTR.CrashReport.Renderer.ImGui.WASM/wwwroot/index.html index c4b07ee..4a28c56 100644 --- a/src/BUTR.CrashReport.Renderer.ImGui.WASM/wwwroot/index.html +++ b/src/BUTR.CrashReport.Renderer.ImGui.WASM/wwwroot/index.html @@ -13,9 +13,13 @@ -
+