From 8ee54bb8df134513dfba753e6134dc1b4c047af5 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sun, 3 May 2026 22:08:48 +0200 Subject: [PATCH] fix(http): close socket leaks in EmoteCache and FontManager - EmoteCache.cs replaces the per-call "new HttpClient()" with the existing static Client field. The static instance already exists for two other endpoints in the same file and reuses connection pooling; the third call site was a stray that leaked a socket on every emote download - FontManager.cs wraps both the HttpClient and the HttpResponseMessage in using-blocks, replaces the .Result/AggregateException sandwich with GetAwaiter().GetResult() for clean exception propagation, and adds EnsureSuccessStatusCode so failed downloads don't silently produce a zero-byte font file. Full async refactor of the FontManager constructor is tracked separately --- HellionChat/EmoteCache.cs | 2 +- HellionChat/FontManager.cs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/HellionChat/EmoteCache.cs b/HellionChat/EmoteCache.cs index c400086..f2c818c 100644 --- a/HellionChat/EmoteCache.cs +++ b/HellionChat/EmoteCache.cs @@ -192,7 +192,7 @@ public static class EmoteCache } else { - var content = await new HttpClient().GetAsync(EmotePath.Format(emote.Id)); + var content = await Client.GetAsync(EmotePath.Format(emote.Id)); RawData = await content.Content.ReadAsByteArrayAsync(); await using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); diff --git a/HellionChat/FontManager.cs b/HellionChat/FontManager.cs index dd06005..df83ef0 100644 --- a/HellionChat/FontManager.cs +++ b/HellionChat/FontManager.cs @@ -39,11 +39,18 @@ public class FontManager } else { - GameSymFont = new HttpClient().GetAsync("https://img.finalfantasyxiv.com/lds/pc/global/fonts/FFXIV_Lodestone_SSF.ttf") - .Result - .Content - .ReadAsByteArrayAsync() - .Result; + // Dispose HttpClient and HttpResponseMessage to avoid socket + // exhaustion on repeated cold-start downloads. GetAwaiter().GetResult() + // unwraps AggregateException so failures surface cleanly. A full + // async refactor of the constructor would be cleaner but is out of + // scope for v1.0.0 — tracked in the backlog. + using var client = new HttpClient(); + using var response = client + .GetAsync("https://img.finalfantasyxiv.com/lds/pc/global/fonts/FFXIV_Lodestone_SSF.ttf") + .GetAwaiter() + .GetResult(); + response.EnsureSuccessStatusCode(); + GameSymFont = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); Dalamud.Utility.FilesystemUtil.WriteAllBytesSafe(filePath, GameSymFont); }