using Newtonsoft.Json; using RobloxLegacy.AppData; using RobloxLegacy.Utilities; using ICSharpCode.SharpZipLib.Zip; namespace RobloxLegacy; public class VersionData { [JsonProperty("version")] public required string Version { get; set; } [JsonProperty("clientVersionUpload")] public required string UploadHash { get; set; } } public class VersionManager : IDisposable { private static readonly HttpClient Client = new(); private const string CdnUrl = "https://setup.rbxcdn.com"; private readonly string _tempPath = Path.Combine(Path.GetTempPath(), $"RobloxLegacy.{Guid.NewGuid().ToString()}"); private readonly IAppData _appData; public VersionManager(IAppData appData) { Directory.CreateDirectory(_tempPath); _appData = appData; } private static string GetVersionPath(string version) { var localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); return Path.Combine(localAppDataPath, "Roblox", "Versions", version); } private async Task GetLatestVersion() { var url = $"https://clientsettings.roblox.com/v2/client-version/{_appData.Name}/channel/LIVE"; var response = await Client.GetAsync(url); if(!response.IsSuccessStatusCode) // just to be safe return null; var version = await response.Content.ReadAsAsync(); return version; } private static void ExtractBundle(string version, string folder, string tempFile) { var fastZip = new FastZip(); var extractPath = Path.Combine(GetVersionPath(version), folder); fastZip.ExtractZip(tempFile, extractPath, null); } public async Task InstallPackage() { var version = await GetLatestVersion(); if(version == null) throw new Exception("No version data found"); Logger.Info($"Installing {_appData.Name} version {version.Version}"); foreach (var file in _appData.PackageFiles) { try { var fileName = $"{version.UploadHash}-{file.Key}"; var fileBytes = await Client.GetByteArrayAsync($"{CdnUrl}/{fileName}"); var zipPath = Path.Combine(_tempPath, fileName); await File.WriteAllBytesAsync(zipPath, fileBytes); ExtractBundle(version.UploadHash, file.Value, zipPath); } catch (HttpRequestException) { Logger.Error($"Failed to download {file.Key}"); } } } public void Dispose() { Directory.Delete(_tempPath, true); GC.SuppressFinalize(this); } }