mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-19 00:51:30 -07:00
add background updating
This commit is contained in:
parent
893aecbdd1
commit
3f666333ee
@ -49,6 +49,7 @@ namespace Bloxstrap
|
||||
private LaunchMode _launchMode;
|
||||
|
||||
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
||||
private Version? _latestVersion = null;
|
||||
private string _latestVersionGuid = null!;
|
||||
private string _latestVersionDirectory = null!;
|
||||
private PackageManifest _versionPackageManifest = null!;
|
||||
@ -70,6 +71,9 @@ namespace Bloxstrap
|
||||
public IBootstrapperDialog? Dialog = null;
|
||||
|
||||
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
|
||||
|
||||
public string MutexName { get; set; } = "Bloxstrap-Bootstrapper";
|
||||
public bool QuitIfMutexExists { get; set; } = false;
|
||||
#endregion
|
||||
|
||||
#region Core
|
||||
@ -198,22 +202,24 @@ namespace Bloxstrap
|
||||
// ensure only one instance of the bootstrapper is running at the time
|
||||
// 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();
|
||||
App.Logger.WriteLine(LOG_IDENT, "Bloxstrap-Bootstrapper mutex exists, waiting...");
|
||||
SetStatus(Strings.Bootstrapper_Status_WaitingOtherInstances);
|
||||
mutexExists = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// no mutex exists
|
||||
if (!QuitIfMutexExists)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"{MutexName} mutex exists, waiting...");
|
||||
SetStatus(Strings.Bootstrapper_Status_WaitingOtherInstances);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"{MutexName} mutex exists, exiting!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
_mutex = mutex;
|
||||
@ -237,12 +243,35 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
CleanupVersionsFolder(); // cleanup after background updater
|
||||
|
||||
bool allModificationsApplied = true;
|
||||
|
||||
if (!_noConnection)
|
||||
{
|
||||
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)
|
||||
return;
|
||||
@ -339,11 +368,13 @@ namespace Bloxstrap
|
||||
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
||||
|
||||
_latestVersionGuid = clientVersion.VersionGuid;
|
||||
_latestVersion = Utilities.ParseVersionSafe(clientVersion.Version);
|
||||
}
|
||||
else
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Version set to {App.LaunchSettings.VersionFlag.Data} from arguments");
|
||||
_latestVersionGuid = App.LaunchSettings.VersionFlag.Data;
|
||||
// we can't determine the version
|
||||
}
|
||||
|
||||
_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()
|
||||
{
|
||||
const string LOG_IDENT = "Bootstrapper::StartRoblox";
|
||||
@ -718,6 +774,12 @@ namespace Bloxstrap
|
||||
{
|
||||
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))
|
||||
{
|
||||
string dirName = Path.GetFileName(dir);
|
||||
@ -801,11 +863,11 @@ namespace Bloxstrap
|
||||
_isInstalling = true;
|
||||
|
||||
// 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();
|
||||
|
||||
// get a fully clean install
|
||||
if (Directory.Exists(_latestVersionDirectory))
|
||||
if (!App.LaunchSettings.BackgroundUpdaterFlag.Active && Directory.Exists(_latestVersionDirectory))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -1002,6 +1064,21 @@ namespace Bloxstrap
|
||||
_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()
|
||||
{
|
||||
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
||||
|
@ -4,6 +4,7 @@ using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
|
||||
using Bloxstrap.UI.Elements.Dialogs;
|
||||
using Bloxstrap.Enums;
|
||||
|
||||
namespace Bloxstrap
|
||||
{
|
||||
@ -58,6 +59,11 @@ namespace Bloxstrap
|
||||
App.Logger.WriteLine(LOG_IDENT, "Opening watcher");
|
||||
LaunchWatcher();
|
||||
}
|
||||
else if (App.LaunchSettings.BackgroundUpdaterFlag.Active)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Opening background updater");
|
||||
LaunchBackgroundUpdater();
|
||||
}
|
||||
else if (App.LaunchSettings.RobloxLaunchMode != LaunchMode.None)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Opening bootstrapper ({App.LaunchSettings.RobloxLaunchMode})");
|
||||
@ -295,5 +301,51 @@ namespace Bloxstrap
|
||||
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 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
|
||||
public bool BypassUpdateCheck => true;
|
||||
|
@ -104,7 +104,7 @@ namespace Bloxstrap.UI.Elements.Bootstrapper
|
||||
|
||||
public ByfronDialog()
|
||||
{
|
||||
string version = Utilities.GetRobloxVersion(Bootstrapper?.IsStudioLaunch ?? false);
|
||||
string version = Utilities.GetRobloxVersionStr(Bootstrapper?.IsStudioLaunch ?? false);
|
||||
_viewModel = new ByfronDialogViewModel(this, version);
|
||||
DataContext = _viewModel;
|
||||
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;
|
||||
|
||||
if (!File.Exists(playerLocation))
|
||||
@ -92,6 +106,19 @@ namespace Bloxstrap
|
||||
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()
|
||||
{
|
||||
const string LOG_IDENT = "Utilities::GetProcessesSafe";
|
||||
@ -107,5 +134,24 @@ namespace Bloxstrap
|
||||
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