mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-14 21:40:29 +00:00
Make --system-required work on Linux (systemd) (#3526)
* Initial POC * Extract the parts that interest us from auto-generated file * Add support for no dbus being available * Add final bits
This commit is contained in:
committed by
GitHub
parent
d4691ced51
commit
8ac4efe392
@@ -24,6 +24,7 @@
|
||||
<PackageReference Include="SteamKit2" />
|
||||
<PackageReference Include="System.Composition" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
|
||||
<PackageReference Include="Tmds.DBus.Protocol" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -37,6 +37,8 @@ using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Storage;
|
||||
using ArchiSteamFarm.Web;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using Tmds.DBus.Protocol;
|
||||
|
||||
namespace ArchiSteamFarm.Core;
|
||||
|
||||
@@ -69,13 +71,20 @@ internal static class OS {
|
||||
}
|
||||
}
|
||||
|
||||
private static SafeHandle? InhibitLock;
|
||||
private static Mutex? SingleInstance;
|
||||
|
||||
internal static void CoreInit(bool minimized, bool systemRequired) {
|
||||
internal static async Task CoreInit(bool minimized, bool systemRequired) {
|
||||
if (minimized) {
|
||||
MinimizeConsoleWindow();
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsLinux()) {
|
||||
if (systemRequired) {
|
||||
await LinuxKeepSystemActive().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsWindows()) {
|
||||
if (systemRequired) {
|
||||
WindowsKeepSystemActive();
|
||||
@@ -181,6 +190,12 @@ internal static class OS {
|
||||
// Instead, we'll dispose the mutex which should automatically release it by the CLR
|
||||
SingleInstance.Dispose();
|
||||
SingleInstance = null;
|
||||
|
||||
// Release the inhibit lock as well, if needed
|
||||
if (InhibitLock != null) {
|
||||
InhibitLock.Dispose();
|
||||
InhibitLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool VerifyEnvironment() {
|
||||
@@ -261,6 +276,79 @@ internal static class OS {
|
||||
NativeMethods.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("Linux")]
|
||||
private static async Task LinuxKeepSystemActive() {
|
||||
if (!OperatingSystem.IsLinux()) {
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
// Docs: https://systemd.io/INHIBITOR_LOCKS
|
||||
string? systemAddress = Address.System;
|
||||
|
||||
if (string.IsNullOrEmpty(systemAddress)) {
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(systemAddress)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using Connection connection = new(systemAddress);
|
||||
|
||||
try {
|
||||
await connection.ConnectAsync().ConfigureAwait(false);
|
||||
} catch (ConnectException e) {
|
||||
// Possible if no DBus is available at all
|
||||
ASF.ArchiLogger.LogGenericDebuggingException(e);
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(connection)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MessageWriter writer = connection.GetMessageWriter();
|
||||
|
||||
writer.WriteMethodCallHeader(
|
||||
"org.freedesktop.login1",
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"Inhibit",
|
||||
"ssss"
|
||||
);
|
||||
|
||||
// Colon-separated list of lock types
|
||||
writer.WriteString("idle");
|
||||
|
||||
// Human-readable, descriptive string of who is taking the lock
|
||||
writer.WriteString(SharedInfo.PublicIdentifier);
|
||||
|
||||
// Human-readable, descriptive string of why the lock is taken
|
||||
writer.WriteString("--system-required");
|
||||
|
||||
// Mode
|
||||
writer.WriteString("block");
|
||||
|
||||
MessageBuffer message = writer.CreateMessage();
|
||||
|
||||
try {
|
||||
// Inhibit() returns a single value, a file descriptor that encapsulates the lock
|
||||
InhibitLock = await connection.CallMethodAsync(
|
||||
message, static (response, _) => {
|
||||
Reader reader = response.GetBodyReader();
|
||||
|
||||
return reader.ReadHandle<SafeFileHandle>();
|
||||
}
|
||||
).ConfigureAwait(false);
|
||||
} catch (DBusException e) {
|
||||
// Possible if login manager does not support inhibit, although that should be super rare
|
||||
ASF.ArchiLogger.LogGenericDebuggingException(e);
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(connection)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (InhibitLock == null) {
|
||||
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningFailedWithError(nameof(InhibitLock)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void MinimizeConsoleWindow() {
|
||||
(_, int top) = Console.GetCursorPosition();
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ internal static class Program {
|
||||
return false;
|
||||
}
|
||||
|
||||
OS.CoreInit(Minimized, SystemRequired);
|
||||
await OS.CoreInit(Minimized, SystemRequired).ConfigureAwait(false);
|
||||
|
||||
Console.Title = SharedInfo.ProgramIdentifier;
|
||||
ASF.ArchiLogger.LogGenericInfo(SharedInfo.ProgramIdentifier);
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
<PackageVersion Include="System.Composition" Version="10.0.1" />
|
||||
<PackageVersion Include="System.Composition.AttributedModel" Version="10.0.1" />
|
||||
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="10.0.1" />
|
||||
<PackageVersion Include="Tmds.DBus.Protocol" Version="0.21.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user