mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
add background updating
This commit is contained in:
parent
893aecbdd1
commit
3f666333ee
@ -49,6 +49,7 @@ namespace Bloxstrap
|
|||||||
private LaunchMode _launchMode;
|
private LaunchMode _launchMode;
|
||||||
|
|
||||||
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
||||||
|
private Version? _latestVersion = null;
|
||||||
private string _latestVersionGuid = null!;
|
private string _latestVersionGuid = null!;
|
||||||
private string _latestVersionDirectory = null!;
|
private string _latestVersionDirectory = null!;
|
||||||
private PackageManifest _versionPackageManifest = null!;
|
private PackageManifest _versionPackageManifest = null!;
|
||||||
@ -70,6 +71,9 @@ namespace Bloxstrap
|
|||||||
public IBootstrapperDialog? Dialog = null;
|
public IBootstrapperDialog? Dialog = null;
|
||||||
|
|
||||||
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
|
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
|
||||||
|
|
||||||
|
public string MutexName { get; set; } = "Bloxstrap-Bootstrapper";
|
||||||
|
public bool QuitIfMutexExists { get; set; } = false;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Core
|
#region Core
|
||||||
@ -198,22 +202,24 @@ namespace Bloxstrap
|
|||||||
// ensure only one instance of the bootstrapper is running at the time
|
// ensure only one instance of the bootstrapper is running at the time
|
||||||
// so that we don't have stuff like two updates happening simultaneously
|
// so that we don't have stuff like two updates happening simultaneously
|
||||||
|
|
||||||
bool mutexExists = false;
|
bool mutexExists = Utilities.DoesMutexExist(MutexName);
|
||||||
|
|
||||||
try
|
if (mutexExists)
|
||||||
{
|
{
|
||||||
Mutex.OpenExisting("Bloxstrap-Bootstrapper").Close();
|
if (!QuitIfMutexExists)
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Bloxstrap-Bootstrapper mutex exists, waiting...");
|
{
|
||||||
SetStatus(Strings.Bootstrapper_Status_WaitingOtherInstances);
|
App.Logger.WriteLine(LOG_IDENT, $"{MutexName} mutex exists, waiting...");
|
||||||
mutexExists = true;
|
SetStatus(Strings.Bootstrapper_Status_WaitingOtherInstances);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
else
|
||||||
{
|
{
|
||||||
// no mutex exists
|
App.Logger.WriteLine(LOG_IDENT, $"{MutexName} mutex exists, exiting!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for mutex to be released if it's not yet
|
// wait for mutex to be released if it's not yet
|
||||||
await using var mutex = new AsyncMutex(false, "Bloxstrap-Bootstrapper");
|
await using var mutex = new AsyncMutex(false, MutexName);
|
||||||
await mutex.AcquireAsync(_cancelTokenSource.Token);
|
await mutex.AcquireAsync(_cancelTokenSource.Token);
|
||||||
|
|
||||||
_mutex = mutex;
|
_mutex = mutex;
|
||||||
@ -237,12 +243,35 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CleanupVersionsFolder(); // cleanup after background updater
|
||||||
|
|
||||||
bool allModificationsApplied = true;
|
bool allModificationsApplied = true;
|
||||||
|
|
||||||
if (!_noConnection)
|
if (!_noConnection)
|
||||||
{
|
{
|
||||||
if (AppData.State.VersionGuid != _latestVersionGuid || _mustUpgrade)
|
if (AppData.State.VersionGuid != _latestVersionGuid || _mustUpgrade)
|
||||||
await UpgradeRoblox();
|
{
|
||||||
|
bool backgroundUpdaterMutexOpen = Utilities.DoesMutexExist("Bloxstrap-BackgroundUpdater");
|
||||||
|
if (App.LaunchSettings.BackgroundUpdaterFlag.Active)
|
||||||
|
backgroundUpdaterMutexOpen = false; // we want to actually update lol
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Background updater running: {backgroundUpdaterMutexOpen}");
|
||||||
|
|
||||||
|
if (backgroundUpdaterMutexOpen && _mustUpgrade)
|
||||||
|
{
|
||||||
|
// I am Forced Upgrade, killer of Background Updates
|
||||||
|
Utilities.KillBackgroundUpdater();
|
||||||
|
backgroundUpdaterMutexOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!backgroundUpdaterMutexOpen)
|
||||||
|
{
|
||||||
|
if (IsEligibleForBackgroundUpdate())
|
||||||
|
StartBackgroundUpdater();
|
||||||
|
else
|
||||||
|
await UpgradeRoblox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_cancelTokenSource.IsCancellationRequested)
|
if (_cancelTokenSource.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
@ -339,11 +368,13 @@ namespace Bloxstrap
|
|||||||
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
||||||
|
|
||||||
_latestVersionGuid = clientVersion.VersionGuid;
|
_latestVersionGuid = clientVersion.VersionGuid;
|
||||||
|
_latestVersion = Utilities.ParseVersionSafe(clientVersion.Version);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Version set to {App.LaunchSettings.VersionFlag.Data} from arguments");
|
App.Logger.WriteLine(LOG_IDENT, $"Version set to {App.LaunchSettings.VersionFlag.Data} from arguments");
|
||||||
_latestVersionGuid = App.LaunchSettings.VersionFlag.Data;
|
_latestVersionGuid = App.LaunchSettings.VersionFlag.Data;
|
||||||
|
// we can't determine the version
|
||||||
}
|
}
|
||||||
|
|
||||||
_latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid);
|
_latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid);
|
||||||
@ -366,6 +397,31 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsEligibleForBackgroundUpdate()
|
||||||
|
{
|
||||||
|
// TODO: storage check
|
||||||
|
|
||||||
|
if (App.LaunchSettings.BackgroundUpdaterFlag.Active || _mustUpgrade || IsStudioLaunch)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_latestVersion == default) // todo: check if this even works
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Version? currentVersion = Utilities.GetRobloxVersion(AppData);
|
||||||
|
if (currentVersion == default)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// always normally upgrade for downgrades
|
||||||
|
if (currentVersion.Minor > _latestVersion.Minor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// only background update if we're:
|
||||||
|
// - one major update behind
|
||||||
|
// - the same major update
|
||||||
|
int diff = _latestVersion.Minor - currentVersion.Minor;
|
||||||
|
return diff == 0 || diff == 1;
|
||||||
|
}
|
||||||
|
|
||||||
private void StartRoblox()
|
private void StartRoblox()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::StartRoblox";
|
const string LOG_IDENT = "Bootstrapper::StartRoblox";
|
||||||
@ -718,6 +774,12 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::CleanupVersionsFolder";
|
const string LOG_IDENT = "Bootstrapper::CleanupVersionsFolder";
|
||||||
|
|
||||||
|
if (App.LaunchSettings.BackgroundUpdaterFlag.Active)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Background updater tried to cleanup, stopping!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (string dir in Directory.GetDirectories(Paths.Versions))
|
foreach (string dir in Directory.GetDirectories(Paths.Versions))
|
||||||
{
|
{
|
||||||
string dirName = Path.GetFileName(dir);
|
string dirName = Path.GetFileName(dir);
|
||||||
@ -801,11 +863,11 @@ namespace Bloxstrap
|
|||||||
_isInstalling = true;
|
_isInstalling = true;
|
||||||
|
|
||||||
// make sure nothing is running before continuing upgrade
|
// make sure nothing is running before continuing upgrade
|
||||||
if (!IsStudioLaunch) // TODO: wait for studio processes to close before updating to prevent data loss
|
if (!App.LaunchSettings.BackgroundUpdaterFlag.Active && !IsStudioLaunch) // TODO: wait for studio processes to close before updating to prevent data loss
|
||||||
KillRobloxPlayers();
|
KillRobloxPlayers();
|
||||||
|
|
||||||
// get a fully clean install
|
// get a fully clean install
|
||||||
if (Directory.Exists(_latestVersionDirectory))
|
if (!App.LaunchSettings.BackgroundUpdaterFlag.Active && Directory.Exists(_latestVersionDirectory))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1002,6 +1064,21 @@ namespace Bloxstrap
|
|||||||
_isInstalling = false;
|
_isInstalling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void StartBackgroundUpdater()
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "Bootstrapper::StartBackgroundUpdater";
|
||||||
|
|
||||||
|
if (Utilities.DoesMutexExist("Bloxstrap-BackgroundUpdater"))
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Background updater already running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Starting background updater");
|
||||||
|
|
||||||
|
Process.Start(Paths.Process, "-backgroundupdater");
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<bool> ApplyModifications()
|
private async Task<bool> ApplyModifications()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
||||||
|
@ -4,6 +4,7 @@ using Windows.Win32;
|
|||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
|
|
||||||
using Bloxstrap.UI.Elements.Dialogs;
|
using Bloxstrap.UI.Elements.Dialogs;
|
||||||
|
using Bloxstrap.Enums;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
{
|
{
|
||||||
@ -58,6 +59,11 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteLine(LOG_IDENT, "Opening watcher");
|
App.Logger.WriteLine(LOG_IDENT, "Opening watcher");
|
||||||
LaunchWatcher();
|
LaunchWatcher();
|
||||||
}
|
}
|
||||||
|
else if (App.LaunchSettings.BackgroundUpdaterFlag.Active)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Opening background updater");
|
||||||
|
LaunchBackgroundUpdater();
|
||||||
|
}
|
||||||
else if (App.LaunchSettings.RobloxLaunchMode != LaunchMode.None)
|
else if (App.LaunchSettings.RobloxLaunchMode != LaunchMode.None)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Opening bootstrapper ({App.LaunchSettings.RobloxLaunchMode})");
|
App.Logger.WriteLine(LOG_IDENT, $"Opening bootstrapper ({App.LaunchSettings.RobloxLaunchMode})");
|
||||||
@ -295,5 +301,51 @@ namespace Bloxstrap
|
|||||||
App.Terminate();
|
App.Terminate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void LaunchBackgroundUpdater()
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "LaunchHandler::LaunchBackgroundUpdater";
|
||||||
|
|
||||||
|
// Activate some LaunchFlags we need
|
||||||
|
App.LaunchSettings.QuietFlag.Active = true;
|
||||||
|
App.LaunchSettings.NoLaunchFlag.Active = true;
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
||||||
|
App.Bootstrapper = new Bootstrapper(LaunchMode.Player)
|
||||||
|
{
|
||||||
|
MutexName = "Bloxstrap-BackgroundUpdaterKillEvent",
|
||||||
|
QuitIfMutexExists = true
|
||||||
|
};
|
||||||
|
|
||||||
|
CancellationTokenSource cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Started event waiter");
|
||||||
|
using (EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-BackgroundUpdater"))
|
||||||
|
handle.WaitOne();
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Received close event, killing it all!");
|
||||||
|
App.Bootstrapper.Cancel();
|
||||||
|
}, cts.Token);
|
||||||
|
|
||||||
|
Task.Run(App.Bootstrapper.Run).ContinueWith(t =>
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
|
||||||
|
cts.Cancel(); // stop event waiter
|
||||||
|
|
||||||
|
if (t.IsFaulted)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
|
||||||
|
|
||||||
|
if (t.Exception is not null)
|
||||||
|
App.FinalizeExceptionHandling(t.Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Terminate();
|
||||||
|
});
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Exiting");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,31 +12,33 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
public class LaunchSettings
|
public class LaunchSettings
|
||||||
{
|
{
|
||||||
public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings");
|
public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings");
|
||||||
|
|
||||||
public LaunchFlag WatcherFlag { get; } = new("watcher");
|
public LaunchFlag WatcherFlag { get; } = new("watcher");
|
||||||
|
|
||||||
public LaunchFlag QuietFlag { get; } = new("quiet");
|
public LaunchFlag BackgroundUpdaterFlag { get; } = new("backgroundupdater");
|
||||||
|
|
||||||
public LaunchFlag UninstallFlag { get; } = new("uninstall");
|
public LaunchFlag QuietFlag { get; } = new("quiet");
|
||||||
|
|
||||||
public LaunchFlag NoLaunchFlag { get; } = new("nolaunch");
|
public LaunchFlag UninstallFlag { get; } = new("uninstall");
|
||||||
|
|
||||||
public LaunchFlag TestModeFlag { get; } = new("testmode");
|
public LaunchFlag NoLaunchFlag { get; } = new("nolaunch");
|
||||||
|
|
||||||
public LaunchFlag NoGPUFlag { get; } = new("nogpu");
|
public LaunchFlag TestModeFlag { get; } = new("testmode");
|
||||||
|
|
||||||
public LaunchFlag UpgradeFlag { get; } = new("upgrade");
|
public LaunchFlag NoGPUFlag { get; } = new("nogpu");
|
||||||
|
|
||||||
public LaunchFlag PlayerFlag { get; } = new("player");
|
public LaunchFlag UpgradeFlag { get; } = new("upgrade");
|
||||||
|
|
||||||
public LaunchFlag StudioFlag { get; } = new("studio");
|
public LaunchFlag PlayerFlag { get; } = new("player");
|
||||||
|
|
||||||
public LaunchFlag VersionFlag { get; } = new("version");
|
public LaunchFlag StudioFlag { get; } = new("studio");
|
||||||
|
|
||||||
public LaunchFlag ChannelFlag { get; } = new("channel");
|
public LaunchFlag VersionFlag { get; } = new("version");
|
||||||
|
|
||||||
public LaunchFlag ForceFlag { get; } = new("force");
|
public LaunchFlag ChannelFlag { get; } = new("channel");
|
||||||
|
|
||||||
|
public LaunchFlag ForceFlag { get; } = new("force");
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public bool BypassUpdateCheck => true;
|
public bool BypassUpdateCheck => true;
|
||||||
|
@ -104,7 +104,7 @@ namespace Bloxstrap.UI.Elements.Bootstrapper
|
|||||||
|
|
||||||
public ByfronDialog()
|
public ByfronDialog()
|
||||||
{
|
{
|
||||||
string version = Utilities.GetRobloxVersion(Bootstrapper?.IsStudioLaunch ?? false);
|
string version = Utilities.GetRobloxVersionStr(Bootstrapper?.IsStudioLaunch ?? false);
|
||||||
_viewModel = new ByfronDialogViewModel(this, version);
|
_viewModel = new ByfronDialogViewModel(this, version);
|
||||||
DataContext = _viewModel;
|
DataContext = _viewModel;
|
||||||
Title = App.Settings.Prop.BootstrapperTitle;
|
Title = App.Settings.Prop.BootstrapperTitle;
|
||||||
|
@ -75,10 +75,24 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRobloxVersion(bool studio)
|
/// <summary>
|
||||||
|
/// Parses the input version string and prints if fails
|
||||||
|
/// </summary>
|
||||||
|
public static Version? ParseVersionSafe(string versionStr)
|
||||||
{
|
{
|
||||||
IAppData data = studio ? new RobloxStudioData() : new RobloxPlayerData();
|
const string LOG_IDENT = "Utilities::ParseVersionSafe";
|
||||||
|
|
||||||
|
if (!Version.TryParse(versionStr, out Version? version))
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Failed to convert {versionStr} to a valid Version type.");
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetRobloxVersionStr(IAppData data)
|
||||||
|
{
|
||||||
string playerLocation = data.ExecutablePath;
|
string playerLocation = data.ExecutablePath;
|
||||||
|
|
||||||
if (!File.Exists(playerLocation))
|
if (!File.Exists(playerLocation))
|
||||||
@ -92,6 +106,19 @@ namespace Bloxstrap
|
|||||||
return versionInfo.ProductVersion.Replace(", ", ".");
|
return versionInfo.ProductVersion.Replace(", ", ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetRobloxVersionStr(bool studio)
|
||||||
|
{
|
||||||
|
IAppData data = studio ? new RobloxStudioData() : new RobloxPlayerData();
|
||||||
|
|
||||||
|
return GetRobloxVersionStr(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version? GetRobloxVersion(IAppData data)
|
||||||
|
{
|
||||||
|
string str = GetRobloxVersionStr(data);
|
||||||
|
return ParseVersionSafe(str);
|
||||||
|
}
|
||||||
|
|
||||||
public static Process[] GetProcessesSafe()
|
public static Process[] GetProcessesSafe()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Utilities::GetProcessesSafe";
|
const string LOG_IDENT = "Utilities::GetProcessesSafe";
|
||||||
@ -107,5 +134,24 @@ namespace Bloxstrap
|
|||||||
return Array.Empty<Process>(); // can we retry?
|
return Array.Empty<Process>(); // can we retry?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool DoesMutexExist(string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Mutex.OpenExisting(name).Close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KillBackgroundUpdater()
|
||||||
|
{
|
||||||
|
using EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-BackgroundUpdaterKillEvent");
|
||||||
|
handle.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user