From 170c6e588491c876e364fe376dff92e05cd360f8 Mon Sep 17 00:00:00 2001
From: pizzaboxer <41478239+pizzaboxer@users.noreply.github.com>
Date: Mon, 14 Nov 2022 18:24:50 +0000
Subject: [PATCH] HttpClient - Use singleton and enable gzip
Rework of #45 as it kept crashing on release
---
Bloxstrap/Bootstrapper.cs | 8 +-
Bloxstrap/Dialogs/Preferences.xaml | 2 +-
Bloxstrap/Helpers/DeployManager.cs | 31 +-
.../Helpers/Integrations/RbxFpsUnlocker.cs | 13 +-
Bloxstrap/Helpers/RSMM/PackageManifest.cs | 7 +-
Bloxstrap/Helpers/ReverseLineReader.cs | 288 ------------------
Bloxstrap/Helpers/Updater.cs | 2 +-
Bloxstrap/Helpers/Utilities.cs | 9 +-
Bloxstrap/Program.cs | 6 +
9 files changed, 34 insertions(+), 332 deletions(-)
delete mode 100644 Bloxstrap/Helpers/ReverseLineReader.cs
diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs
index 96c3798..5db507b 100644
--- a/Bloxstrap/Bootstrapper.cs
+++ b/Bloxstrap/Bootstrapper.cs
@@ -10,6 +10,7 @@ using Bloxstrap.Dialogs.BootstrapperDialogs;
using Bloxstrap.Helpers;
using Bloxstrap.Helpers.Integrations;
using Bloxstrap.Helpers.RSMM;
+using System.Net;
namespace Bloxstrap
{
@@ -66,8 +67,6 @@ namespace Bloxstrap
"By default, two mod presets are provided for restoring the old death\n" +
"sound and the old mouse cursor.\n";
- private static readonly HttpClient Client = new();
-
private string? LaunchCommandLine;
private string VersionGuid = null!;
@@ -87,7 +86,6 @@ namespace Bloxstrap
{
LaunchCommandLine = launchCommandLine;
FreshInstall = String.IsNullOrEmpty(Program.Settings.VersionGuid);
- Client.Timeout = TimeSpan.FromMinutes(10);
}
// this is called from BootstrapperStyleForm.SetupDialog()
@@ -133,7 +131,7 @@ namespace Bloxstrap
{
Dialog.Message = "Connecting to Roblox...";
- VersionGuid = await Client.GetStringAsync($"{DeployManager.BaseUrl}/version");
+ VersionGuid = await Program.HttpClient.GetStringAsync($"{DeployManager.BaseUrl}/version");
VersionFolder = Path.Combine(Directories.Versions, VersionGuid);
VersionPackageManifest = await PackageManifest.Get(VersionGuid);
}
@@ -611,7 +609,7 @@ namespace Bloxstrap
{
Debug.WriteLine($"Downloading {package.Name}...");
- var response = await Client.GetAsync(packageUrl);
+ var response = await Program.HttpClient.GetAsync(packageUrl);
if (CancelFired)
return;
diff --git a/Bloxstrap/Dialogs/Preferences.xaml b/Bloxstrap/Dialogs/Preferences.xaml
index 09fdf82..c10019a 100644
--- a/Bloxstrap/Dialogs/Preferences.xaml
+++ b/Bloxstrap/Dialogs/Preferences.xaml
@@ -34,7 +34,7 @@
-
+
diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs
index d794dbd..aa5241f 100644
--- a/Bloxstrap/Helpers/DeployManager.cs
+++ b/Bloxstrap/Helpers/DeployManager.cs
@@ -104,19 +104,16 @@ namespace Bloxstrap.Helpers
string baseUrl = BuildBaseUrl(channel);
string lastDeploy = "";
- using (HttpClient client = new())
+ string deployHistory = await Program.HttpClient.GetStringAsync($"{baseUrl}/DeployHistory.txt");
+
+ using (StringReader reader = new(deployHistory))
{
- string deployHistory = await client.GetStringAsync($"{baseUrl}/DeployHistory.txt");
+ string? line;
- using (StringReader reader = new(deployHistory))
+ while ((line = await reader.ReadLineAsync()) is not null)
{
- string? line;
-
- while ((line = await reader.ReadLineAsync()) is not null)
- {
- if (line.Contains("WindowsPlayer"))
- lastDeploy = line;
- }
+ if (line.Contains("WindowsPlayer"))
+ lastDeploy = line;
}
}
@@ -132,10 +129,10 @@ namespace Bloxstrap.Helpers
lastDeploy = lastDeploy[18..]; // 'version-29fb7cdd06e84001 at 8/23/2022 2:07:27 PM, file version: 0, 542, 100, 5420251, git hash: b98d6b2bea36fa2161f48cca979fb620bb0c24fd ...'
string versionGuid = lastDeploy[..lastDeploy.IndexOf(" at")]; // 'version-29fb7cdd06e84001'
-
+
lastDeploy = lastDeploy[(versionGuid.Length + 4)..]; // '8/23/2022 2:07:27 PM, file version: 0, 542, 100, 5420251, git hash: b98d6b2bea36fa2161f48cca979fb620bb0c24fd ...'
string strTimestamp = lastDeploy[..lastDeploy.IndexOf(", file")]; // '8/23/2022 2:07:27 PM'
-
+
lastDeploy = lastDeploy[(strTimestamp.Length + 16)..]; // '0, 542, 100, 5420251, git hash: b98d6b2bea36fa2161f48cca979fb620bb0c24fd ...'
string fileVersion = "";
@@ -157,11 +154,11 @@ namespace Bloxstrap.Helpers
// convert to traditional version format
fileVersion = fileVersion.Replace(" ", "").Replace(',', '.');
- return new VersionDeploy
- {
- VersionGuid = versionGuid,
- Timestamp = dtTimestamp,
- FileVersion = fileVersion
+ return new VersionDeploy
+ {
+ VersionGuid = versionGuid,
+ Timestamp = dtTimestamp,
+ FileVersion = fileVersion
};
}
}
diff --git a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
index 2507dd5..2be5620 100644
--- a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
+++ b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
@@ -91,15 +91,12 @@ namespace Bloxstrap.Helpers.Integrations
Debug.WriteLine("Installing/Updating rbxfpsunlocker...");
- using (HttpClient client = new())
- {
- byte[] bytes = await client.GetByteArrayAsync(downloadUrl);
+ byte[] bytes = await Program.HttpClient.GetByteArrayAsync(downloadUrl);
- using (MemoryStream zipStream = new(bytes))
- {
- ZipArchive zip = new(zipStream);
- zip.ExtractToDirectory(folderLocation, true);
- }
+ using (MemoryStream zipStream = new(bytes))
+ {
+ ZipArchive zip = new(zipStream);
+ zip.ExtractToDirectory(folderLocation, true);
}
if (!File.Exists(settingsLocation))
diff --git a/Bloxstrap/Helpers/RSMM/PackageManifest.cs b/Bloxstrap/Helpers/RSMM/PackageManifest.cs
index bacfabd..4404809 100644
--- a/Bloxstrap/Helpers/RSMM/PackageManifest.cs
+++ b/Bloxstrap/Helpers/RSMM/PackageManifest.cs
@@ -75,11 +75,8 @@ namespace Bloxstrap.Helpers.RSMM
string pkgManifestUrl = $"{DeployManager.BaseUrl}/{versionGuid}-rbxPkgManifest.txt";
string pkgManifestData;
- using (HttpClient http = new())
- {
- var getData = http.GetStringAsync(pkgManifestUrl);
- pkgManifestData = await getData.ConfigureAwait(false);
- }
+ var getData = Program.HttpClient.GetStringAsync(pkgManifestUrl);
+ pkgManifestData = await getData.ConfigureAwait(false);
return new PackageManifest(pkgManifestData);
}
diff --git a/Bloxstrap/Helpers/ReverseLineReader.cs b/Bloxstrap/Helpers/ReverseLineReader.cs
deleted file mode 100644
index 864e2c0..0000000
--- a/Bloxstrap/Helpers/ReverseLineReader.cs
+++ /dev/null
@@ -1,288 +0,0 @@
-using System.Collections;
-using System.IO;
-using System.Text;
-
-// taken from MiscUtil: https://github.com/loory/MiscUtil
-// the proper usage of MiscUtil nowadays is to *not* use the library and rather copy the code you need so lol
-
-namespace Bloxstrap.Helpers
-{
- ///
- /// Takes an encoding (defaulting to UTF-8) and a function which produces a seekable stream
- /// (or a filename for convenience) and yields lines from the end of the stream backwards.
- /// Only single byte encodings, and UTF-8 and Unicode, are supported. The stream
- /// returned by the function must be seekable.
- ///
- public sealed class ReverseLineReader : IEnumerable
- {
- ///
- /// Buffer size to use by default. Classes with internal access can specify
- /// a different buffer size - this is useful for testing.
- ///
- private const int DefaultBufferSize = 4096;
-
- ///
- /// Means of creating a Stream to read from.
- ///
- private readonly Func streamSource;
-
- ///
- /// Encoding to use when converting bytes to text
- ///
- private readonly Encoding encoding;
-
- ///
- /// Size of buffer (in bytes) to read each time we read from the
- /// stream. This must be at least as big as the maximum number of
- /// bytes for a single character.
- ///
- private readonly int bufferSize;
-
- ///
- /// Function which, when given a position within a file and a byte, states whether
- /// or not the byte represents the start of a character.
- ///
- private Func characterStartDetector;
-
- ///
- /// Creates a LineReader from a stream source. The delegate is only
- /// called when the enumerator is fetched. UTF-8 is used to decode
- /// the stream into text.
- ///
- /// Data source
- public ReverseLineReader(Func streamSource)
- : this(streamSource, Encoding.UTF8)
- {
- }
-
- ///
- /// Creates a LineReader from a filename. The file is only opened
- /// (or even checked for existence) when the enumerator is fetched.
- /// UTF8 is used to decode the file into text.
- ///
- /// File to read from
- public ReverseLineReader(string filename)
- : this(filename, Encoding.UTF8)
- {
- }
-
- ///
- /// Creates a LineReader from a filename. The file is only opened
- /// (or even checked for existence) when the enumerator is fetched.
- ///
- /// File to read from
- /// Encoding to use to decode the file into text
- public ReverseLineReader(string filename, Encoding encoding)
- : this(() => File.OpenRead(filename), encoding)
- {
- }
-
- ///
- /// Creates a LineReader from a stream source. The delegate is only
- /// called when the enumerator is fetched.
- ///
- /// Data source
- /// Encoding to use to decode the stream into text
- public ReverseLineReader(Func streamSource, Encoding encoding)
- : this(streamSource, encoding, DefaultBufferSize)
- {
- }
-
- internal ReverseLineReader(Func streamSource, Encoding encoding, int bufferSize)
- {
- this.streamSource = streamSource;
- this.encoding = encoding;
- this.bufferSize = bufferSize;
- if (encoding.IsSingleByte)
- {
- // For a single byte encoding, every byte is the start (and end) of a character
- characterStartDetector = (pos, data) => true;
- }
- else if (encoding is UnicodeEncoding)
- {
- // For UTF-16, even-numbered positions are the start of a character.
- // TODO: This assumes no surrogate pairs. More work required
- // to handle that.
- characterStartDetector = (pos, data) => (pos & 1) == 0;
- }
- else if (encoding is UTF8Encoding)
- {
- // For UTF-8, bytes with the top bit clear or the second bit set are the start of a character
- // See http://www.cl.cam.ac.uk/~mgk25/unicode.html
- characterStartDetector = (pos, data) => (data & 0x80) == 0 || (data & 0x40) != 0;
- }
- else
- {
- throw new ArgumentException("Only single byte, UTF-8 and Unicode encodings are permitted");
- }
- }
-
- ///
- /// Returns the enumerator reading strings backwards. If this method discovers that
- /// the returned stream is either unreadable or unseekable, a NotSupportedException is thrown.
- ///
- public IEnumerator GetEnumerator()
- {
- Stream stream = streamSource();
- if (!stream.CanSeek)
- {
- stream.Dispose();
- throw new NotSupportedException("Unable to seek within stream");
- }
- if (!stream.CanRead)
- {
- stream.Dispose();
- throw new NotSupportedException("Unable to read within stream");
- }
- return GetEnumeratorImpl(stream);
- }
-
- private IEnumerator GetEnumeratorImpl(Stream stream)
- {
- try
- {
- long position = stream.Length;
-
- if (encoding is UnicodeEncoding && (position & 1) != 0)
- {
- throw new InvalidDataException("UTF-16 encoding provided, but stream has odd length.");
- }
-
- // Allow up to two bytes for data from the start of the previous
- // read which didn't quite make it as full characters
- byte[] buffer = new byte[bufferSize + 2];
- char[] charBuffer = new char[encoding.GetMaxCharCount(buffer.Length)];
- int leftOverData = 0;
- String? previousEnd = null;
- // TextReader doesn't return an empty string if there's line break at the end
- // of the data. Therefore we don't return an empty string if it's our *first*
- // return.
- bool firstYield = true;
-
- // A line-feed at the start of the previous buffer means we need to swallow
- // the carriage-return at the end of this buffer - hence this needs declaring
- // way up here!
- bool swallowCarriageReturn = false;
-
- while (position > 0)
- {
- int bytesToRead = Math.Min(position > int.MaxValue ? bufferSize : (int)position, bufferSize);
-
- position -= bytesToRead;
- stream.Position = position;
- StreamUtil.ReadExactly(stream, buffer, bytesToRead);
- // If we haven't read a full buffer, but we had bytes left
- // over from before, copy them to the end of the buffer
- if (leftOverData > 0 && bytesToRead != bufferSize)
- {
- // Buffer.BlockCopy doesn't document its behaviour with respect
- // to overlapping data: we *might* just have read 7 bytes instead of
- // 8, and have two bytes to copy...
- Array.Copy(buffer, bufferSize, buffer, bytesToRead, leftOverData);
- }
- // We've now *effectively* read this much data.
- bytesToRead += leftOverData;
-
- int firstCharPosition = 0;
- while (!characterStartDetector(position + firstCharPosition, buffer[firstCharPosition]))
- {
- firstCharPosition++;
- // Bad UTF-8 sequences could trigger this. For UTF-8 we should always
- // see a valid character start in every 3 bytes, and if this is the start of the file
- // so we've done a short read, we should have the character start
- // somewhere in the usable buffer.
- if (firstCharPosition == 3 || firstCharPosition == bytesToRead)
- {
- throw new InvalidDataException("Invalid UTF-8 data");
- }
- }
- leftOverData = firstCharPosition;
-
- int charsRead = encoding.GetChars(buffer, firstCharPosition, bytesToRead - firstCharPosition, charBuffer, 0);
- int endExclusive = charsRead;
-
- for (int i = charsRead - 1; i >= 0; i--)
- {
- char lookingAt = charBuffer[i];
- if (swallowCarriageReturn)
- {
- swallowCarriageReturn = false;
- if (lookingAt == '\r')
- {
- endExclusive--;
- continue;
- }
- }
- // Anything non-line-breaking, just keep looking backwards
- if (lookingAt != '\n' && lookingAt != '\r')
- {
- continue;
- }
- // End of CRLF? Swallow the preceding CR
- if (lookingAt == '\n')
- {
- swallowCarriageReturn = true;
- }
- int start = i + 1;
- string bufferContents = new string(charBuffer, start, endExclusive - start);
- endExclusive = i;
- string stringToYield = previousEnd == null ? bufferContents : bufferContents + previousEnd;
- if (!firstYield || stringToYield.Length != 0)
- {
- yield return stringToYield;
- }
- firstYield = false;
- previousEnd = null;
- }
-
- previousEnd = endExclusive == 0 ? null : (new string(charBuffer, 0, endExclusive) + previousEnd);
-
- // If we didn't decode the start of the array, put it at the end for next time
- if (leftOverData != 0)
- {
- Buffer.BlockCopy(buffer, 0, buffer, bufferSize, leftOverData);
- }
- }
- if (leftOverData != 0)
- {
- // At the start of the final buffer, we had the end of another character.
- throw new InvalidDataException("Invalid UTF-8 data at start of stream");
- }
- if (firstYield && string.IsNullOrEmpty(previousEnd))
- {
- yield break;
- }
- yield return previousEnd ?? "";
- }
- finally
- {
- stream.Dispose();
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- }
-
- public static class StreamUtil
- {
- public static void ReadExactly(Stream input, byte[] buffer, int bytesToRead)
- {
- int index = 0;
- while (index < bytesToRead)
- {
- int read = input.Read(buffer, index, bytesToRead - index);
- if (read == 0)
- {
- throw new EndOfStreamException
- (String.Format("End of stream reached with {0} byte{1} left to read.",
- bytesToRead - index,
- bytesToRead - index == 1 ? "s" : ""));
- }
- index += read;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Bloxstrap/Helpers/Updater.cs b/Bloxstrap/Helpers/Updater.cs
index 316a898..942376a 100644
--- a/Bloxstrap/Helpers/Updater.cs
+++ b/Bloxstrap/Helpers/Updater.cs
@@ -42,7 +42,7 @@ namespace Bloxstrap.Helpers
new Preferences().ShowDialog();
- Environment.Exit(0);
+ Program.Exit();
}
}
diff --git a/Bloxstrap/Helpers/Utilities.cs b/Bloxstrap/Helpers/Utilities.cs
index 22a60d4..a37d9ad 100644
--- a/Bloxstrap/Helpers/Utilities.cs
+++ b/Bloxstrap/Helpers/Utilities.cs
@@ -15,13 +15,8 @@ namespace Bloxstrap.Helpers
public static async Task GetJson(string url)
{
- using (HttpClient client = new())
- {
- client.DefaultRequestHeaders.Add("User-Agent", Program.ProjectRepository);
-
- string json = await client.GetStringAsync(url);
- return JsonSerializer.Deserialize(json);
- }
+ string json = await Program.HttpClient.GetStringAsync(url);
+ return JsonSerializer.Deserialize(json);
}
public static string MD5File(string filename)
diff --git a/Bloxstrap/Program.cs b/Bloxstrap/Program.cs
index fea6524..980fc82 100644
--- a/Bloxstrap/Program.cs
+++ b/Bloxstrap/Program.cs
@@ -8,6 +8,8 @@ using Bloxstrap.Enums;
using Bloxstrap.Helpers;
using Bloxstrap.Models;
using Bloxstrap.Dialogs;
+using System.Net.Http;
+using System.Net;
namespace Bloxstrap
{
@@ -34,6 +36,7 @@ namespace Bloxstrap
public static SettingsManager SettingsManager = new();
public static SettingsFormat Settings = SettingsManager.Settings;
+ public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All });
// shorthand
public static DialogResult ShowMessageBox(string message, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxButtons buttons = MessageBoxButtons.OK)
@@ -57,6 +60,9 @@ namespace Bloxstrap
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
+ HttpClient.Timeout = TimeSpan.FromMinutes(5);
+ HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository);
+
LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
StartMenu = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", ProjectName);