Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ArchiSteamFarm/ArchiSteamFarm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageReference Include="SteamKit2" />
<PackageReference Include="System.Composition" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" />
<PackageReference Include="Tmds.DBus.Protocol" />
</ItemGroup>

<ItemGroup>
Expand Down
90 changes: 89 additions & 1 deletion ArchiSteamFarm/Core/OS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
using ArchiSteamFarm.Localization;
using ArchiSteamFarm.Storage;
using ArchiSteamFarm.Web;
using Microsoft.Win32.SafeHandles;
using Tmds.DBus.Protocol;

namespace ArchiSteamFarm.Core;

Expand Down Expand Up @@ -69,13 +71,20 @@ internal static string Version {
}
}

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();
Expand Down Expand Up @@ -181,6 +190,12 @@ internal static void UnregisterProcess() {
// 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() {
Expand Down Expand Up @@ -261,6 +276,79 @@ internal static void WindowsStopFlashingConsoleWindow() {
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();

Expand Down
2 changes: 1 addition & 1 deletion ArchiSteamFarm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ private static async Task<bool> InitCore(IReadOnlyCollection<string>? args) {
return false;
}

OS.CoreInit(Minimized, SystemRequired);
await OS.CoreInit(Minimized, SystemRequired).ConfigureAwait(false);

Console.Title = SharedInfo.ProgramIdentifier;
ASF.ArchiLogger.LogGenericInfo(SharedInfo.ProgramIdentifier);
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -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>