Make logging more consistent

also added more verbosity, added -menu as an alias for -preferences, and added a migration for people using progress dialog
This commit is contained in:
pizzaboxer 2023-02-16 10:29:40 +00:00
parent 1d48657152
commit 2b646e2b55
8 changed files with 127 additions and 56 deletions

View File

@ -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> Settings = new();
public static readonly JsonManager<State> 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]);
}

View File

@ -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);
}

View File

@ -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<ClientVersion> 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<ClientVersion>(rawJson)!;
App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Got JSON: {rawResponse}");
ClientVersion clientVersion = JsonSerializer.Deserialize<ClientVersion>(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);
}
}

View File

@ -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<string> _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, "<UserProfileFolder>")}\r\n");
string outcon = $"{timestamp} {message}";
string outlog = outcon.Replace(Directories.UserProfile, "<UserProfileFolder>");
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

View File

@ -2,7 +2,7 @@
using System.Diagnostics;
using System.IO;
using System.Windows;
using Bloxstrap.Enums;
using Bloxstrap.Views;
namespace Bloxstrap.Helpers
@ -49,6 +49,10 @@ namespace Bloxstrap.Helpers
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;

View File

@ -17,7 +17,7 @@
},
"Bloxstrap (Menu)": {
"commandName": "Project",
"commandLineArgs": "-preferences"
"commandLineArgs": "-menu"
}
}
}

View File

@ -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));
}

View File

@ -19,6 +19,8 @@ namespace Bloxstrap.Views
public MainWindow()
{
App.Logger.WriteLine("[MainWindow::MainWindow] Initializing menu");
DataContext = new MainWindowViewModel(this, _dialogService);
SetTheme();
InitializeComponent();