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:
JustArchi
2020-11-19 21:01:17 +01:00
parent fc36174953
commit 51ad3b0c76
4 changed files with 350 additions and 303 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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>
<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>

View File

@@ -40,8 +40,13 @@ namespace ArchiSteamFarm {
private static Mutex? SingleInstance;
internal static void CoreInit() {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Console.IsOutputRedirected) {
internal static void CoreInit(bool systemRequired) {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
if (systemRequired) {
WindowsKeepSystemActive();
}
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
@@ -56,6 +61,7 @@ namespace ArchiSteamFarm {
WindowsDisableQuickEditMode();
}
}
}
internal static ICrossProcessSemaphore CreateCrossProcessSemaphore(string objectName) {
if (string.IsNullOrEmpty(objectName)) {
@@ -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) {

View File

@@ -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;
}
}