summary refs log tree commit diff
path: root/ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs143
1 files changed, 112 insertions, 31 deletions
diff --git a/ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs b/ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs

index 4aeab96..42d9d51 100644 --- a/ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs +++ b/ReferenceClientProxyImplementation/Tasks/Startup/InitClientStoreTask.cs
@@ -1,40 +1,97 @@ using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; +using AngleSharp.Html.Parser; using ArcaneLibs.Extensions; using ReferenceClientProxyImplementation.Configuration; +using ReferenceClientProxyImplementation.Services; namespace ReferenceClientProxyImplementation.Tasks.Startup; -public partial class InitClientStoreService(ProxyConfiguration proxyConfig) : ITask { +public partial class InitClientStoreService(ProxyConfiguration proxyConfig, ClientStoreService clientStore) : ITask +{ public int GetOrder() => 0; public string GetName() => "Get client revision"; - public async Task Execute() { - switch (proxyConfig.TestClient.Revision) { + public async Task Execute() + { + switch (proxyConfig.TestClient.Revision) + { case "canary": proxyConfig.TestClient.RevisionBaseUrl = "https://canary.discord.com"; - proxyConfig.TestClient.RevisionPath = await GetRevisionPathFromUrl("canary", "https://canary.discord.com/app"); + proxyConfig.TestClient.RevisionPath = + await GetRevisionPathFromUrl("canary", "https://canary.discord.com/app"); break; case "ptb": proxyConfig.TestClient.RevisionBaseUrl = "https://ptb.discord.com"; - proxyConfig.TestClient.RevisionPath = await GetRevisionPathFromUrl("ptb", "https://ptb.discord.com/app"); + proxyConfig.TestClient.RevisionPath = + await GetRevisionPathFromUrl("ptb", "https://ptb.discord.com/app"); break; case "stable": proxyConfig.TestClient.RevisionBaseUrl = "https://discord.com"; proxyConfig.TestClient.RevisionPath = await GetRevisionPathFromUrl("stable", "https://discord.com/app"); break; default: - if (proxyConfig.TestClient.RevisionPath == null) { + if (proxyConfig.TestClient.RevisionPath == null) + { throw new Exception("Test client revision path is not set!"); } break; } + + var hp = new HtmlParser(); + { + Console.WriteLine("Parsing app.html content"); + var appDocument = hp.ParseDocument(await clientStore.GetPatchedClientAsset("app.html")); + Console.WriteLine("Parsed app.html content"); + if (appDocument.Head is null) Console.WriteLine("No head element???"); + else if (appDocument.Head.Children.Length == 0) Console.WriteLine("Head element has no children????"); + else Console.WriteLine($"Checking {appDocument.Head.Children.Length} children...."); + List<string> toDownload = []; + foreach (var child in appDocument.Head.Children) + { + if (child.TagName.ToLower() == "link" && child.GetAttribute("rel") == "stylesheet") + { + var name = child.GetAttribute("href"); + Console.WriteLine($"Found stylesheet {name} in app.html"); + toDownload.Add(name!); + } + else if (child.TagName.ToLower() == "link" && child.GetAttribute("rel") == "preload" && + child.GetAttribute("as") == "script") + { + var name = child.GetAttribute("href"); + Console.WriteLine($"Found preload script {name} in app.html"); + toDownload.Add(name!); + } + else if (child.TagName.ToLower() == "script" && child.HasAttribute("defer")) + { + var name = child.GetAttribute("src"); + Console.WriteLine($"Found deferred script {name} in app.html"); + toDownload.Add(name!); + } + else + { + Console.WriteLine($"wtf is a {child.TagName} ({child.OuterHtml})"); + } + } + + var patchSem = new SemaphoreSlim(8, 8); + var tasks = toDownload.Distinct().Select(async x => + { + await clientStore.GetOrDownloadRawAsset(x); + await patchSem.WaitAsync(); + var res = await clientStore.GetPatchedClientAsset(x); + await res.DisposeAsync(); + patchSem.Release(); + }).ToList(); + await Task.WhenAll(tasks); + } } - private async Task<string> GetRevisionPathFromUrl(string rev, string url) { + private async Task<string> GetRevisionPathFromUrl(string rev, string url) + { using var hc = new HttpClient(); using var response = await hc.GetAsync(url); var content = await response.Content.ReadAsStringAsync(); @@ -42,16 +99,23 @@ public partial class InitClientStoreService(ProxyConfiguration proxyConfig) : IT var hash = System.Security.Cryptography.SHA256.HashData(Encoding.UTF8.GetBytes(normalisedContent)); var knownHashes = await GetKnownRevisionHashes("src/app.html"); var currentRevisionFilePath = Path.Combine(proxyConfig.AssetCache.DiskCacheBaseDirectory, "currentRevision"); - var previousRevision = Path.Exists(currentRevisionFilePath) ? await File.ReadAllTextAsync(currentRevisionFilePath) : ""; + var previousRevision = Path.Exists(currentRevisionFilePath) + ? await File.ReadAllTextAsync(currentRevisionFilePath) + : ""; var revisionName = rev; - if (knownHashes.Any(x => x.Value.SequenceEqual(hash))) { - Console.WriteLine($"[InitClientStoreTask] Found known revision '{rev}' with hash {hash.AsHexString().Replace(" ", "")}!"); + if (knownHashes.Any(x => x.Value.SequenceEqual(hash))) + { + Console.WriteLine( + $"[InitClientStoreTask] Found known revision '{rev}' with hash {hash.AsHexString().Replace(" ", "")}!"); revisionName = knownHashes.First(x => x.Value.SequenceEqual(hash)).Key; } - else { - Console.WriteLine($"[InitClientStoreTask] No known revision found for hash {hash.AsHexString().Replace(" ", "")}, creating new revision directory!"); - if (response.Headers.Contains("X-Build-Id")) { + else + { + Console.WriteLine( + $"[InitClientStoreTask] No known revision found for hash {hash.AsHexString().Replace(" ", "")}, creating new revision directory!"); + if (response.Headers.Contains("X-Build-Id")) + { revisionName = "buildId_" + response.Headers.GetValues("X-Build-Id").FirstOrDefault(); Console.WriteLine("[InitClientStoreTask] Using build ID from X-Build-Id header: " + revisionName); } @@ -61,44 +125,57 @@ public partial class InitClientStoreService(ProxyConfiguration proxyConfig) : IT Console.WriteLine($"[InitClientStoreTask] Saving revision '{revisionName}' to {revisionPath}..."); PrepareRevisionDirectory(revisionPath); await File.WriteAllTextAsync(Path.Combine(revisionPath, "src", "app.html"), content); - await File.WriteAllTextAsync(Path.Combine(proxyConfig.AssetCache.DiskCacheBaseDirectory, "currentRevision"), revisionName); + await File.WriteAllTextAsync(Path.Combine(proxyConfig.AssetCache.DiskCacheBaseDirectory, "currentRevision"), + revisionName); //also download dev page using var devResponse = await hc.GetAsync(url.Replace("/app", "/developers/applications")); var devContent = await devResponse.Content.ReadAsStringAsync(); await File.WriteAllTextAsync(Path.Combine(revisionPath, "src", "developers.html"), devContent); - + //...and popout using var popoutResponse = await hc.GetAsync(url.Replace("/app", "/popout")); var popoutContent = await popoutResponse.Content.ReadAsStringAsync(); await File.WriteAllTextAsync(Path.Combine(revisionPath, "src", "popout.html"), popoutContent); - - if (proxyConfig.AssetCache.DitchPatchedOnStartup) { + + if (proxyConfig.AssetCache.DitchPatchedOnStartup) + { Directory.Delete(Path.Combine(revisionPath, "patched"), true); Directory.CreateDirectory(Path.Combine(revisionPath, "patched")); } - if (previousRevision != revisionName || true) { - foreach (var argv in proxyConfig.AssetCache.ExecOnRevisionChange) { - try { - var psi = new ProcessStartInfo(argv[0], argv[1..].Select(a => a.Replace("{revisionPath}", revisionPath))) { + if (previousRevision != revisionName || true) + { + foreach (var argv in proxyConfig.AssetCache.ExecOnRevisionChange) + { + try + { + var psi = new ProcessStartInfo(argv[0], + argv[1..].Select(a => a.Replace("{revisionPath}", revisionPath))) + { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(psi); - if (process != null) { + if (process != null) + { _ = process.StandardOutput.ReadToEndAsync(); _ = process.StandardError.ReadToEndAsync(); - Console.WriteLine($"[InitClientStoreTask] Executing post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}"); + Console.WriteLine( + $"[InitClientStoreTask] Executing post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}"); } - else { - Console.WriteLine($"[InitClientStoreTask] Failed to start post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}"); + else + { + Console.WriteLine( + $"[InitClientStoreTask] Failed to start post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}"); } } - catch (Exception e) { - Console.WriteLine($"[InitClientStoreTask] Failed to start post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}\n{e}"); + catch (Exception e) + { + Console.WriteLine( + $"[InitClientStoreTask] Failed to start post-revision change command: {argv[0]} {string.Join(" ", argv[1..])}\n{e}"); } } } @@ -106,14 +183,16 @@ public partial class InitClientStoreService(ProxyConfiguration proxyConfig) : IT return revisionPath; } - private static void PrepareRevisionDirectory(string revisionPath, bool dropPatched = false) { + private static void PrepareRevisionDirectory(string revisionPath, bool dropPatched = false) + { Directory.CreateDirectory(revisionPath); Directory.CreateDirectory(Path.Combine(revisionPath, "src")); Directory.CreateDirectory(Path.Combine(revisionPath, "formatted")); Directory.CreateDirectory(Path.Combine(revisionPath, "patched")); } - private async Task<Dictionary<string, byte[]>> GetKnownRevisionHashes(string file) { + private async Task<Dictionary<string, byte[]>> GetKnownRevisionHashes(string file) + { if (!Directory.Exists(proxyConfig.AssetCache.DiskCacheBaseDirectory)) Directory.CreateDirectory(proxyConfig.AssetCache.DiskCacheBaseDirectory); @@ -130,9 +209,11 @@ public partial class InitClientStoreService(ProxyConfiguration proxyConfig) : IT ); } - private async Task<(string RevisionId, byte[] Hash)?> GetKnownRevisionHash(string dir, string file) { + private async Task<(string RevisionId, byte[] Hash)?> GetKnownRevisionHash(string dir, string file) + { var hashFile = Path.Combine(dir, file); - if (File.Exists(hashFile)) { + if (File.Exists(hashFile)) + { var content = StripNonces(await File.ReadAllTextAsync(hashFile)); var hash = System.Security.Cryptography.SHA256.HashData(Encoding.UTF8.GetBytes(content)); var result = (new DirectoryInfo(dir).Name, hash);