mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-06 17:10:13 +00:00
Improve runtime compatibility
This commit does 3 things: - adds safeguard against running generic-netf in unsupported environments - adds notice about providing ASF with unknown command-line arguments - refactors old pre+post args parsing into a single window
This commit is contained in:
396
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
396
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
@@ -26,36 +26,36 @@
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
@@ -736,4 +736,10 @@ Process uptime: {1}</value>
|
||||
<value>Result: {0}</value>
|
||||
<comment>{0} will be replaced by generic result of various functions that use this string</comment>
|
||||
</data>
|
||||
</root>
|
||||
<data name="WarningUnsupportedEnvironment" xml:space="preserve">
|
||||
<value>You're attempting to run {0} variant of ASF in unsupported environment: {1}. Supply --ignore-unsupported-environment argument if you really know what you're doing.</value>
|
||||
</data>
|
||||
<data name="WarningUnknownCommandLineArgument" xml:space="preserve">
|
||||
<value>Unknown command-line argument: {0}</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -40,20 +40,26 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private static Mutex? SingleInstance;
|
||||
|
||||
internal static void CoreInit() {
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Console.IsOutputRedirected) {
|
||||
// Normally we should use UTF-8 encoding as it's the most correct one for our case, and we already use it on other OSes such as Linux
|
||||
// However, older Windows versions, mainly 7/8.1 can't into UTF-8 without appropriate console font, and expecting from users to change it manually is unwanted
|
||||
// As irrational as it can sound, those versions actually can work with unicode encoding instead, as they magically map it into proper chars despite of incorrect font
|
||||
// We could in theory conditionally use UTF-8 for Windows 10+ and unicode otherwise, but Windows version detection is simply not worth the hassle in this case
|
||||
// Therefore, until we can drop support for Windows < 10, we'll stick with Unicode for all Windows boxes, unless there will be valid reasoning for conditional switch
|
||||
// See https://github.com/JustArchiNET/ArchiSteamFarm/issues/1289 for more details
|
||||
Console.OutputEncoding = Encoding.Unicode;
|
||||
internal static void CoreInit(bool systemRequired) {
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
if (systemRequired) {
|
||||
WindowsKeepSystemActive();
|
||||
}
|
||||
|
||||
// Quick edit mode will freeze when user start selecting something on the console until the selection is cancelled
|
||||
// Users are very often doing it accidentally without any real purpose, and we want to avoid this common issue which causes the whole process to hang
|
||||
// See http://stackoverflow.com/questions/30418886/how-and-why-does-quickedit-mode-in-command-prompt-freeze-applications for more details
|
||||
WindowsDisableQuickEditMode();
|
||||
if (!Console.IsOutputRedirected) {
|
||||
// Normally we should use UTF-8 encoding as it's the most correct one for our case, and we already use it on other OSes such as Linux
|
||||
// However, older Windows versions, mainly 7/8.1 can't into UTF-8 without appropriate console font, and expecting from users to change it manually is unwanted
|
||||
// As irrational as it can sound, those versions actually can work with unicode encoding instead, as they magically map it into proper chars despite of incorrect font
|
||||
// We could in theory conditionally use UTF-8 for Windows 10+ and unicode otherwise, but Windows version detection is simply not worth the hassle in this case
|
||||
// Therefore, until we can drop support for Windows < 10, we'll stick with Unicode for all Windows boxes, unless there will be valid reasoning for conditional switch
|
||||
// See https://github.com/JustArchiNET/ArchiSteamFarm/issues/1289 for more details
|
||||
Console.OutputEncoding = Encoding.Unicode;
|
||||
|
||||
// Quick edit mode will freeze when user start selecting something on the console until the selection is cancelled
|
||||
// Users are very often doing it accidentally without any real purpose, and we want to avoid this common issue which causes the whole process to hang
|
||||
// See http://stackoverflow.com/questions/30418886/how-and-why-does-quickedit-mode-in-command-prompt-freeze-applications for more details
|
||||
WindowsDisableQuickEditMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,15 +73,39 @@ namespace ArchiSteamFarm {
|
||||
return new CrossProcessFileBasedSemaphore(resourceName);
|
||||
}
|
||||
|
||||
internal static void Init(bool systemRequired, GlobalConfig.EOptimizationMode optimizationMode) {
|
||||
if (!Enum.IsDefined(typeof(GlobalConfig.EOptimizationMode), optimizationMode)) {
|
||||
throw new ArgumentNullException(nameof(optimizationMode));
|
||||
internal static bool VerifyEnvironment() {
|
||||
#if NETFRAMEWORK
|
||||
// This is .NET Framework build, we support that one only on mono for platforms not supported by .NET Core
|
||||
|
||||
// We're not going to analyze source builds, as we don't know what changes the author has made, assume they have a point
|
||||
if (SharedInfo.BuildInfo.IsCustomBuild) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
if (systemRequired) {
|
||||
WindowsKeepSystemActive();
|
||||
}
|
||||
// All windows variants have valid .NET Core build, and generic-netf is supported only on mono
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || !RuntimeCompatibility.IsRunningOnMono) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return RuntimeInformation.OSArchitecture switch {
|
||||
// Sadly we can't tell a difference between ARMv6 and ARMv7 reliably, we'll believe that this linux-arm user knows what he's doing and he's indeed in need of generic-netf on ARMv6
|
||||
Architecture.Arm => true,
|
||||
|
||||
// Apart from real x86, this also covers all unknown architectures, such as sparc, ppc64, and anything else Mono might support, we're fine with that
|
||||
Architecture.X86 => true,
|
||||
|
||||
// Everything else is covered by .NET Core
|
||||
_ => false
|
||||
};
|
||||
#else
|
||||
// This is .NET Core build, we support all scenarios
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void Init(GlobalConfig.EOptimizationMode optimizationMode) {
|
||||
if (!Enum.IsDefined(typeof(GlobalConfig.EOptimizationMode), optimizationMode)) {
|
||||
throw new ArgumentNullException(nameof(optimizationMode));
|
||||
}
|
||||
|
||||
switch (optimizationMode) {
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private static readonly TaskCompletionSource<byte> ShutdownResetEvent = new();
|
||||
|
||||
private static bool IgnoreUnsupportedEnvironment;
|
||||
private static bool SystemRequired;
|
||||
|
||||
internal static async Task Exit(byte exitCode = 0) {
|
||||
@@ -119,38 +120,26 @@ namespace ArchiSteamFarm {
|
||||
Target.Register<HistoryTarget>(HistoryTarget.TargetName);
|
||||
Target.Register<SteamTarget>(SteamTarget.TargetName);
|
||||
|
||||
if (!await InitCore(args).ConfigureAwait(false)) {
|
||||
if (!await InitCore(args).ConfigureAwait(false) || !await InitASF().ConfigureAwait(false)) {
|
||||
await Exit(1).ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await InitASF(args).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static async Task InitASF(IReadOnlyCollection<string>? args) {
|
||||
OS.CoreInit();
|
||||
|
||||
Console.Title = SharedInfo.ProgramIdentifier;
|
||||
ASF.ArchiLogger.LogGenericInfo(SharedInfo.ProgramIdentifier);
|
||||
|
||||
private static async Task<bool> InitASF() {
|
||||
if (!await InitGlobalConfigAndLanguage().ConfigureAwait(false)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ASF.GlobalConfig == null) {
|
||||
throw new InvalidOperationException(nameof(ASF.GlobalConfig));
|
||||
}
|
||||
|
||||
// Parse post-init args
|
||||
if (args != null) {
|
||||
ParsePostInitArgs(args);
|
||||
}
|
||||
|
||||
OS.Init(SystemRequired, ASF.GlobalConfig.OptimizationMode);
|
||||
OS.Init(ASF.GlobalConfig.OptimizationMode);
|
||||
|
||||
await InitGlobalDatabaseAndServices().ConfigureAwait(false);
|
||||
await ASF.Init().ConfigureAwait(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> InitCore(IReadOnlyCollection<string>? args) {
|
||||
@@ -173,9 +162,9 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
// Parse pre-init args
|
||||
// Parse args
|
||||
if (args != null) {
|
||||
ParsePreInitArgs(args);
|
||||
ParseArgs(args);
|
||||
}
|
||||
|
||||
bool uniqueInstance = OS.RegisterProcess();
|
||||
@@ -188,6 +177,20 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
OS.CoreInit(SystemRequired);
|
||||
|
||||
Console.Title = SharedInfo.ProgramIdentifier;
|
||||
ASF.ArchiLogger.LogGenericInfo(SharedInfo.ProgramIdentifier);
|
||||
|
||||
if (!IgnoreUnsupportedEnvironment) {
|
||||
if (!OS.VerifyEnvironment()) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnsupportedEnvironment, SharedInfo.BuildInfo.Variant, OS.Variant));
|
||||
await Task.Delay(10000).ConfigureAwait(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -413,7 +416,7 @@ namespace ArchiSteamFarm {
|
||||
e.SetObserved();
|
||||
}
|
||||
|
||||
private static void ParsePostInitArgs(IReadOnlyCollection<string> args) {
|
||||
private static void ParseArgs(IReadOnlyCollection<string> args) {
|
||||
if (args == null) {
|
||||
throw new ArgumentNullException(nameof(args));
|
||||
}
|
||||
@@ -424,49 +427,7 @@ namespace ArchiSteamFarm {
|
||||
if (!string.IsNullOrEmpty(envCryptKey)) {
|
||||
HandleCryptKeyArgument(envCryptKey!);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
|
||||
bool cryptKeyNext = false;
|
||||
|
||||
foreach (string arg in args) {
|
||||
switch (arg) {
|
||||
case "--cryptkey" when !cryptKeyNext:
|
||||
cryptKeyNext = true;
|
||||
|
||||
break;
|
||||
case "--no-restart" when !cryptKeyNext:
|
||||
RestartAllowed = false;
|
||||
|
||||
break;
|
||||
case "--process-required" when !cryptKeyNext:
|
||||
ProcessRequired = true;
|
||||
|
||||
break;
|
||||
case "--system-required" when !cryptKeyNext:
|
||||
SystemRequired = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
if (cryptKeyNext) {
|
||||
cryptKeyNext = false;
|
||||
HandleCryptKeyArgument(arg);
|
||||
} else if ((arg.Length > 11) && arg.StartsWith("--cryptkey=", StringComparison.Ordinal)) {
|
||||
HandleCryptKeyArgument(arg.Substring(11));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParsePreInitArgs(IReadOnlyCollection<string> args) {
|
||||
if (args == null) {
|
||||
throw new ArgumentNullException(nameof(args));
|
||||
}
|
||||
|
||||
try {
|
||||
string? envNetworkGroup = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableNetworkGroup);
|
||||
|
||||
if (!string.IsNullOrEmpty(envNetworkGroup)) {
|
||||
@@ -482,21 +443,45 @@ namespace ArchiSteamFarm {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
|
||||
bool cryptKeyNext = false;
|
||||
bool networkGroupNext = false;
|
||||
bool pathNext = false;
|
||||
|
||||
foreach (string arg in args) {
|
||||
switch (arg) {
|
||||
case "--network-group" when !networkGroupNext && !pathNext:
|
||||
case "--cryptkey" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
cryptKeyNext = true;
|
||||
|
||||
break;
|
||||
case "--ignore-unsupported-environment" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
IgnoreUnsupportedEnvironment = true;
|
||||
|
||||
break;
|
||||
case "--network-group" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
networkGroupNext = true;
|
||||
|
||||
break;
|
||||
case "--path" when !networkGroupNext && !pathNext:
|
||||
case "--no-restart" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
RestartAllowed = false;
|
||||
|
||||
break;
|
||||
case "--process-required" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
ProcessRequired = true;
|
||||
|
||||
break;
|
||||
case "--path" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
pathNext = true;
|
||||
|
||||
break;
|
||||
case "--system-required" when !cryptKeyNext && !networkGroupNext && !pathNext:
|
||||
SystemRequired = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
if (networkGroupNext) {
|
||||
if (cryptKeyNext) {
|
||||
cryptKeyNext = false;
|
||||
HandleCryptKeyArgument(arg);
|
||||
} else if (networkGroupNext) {
|
||||
networkGroupNext = false;
|
||||
HandleNetworkGroupArgument(arg);
|
||||
} else if (pathNext) {
|
||||
@@ -507,10 +492,18 @@ namespace ArchiSteamFarm {
|
||||
case > 16 when arg.StartsWith("--network-group=", StringComparison.Ordinal):
|
||||
HandleNetworkGroupArgument(arg.Substring(16));
|
||||
|
||||
break;
|
||||
case > 11 when arg.StartsWith("--cryptkey=", StringComparison.Ordinal):
|
||||
HandleCryptKeyArgument(arg.Substring(11));
|
||||
|
||||
break;
|
||||
case > 7 when arg.StartsWith("--path=", StringComparison.Ordinal):
|
||||
HandlePathArgument(arg.Substring(7));
|
||||
|
||||
break;
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownCommandLineArgument, arg));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user