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);
|