diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index 7f841ee..9d6ea5a 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -67,13 +67,15 @@ namespace Bloxstrap e.Handled = true; Logger.WriteLine("App::GlobalExceptionHandler", "An exception occurred"); - Logger.WriteLine("App::GlobalExceptionHandler", $"{e.Exception}"); FinalizeExceptionHandling(e.Exception); } - void FinalizeExceptionHandling(Exception exception) + public static void FinalizeExceptionHandling(Exception exception, bool log = true) { + if (log) + Logger.WriteException("App::FinalizeExceptionHandling", exception); + #if DEBUG throw exception; #else @@ -306,7 +308,7 @@ namespace Bloxstrap if (t.Exception is null) return; - Logger.WriteLine(LOG_IDENT, $"{t.Exception}"); + Logger.WriteException(LOG_IDENT, t.Exception); Exception exception = t.Exception; @@ -315,7 +317,7 @@ namespace Bloxstrap exception = t.Exception.InnerException!; #endif - FinalizeExceptionHandling(exception); + FinalizeExceptionHandling(exception, false); }); // this ordering is very important as all wpf windows are shown as modal dialogs, mess it up and you'll end up blocking input to one of them diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index b19ff90..aeb2f10 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -787,7 +787,7 @@ namespace Bloxstrap // extract the package immediately after download asynchronously // discard is just used to suppress the warning - Task _ = ExtractPackage(package); + _ = ExtractPackage(package); } if (_cancelFired) @@ -808,6 +808,7 @@ namespace Bloxstrap await Task.Delay(100); } + App.Logger.WriteLine(LOG_IDENT, "Writing AppSettings.xml..."); string appSettingsLocation = Path.Combine(_versionFolder, "AppSettings.xml"); await File.WriteAllTextAsync(appSettingsLocation, AppSettings); @@ -1220,7 +1221,7 @@ namespace Bloxstrap { FileInfo file = new(packageLocation); - string calculatedMD5 = Utility.MD5Hash.FromFile(packageLocation); + string calculatedMD5 = MD5Hash.FromFile(packageLocation); if (calculatedMD5 != package.Signature) { @@ -1292,37 +1293,34 @@ namespace Bloxstrap string packageLocation = Path.Combine(Paths.Downloads, package.Signature); string packageFolder = Path.Combine(_versionFolder, PackageDirectories[package.Name]); - string extractPath; App.Logger.WriteLine(LOG_IDENT, $"Extracting {package.Name} to {packageFolder}..."); - using ZipArchive archive = await Task.Run(() => ZipFile.OpenRead(packageLocation)); + var readTask = new Task(() => ZipFile.OpenRead(packageLocation)); + _ = readTask.ContinueWith(AsyncHelpers.ExceptionHandler, $"reading {package.Name}"); + readTask.Start(); - foreach (ZipArchiveEntry entry in archive.Entries) + using ZipArchive archive = await readTask.WaitAsync(TimeSpan.FromSeconds(30)); + + // yeah so because roblox is roblox, these packages aren't actually valid zip files + // besides the fact that they use backslashes instead of forward slashes for directories, + // empty folders that *BEGIN* with a backslash in their fullname, but have an empty name are listed here for some reason... + + foreach (var entry in archive.Entries) { if (_cancelFired) return; - if (entry.FullName.EndsWith('\\')) + if (String.IsNullOrEmpty(entry.Name)) continue; - extractPath = Path.Combine(packageFolder, entry.FullName); - - //App.Logger.WriteLine("{package.Name}", $"Writing {extractPath}..."); - + string extractPath = Path.Combine(packageFolder, entry.FullName); string? directory = Path.GetDirectoryName(extractPath); - if (directory is null) - continue; + if (directory is not null) + Directory.CreateDirectory(directory); - Directory.CreateDirectory(directory); - - using var fileStream = new FileStream(extractPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize: 0x1000, useAsync: true); - using var dataStream = entry.Open(); - - await dataStream.CopyToAsync(fileStream); - - File.SetLastWriteTime(extractPath, entry.LastWriteTime.DateTime); + entry.ExtractToFile(extractPath, true); } App.Logger.WriteLine(LOG_IDENT, $"Finished extracting {package.Name}"); diff --git a/Bloxstrap/Utility/AsyncHelpers.cs b/Bloxstrap/Utility/AsyncHelpers.cs new file mode 100644 index 0000000..d6a53f8 --- /dev/null +++ b/Bloxstrap/Utility/AsyncHelpers.cs @@ -0,0 +1,20 @@ +namespace Bloxstrap.Utility +{ + public static class AsyncHelpers + { + public static void ExceptionHandler(Task task, object? state) + { + const string LOG_IDENT = "AsyncHelpers::ExceptionHandler"; + + if (task.Exception is null) + return; + + if (state is null) + App.Logger.WriteLine(LOG_IDENT, "An exception occurred while running the task"); + else + App.Logger.WriteLine(LOG_IDENT, $"An exception occurred while running the task '{state}'"); + + App.FinalizeExceptionHandling(task.Exception); + } + } +}