using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Security.Principal;
using SkiaSharp;
namespace Artemis.Core;
///
/// Provides a few general utilities for ease of use
///
public static class Utilities
{
///
/// Call this before even initializing the Core to make sure the folders required for operation are in place
///
public static void PrepareFirstLaunch()
{
CreateAccessibleDirectory(Constants.DataFolder);
CreateAccessibleDirectory(Constants.PluginsFolder);
CreateAccessibleDirectory(Constants.LayoutsFolder);
CreateAccessibleDirectory(Constants.UpdatingFolder);
}
///
/// Attempts to gracefully shut down the application with a delayed kill to ensure the application shut down
///
/// This is required because not all SDKs shut down properly, it is too unpredictable to just assume we can
/// gracefully shut down
///
///
public static void Shutdown()
{
// Request a graceful shutdown, whatever UI we're running can pick this up
OnShutdownRequested();
}
///
/// Restarts the application
///
/// Whether the application should be restarted with elevated permissions
/// Delay in seconds before killing process and restarting
/// A list of extra arguments to pass to Artemis when restarting
public static void Restart(bool elevate, TimeSpan delay, params string[] extraArgs)
{
if (!OperatingSystem.IsWindows() && elevate)
throw new ArtemisCoreException("Elevation on non-Windows platforms is not supported.");
OnRestartRequested(new RestartEventArgs(elevate, delay, extraArgs.ToList()));
}
///
/// Applies a pending update
///
/// A boolean indicating whether to silently update or not.
public static void ApplyUpdate(bool silent)
{
OnUpdateRequested(new UpdateEventArgs(silent));
}
///
/// Opens the provided URL in the default web browser
///
/// The URL to open
/// The process created to open the URL
public static Process? OpenUrl(string url)
{
ProcessStartInfo processInfo = new()
{
FileName = url,
UseShellExecute = true
};
return Process.Start(processInfo);
}
///
/// Creates all directories and subdirectories in the specified path unless they already exist with permissions
/// allowing access by everyone.
///
/// The directory to create.
public static void CreateAccessibleDirectory(string path)
{
if (!Directory.Exists(path))
{
DirectoryInfo dataDirectory = Directory.CreateDirectory(path);
if (!OperatingSystem.IsWindows())
return;
// On Windows, ensure everyone has permission (important when running as admin)
DirectorySecurity security = dataDirectory.GetAccessControl();
SecurityIdentifier everyone = new(WellKnownSidType.WorldSid, null);
security.AddAccessRule(new FileSystemAccessRule(
everyone,
FileSystemRights.Modify | FileSystemRights.Synchronize,
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
PropagationFlags.None, AccessControlType.Allow)
);
dataDirectory.SetAccessControl(security);
}
}
///
/// Occurs when the core has requested an application shutdown
///
public static event EventHandler? ShutdownRequested;
///
/// Occurs when the core has requested an application restart
///
public static event EventHandler? RestartRequested;
///
/// Occurs when the core has requested a pending application update to be applied
///
public static event EventHandler? UpdateRequested;
///
/// Opens the provided folder in the user's file explorer
///
/// The full path of the folder to open
public static void OpenFolder(string path)
{
if (OperatingSystem.IsWindows())
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", path);
else if (OperatingSystem.IsMacOS())
Process.Start("open", path);
else if (OperatingSystem.IsLinux())
Process.Start("xdg-open", path);
else
throw new PlatformNotSupportedException("Can't open folders on this platform");
}
///
/// Gets the current application location
///
///
internal static string GetCurrentLocation()
{
return Process.GetCurrentProcess().MainModule!.FileName!;
}
private static void OnRestartRequested(RestartEventArgs e)
{
RestartRequested?.Invoke(null, e);
}
private static void OnShutdownRequested()
{
ShutdownRequested?.Invoke(null, EventArgs.Empty);
}
private static void OnUpdateRequested(UpdateEventArgs e)
{
UpdateRequested?.Invoke(null, e);
}
}