diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index abfb013..0a22e98 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -35,13 +35,14 @@ namespace Bloxstrap public static bool IsUninstall { get; private set; } = false; public static bool IsNoLaunch { get; private set; } = false; public static bool IsUpgrade { get; private set; } = false; + public static bool IsMenuLaunch { get; private set; } = false; public static string[] LaunchArgs { get; private set; } = null!; public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; // singletons - public static Logger Logger { get; private set; } = null!; + public static readonly Logger Logger = new(); public static readonly JsonManager Settings = new(); public static readonly JsonManager State = new(); public static readonly HttpClient HttpClient = new(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.All }); @@ -63,10 +64,22 @@ namespace Bloxstrap Environment.Exit(code); } + private void InitLog() + { + // if we're running for the first time or uninstalling, log to temp folder + // else, log to bloxstrap folder + + string logdir = IsFirstRun || IsUninstall ? Path.Combine(Directories.LocalAppData, "Temp") : Path.Combine(Directories.Base, "Logs"); + string timestamp = DateTime.UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'"); + Logger.Initialize(Path.Combine(logdir, $"{ProjectName}_{timestamp}.log")); + } + protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); + Logger.WriteLine($"[App::OnStartup] Starting {ProjectName} v{Version}"); + // To customize application configuration such as set high DPI settings or default font, // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); @@ -78,53 +91,74 @@ namespace Bloxstrap if (LaunchArgs.Length > 0) { + if (Array.IndexOf(LaunchArgs, "-preferences") != -1 || Array.IndexOf(LaunchArgs, "-menu") != -1) + { + Logger.WriteLine("[App::OnStartup] Started with IsMenuLaunch flag"); + IsMenuLaunch = true; + } + if (Array.IndexOf(LaunchArgs, "-quiet") != -1) + { + Logger.WriteLine("[App::OnStartup] Started with IsQuiet flag"); IsQuiet = true; + } if (Array.IndexOf(LaunchArgs, "-uninstall") != -1) + { + Logger.WriteLine("[App::OnStartup] Started with IsUninstall flag"); IsUninstall = true; + } if (Array.IndexOf(LaunchArgs, "-nolaunch") != -1) + { + Logger.WriteLine("[App::OnStartup] Started with IsNoLaunch flag"); IsNoLaunch = true; + } if (Array.IndexOf(LaunchArgs, "-upgrade") != -1) + { + Logger.WriteLine("[App::OnStartup] Bloxstrap started with IsUpgrade flag"); IsUpgrade = true; + } } // check if installed - RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}"); - - if (registryKey is null) + using (RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}")) { - BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); - - if (!IsQuiet) + if (registryKey is null) { - IsSetupComplete = false; - new MainWindow().ShowDialog(); + Logger.WriteLine("[App::OnStartup] Running first-time install"); + + BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); + InitLog(); + + if (!IsQuiet) + { + IsSetupComplete = false; + new MainWindow().ShowDialog(); + } + } + else + { + IsFirstRun = false; + BaseDirectory = (string)registryKey.GetValue("InstallLocation")!; } - } - else - { - IsFirstRun = false; - BaseDirectory = (string)registryKey.GetValue("InstallLocation")!; - registryKey.Close(); } // exit if we don't click the install button on installation if (!IsSetupComplete) + { + Logger.WriteLine("[App::OnStartup] Installation cancelled!"); Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT); + } Directories.Initialize(BaseDirectory); - string logdir = IsFirstRun || IsUninstall ? Path.Combine(Directories.LocalAppData, "Temp") : Path.Combine(Directories.Base, "Logs"); - string timestamp = DateTime.UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'"); - Logger = new(Path.Combine(logdir, $"{ProjectName}_{timestamp}.log")); - // we shouldn't save settings on the first run until the first installation is finished, // just in case the user decides to cancel the install if (!IsFirstRun) { + InitLog(); Settings.Load(); State.Load(); } @@ -136,10 +170,8 @@ namespace Bloxstrap string commandLine = ""; - if (LaunchArgs.Length > 0) + if (IsMenuLaunch) { - if (LaunchArgs[0] == "-preferences") - { #if !DEBUG if (Process.GetProcessesByName(ProjectName).Length > 1) { @@ -148,9 +180,11 @@ namespace Bloxstrap } #endif - new MainWindow().ShowDialog(); - } - else if (LaunchArgs[0].StartsWith("roblox-player:")) + new MainWindow().ShowDialog(); + } + else if (LaunchArgs.Length > 0) + { + if (LaunchArgs[0].StartsWith("roblox-player:")) { commandLine = Protocol.ParseUri(LaunchArgs[0]); } diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 19c7787..8b53e25 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -427,7 +427,7 @@ namespace Bloxstrap uninstallKey.SetValue("InstallLocation", Directories.Base); uninstallKey.SetValue("NoRepair", 1); uninstallKey.SetValue("Publisher", "pizzaboxer"); - uninstallKey.SetValue("ModifyPath", $"\"{Directories.Application}\" -preferences"); + uninstallKey.SetValue("ModifyPath", $"\"{Directories.Application}\" -menu"); uninstallKey.SetValue("QuietUninstallString", $"\"{Directories.Application}\" -uninstall -quiet"); uninstallKey.SetValue("UninstallString", $"\"{Directories.Application}\" -uninstall"); uninstallKey.SetValue("URLInfoAbout", $"https://github.com/{App.ProjectRepository}"); @@ -466,7 +466,7 @@ namespace Bloxstrap ShellLink.Shortcut.CreateShortcut(Directories.Application, "", Directories.Application, 0) .WriteToFile(Path.Combine(Directories.StartMenu, "Play Roblox.lnk")); - ShellLink.Shortcut.CreateShortcut(Directories.Application, "-preferences", Directories.Application, 0) + ShellLink.Shortcut.CreateShortcut(Directories.Application, "-menu", Directories.Application, 0) .WriteToFile(Path.Combine(Directories.StartMenu, $"{App.ProjectName} Menu.lnk")); } else @@ -479,7 +479,7 @@ namespace Bloxstrap File.Delete(oldMenuShortcut); if (!File.Exists(newMenuShortcut)) - ShellLink.Shortcut.CreateShortcut(Directories.Application, "-preferences", Directories.Application, 0) + ShellLink.Shortcut.CreateShortcut(Directories.Application, "-menu", Directories.Application, 0) .WriteToFile(newMenuShortcut); } diff --git a/Bloxstrap/Helpers/DeployManager.cs b/Bloxstrap/Helpers/DeployManager.cs index 3a8032d..e4b751b 100644 --- a/Bloxstrap/Helpers/DeployManager.cs +++ b/Bloxstrap/Helpers/DeployManager.cs @@ -50,40 +50,51 @@ namespace Bloxstrap.Helpers }; #endregion - private static string BuildBaseUrl(string channel) - { - if (channel == DefaultChannel) - return DefaultBaseUrl; - else - return $"{DefaultBaseUrl}/channel/{channel.ToLower()}"; - } + private static string BuildBaseUrl(string channel) => channel == DefaultChannel ? DefaultBaseUrl : $"{DefaultBaseUrl}/channel/{channel.ToLower()}"; public static async Task GetLastDeploy(string channel, bool timestamp = false) { + App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Getting deploy info for channel {channel} (timestamp={timestamp})"); + HttpResponseMessage deployInfoResponse = await App.HttpClient.GetAsync($"https://clientsettings.roblox.com/v2/client-version/WindowsPlayer/channel/{channel}"); + string rawResponse = await deployInfoResponse.Content.ReadAsStringAsync(); + if (!deployInfoResponse.IsSuccessStatusCode) { // 400 = Invalid binaryType. // 404 = Could not find version details for binaryType. // 500 = Error while fetching version information. // either way, we throw - throw new Exception($"Could not get latest deploy for channel {channel}"); + + App.Logger.WriteLine( + "[DeployManager::GetLastDeploy] Failed to fetch deploy info!\r\n"+ + $"\tStatus code: {deployInfoResponse.StatusCode}\r\n"+ + $"\tResponse: {rawResponse}" + ); + + throw new Exception($"Could not get latest deploy for channel {channel}! (HTTP {deployInfoResponse.StatusCode})"); } - string rawJson = await deployInfoResponse.Content.ReadAsStringAsync(); - ClientVersion clientVersion = JsonSerializer.Deserialize(rawJson)!; + App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Got JSON: {rawResponse}"); + + ClientVersion clientVersion = JsonSerializer.Deserialize(rawResponse)!; // for preferences if (timestamp) { + App.Logger.WriteLine("[DeployManager::GetLastDeploy] Getting timestamp..."); + string channelUrl = BuildBaseUrl(channel); + string manifestUrl = $"{channelUrl}/{clientVersion.VersionGuid}-rbxPkgManifest.txt"; // get an approximate deploy time from rbxpkgmanifest's last modified date - HttpResponseMessage pkgResponse = await App.HttpClient.GetAsync($"{channelUrl}/{clientVersion.VersionGuid}-rbxPkgManifest.txt"); + HttpResponseMessage pkgResponse = await App.HttpClient.GetAsync(manifestUrl); + if (pkgResponse.Content.Headers.TryGetValues("last-modified", out var values)) { string lastModified = values.First(); + App.Logger.WriteLine($"[DeployManager::GetLastDeploy] {manifestUrl} - Last-Modified: {lastModified}"); clientVersion.Timestamp = DateTime.Parse(lastModified); } } diff --git a/Bloxstrap/Helpers/Logger.cs b/Bloxstrap/Helpers/Logger.cs index 7d51523..c4fd13f 100644 --- a/Bloxstrap/Helpers/Logger.cs +++ b/Bloxstrap/Helpers/Logger.cs @@ -2,11 +2,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; -using System.Printing; using System.Text; using System.Threading; -using System.Threading.Tasks; namespace Bloxstrap.Helpers { @@ -14,31 +11,49 @@ namespace Bloxstrap.Helpers public class Logger { private readonly SemaphoreSlim _semaphore = new(1, 1); - private readonly FileStream _filestream; + private readonly List _backlog = new(); + private FileStream? _filestream; - public Logger(string filename) + public void Initialize(string filename) { + if (_filestream is not null) + throw new Exception("Logger is already initialized"); + string? directory = Path.GetDirectoryName(filename); - + if (directory is not null) Directory.CreateDirectory(directory); _filestream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read); - WriteLine($"[Logger::Logger] {App.ProjectName} v{App.Version} - Initialized at {filename}"); + + if (_backlog.Count > 0) + WriteToLog(String.Join("\r\n", _backlog)); + + WriteLine($"[Logger::Logger] Initialized at {filename}"); } - public async void WriteLine(string message) + public void WriteLine(string message) { string timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'"); - string conout = $"{timestamp} {message}"; - byte[] fileout = Encoding.Unicode.GetBytes($"{conout.Replace(Directories.UserProfile, "")}\r\n"); + string outcon = $"{timestamp} {message}"; + string outlog = outcon.Replace(Directories.UserProfile, ""); - Debug.WriteLine(conout); + Debug.WriteLine(outcon); + WriteToLog(outlog); + } + + private async void WriteToLog(string message) + { + if (_filestream is null) + { + _backlog.Add(message); + return; + } try { await _semaphore.WaitAsync(); - await _filestream.WriteAsync(fileout); + await _filestream.WriteAsync(Encoding.Unicode.GetBytes($"{message}\r\n")); await _filestream.FlushAsync(); } finally diff --git a/Bloxstrap/Helpers/Updater.cs b/Bloxstrap/Helpers/Updater.cs index 89b6940..abf2593 100644 --- a/Bloxstrap/Helpers/Updater.cs +++ b/Bloxstrap/Helpers/Updater.cs @@ -2,7 +2,7 @@ using System.Diagnostics; using System.IO; using System.Windows; - +using Bloxstrap.Enums; using Bloxstrap.Views; namespace Bloxstrap.Helpers @@ -48,7 +48,11 @@ namespace Bloxstrap.Helpers File.Copy(Environment.ProcessPath, Directories.Application); Bootstrapper.Register(); - + + // make people using progress dialog auto switch over to fluent on upgrade + if (App.Version == "2.0.0" && App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ProgressDialog) + App.Settings.Prop.BootstrapperStyle = BootstrapperStyle.FluentDialog; + if (App.IsQuiet || isAutoUpgrade) return; diff --git a/Bloxstrap/Properties/launchSettings.json b/Bloxstrap/Properties/launchSettings.json index 95e6857..63472e5 100644 --- a/Bloxstrap/Properties/launchSettings.json +++ b/Bloxstrap/Properties/launchSettings.json @@ -17,7 +17,7 @@ }, "Bloxstrap (Menu)": { "commandName": "Project", - "commandLineArgs": "-preferences" + "commandLineArgs": "-menu" } } } \ No newline at end of file diff --git a/Bloxstrap/ViewModels/InstallationViewModel.cs b/Bloxstrap/ViewModels/InstallationViewModel.cs index 5813cd7..997d4c8 100644 --- a/Bloxstrap/ViewModels/InstallationViewModel.cs +++ b/Bloxstrap/ViewModels/InstallationViewModel.cs @@ -40,9 +40,14 @@ namespace Bloxstrap.ViewModels OnPropertyChanged(nameof(ChannelDeployInfo)); ClientVersion info = await DeployManager.GetLastDeploy(channel, true); - string? strTimestamp = info.Timestamp?.ToString("MM/dd/yyyy h:mm:ss tt", App.CultureFormat); - ChannelDeployInfo = new DeployInfo() { Version = info.Version, VersionGuid = info.VersionGuid, Timestamp = strTimestamp! }; + ChannelDeployInfo = new DeployInfo + { + Version = info.Version, + VersionGuid = info.VersionGuid, + Timestamp = info.Timestamp?.ToString("MM/dd/yyyy h:mm:ss tt", App.CultureFormat)! + }; + OnPropertyChanged(nameof(ChannelDeployInfo)); } diff --git a/Bloxstrap/Views/MainWindow.xaml.cs b/Bloxstrap/Views/MainWindow.xaml.cs index ca77230..b2087b6 100644 --- a/Bloxstrap/Views/MainWindow.xaml.cs +++ b/Bloxstrap/Views/MainWindow.xaml.cs @@ -19,6 +19,8 @@ namespace Bloxstrap.Views public MainWindow() { + App.Logger.WriteLine("[MainWindow::MainWindow] Initializing menu"); + DataContext = new MainWindowViewModel(this, _dialogService); SetTheme(); InitializeComponent();