From b98268a465d9055a5709f68edd54d0b6266559e2 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Sun, 19 May 2019 15:38:06 +0200 Subject: [PATCH] R# cleanup, small code improvements --- .../ExamplePlugin.cs | 12 +- ArchiSteamFarm.sln.DotSettings | 2 + ArchiSteamFarm/ASF.cs | 17 +- ArchiSteamFarm/ArchiCryptoHelper.cs | 6 - ArchiSteamFarm/ArchiHandler.cs | 1 - ArchiSteamFarm/ArchiWebHandler.cs | 9 - ArchiSteamFarm/Bot.cs | 67 ++---- ArchiSteamFarm/CardsFarmer.cs | 8 +- ArchiSteamFarm/Commands.cs | 219 +++++++----------- ArchiSteamFarm/Helpers/ArchiCacheable.cs | 4 +- ArchiSteamFarm/Json/Steam.cs | 7 +- ArchiSteamFarm/NLog/SteamTarget.cs | 9 +- ArchiSteamFarm/OS.cs | 2 - ArchiSteamFarm/Program.cs | 4 +- ArchiSteamFarm/SharedInfo.cs | 7 +- ArchiSteamFarm/Statistics.cs | 6 +- ArchiSteamFarm/Trading.cs | 5 - ArchiSteamFarm/Utilities.cs | 51 +--- ArchiSteamFarm/WebBrowser.cs | 3 - 19 files changed, 143 insertions(+), 296 deletions(-) diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs index ab4385218164f..8b5a47b4137da 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs @@ -55,8 +55,8 @@ public void OnASFInit(IReadOnlyDictionary additionalConfigProper // ReSharper disable once UseDeconstruction - deconstruction is not available in .NET Framework foreach (KeyValuePair configProperty in additionalConfigProperties) { + // It's a good idea to prefix your custom properties with the name of your plugin, so there will be no possible conflict of ASF or other plugins using the same name, neither now or in the future switch (configProperty.Key) { - // It's a good idea to prefix your custom properties with the name of your plugin, so there will be no possible conflict of ASF or other plugins using the same name, neither now or in the future case nameof(ExamplePlugin) + "TestProperty" when configProperty.Value.Type == JTokenType.Boolean: bool exampleBooleanValue = configProperty.Value.Value(); ASF.ArchiLogger.LogGenericInfo(nameof(ExamplePlugin) + "TestProperty boolean property has been found with a value of: " + exampleBooleanValue); @@ -75,21 +75,15 @@ public void OnASFInit(IReadOnlyDictionary additionalConfigProper // If you do not recognize the command, just return null/empty and allow ASF to gracefully return "unknown command" to user on usual basis public async Task OnBotCommand(Bot bot, ulong steamID, string message, string[] args) { // In comparison with OnBotMessage(), we're using asynchronous CatAPI call here, so we declare our method as async and return the message as usual + // Notice how we handle access here as well, it'll work only for FamilySharing+ switch (args[0].ToUpperInvariant()) { - // Notice how we handle access here as well, it'll work only for FamilySharing+ case "CAT" when bot.HasPermission(steamID, BotConfig.EPermission.FamilySharing): - // Notice how we can decide whether to use bot's AWH WebBrowser or ASF's one. For Steam-related requests, AWH's one should always be used, for third-party requests like those it doesn't really matter // Still, it makes sense to pass AWH's one, so in case you get some errors or alike, you know from which bot instance they come from. It's similar to using Bot's ArchiLogger compared to ASF's one string randomCatURL = await CatAPI.GetRandomCatURL(bot.ArchiWebHandler.WebBrowser).ConfigureAwait(false); - if (string.IsNullOrEmpty(randomCatURL)) { - return "God damn it, we're out of cats, care to notify my master? Thanks!"; - } - - return randomCatURL; + return !string.IsNullOrEmpty(randomCatURL) ? randomCatURL : "God damn it, we're out of cats, care to notify my master? Thanks!"; default: - return null; } } diff --git a/ArchiSteamFarm.sln.DotSettings b/ArchiSteamFarm.sln.DotSettings index e6c9a36980dda..c2a288a8e1d2f 100644 --- a/ArchiSteamFarm.sln.DotSettings +++ b/ArchiSteamFarm.sln.DotSettings @@ -567,6 +567,8 @@ limitations under the License. True 8 True + True + True True True True diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index c309b3a6d31f1..24c3ef8f05eaf 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -81,10 +81,8 @@ internal static string GetFilePath(EFileType fileType) { switch (fileType) { case EFileType.Config: - return Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName); case EFileType.Database: - return Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalDatabaseFileName); default: ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(fileType), fileType)); @@ -350,10 +348,8 @@ private static bool IsValidBotName(string botName) { switch (botName) { case SharedInfo.ASF: - return false; default: - return true; } } @@ -687,28 +683,22 @@ private static bool UpdateFromArchive(ZipArchive archive, string targetDirectory ArchiLogger.LogNullError(nameof(relativeDirectoryName)); return false; - - // No directory, root folder case "": - + // No directory, root folder switch (fileName) { - // Files with those names in root directory we want to keep case SharedInfo.LogFile: case "NLog.config": - + // Files with those names in root directory we want to keep continue; } break; - - // Files in those directories we want to keep in their current place case SharedInfo.ConfigDirectory: case SharedInfo.PluginsDirectory: case SharedInfo.UpdateDirectory: - + // Files in those directories we want to keep in their current place continue; default: - // Files in subdirectories of those directories we want to keep as well if (Utilities.RelativeDirectoryStartsWith(relativeDirectoryName, SharedInfo.ConfigDirectory, SharedInfo.PluginsDirectory, SharedInfo.UpdateDirectory)) { continue; @@ -758,7 +748,6 @@ private static bool UpdateFromArchive(ZipArchive archive, string targetDirectory // We're not interested in extracting placeholder files (but we still want directories created for them, done above) switch (zipFile.Name) { case ".gitkeep": - continue; } } diff --git a/ArchiSteamFarm/ArchiCryptoHelper.cs b/ArchiSteamFarm/ArchiCryptoHelper.cs index f34be03ce2acf..b0712f198b616 100644 --- a/ArchiSteamFarm/ArchiCryptoHelper.cs +++ b/ArchiSteamFarm/ArchiCryptoHelper.cs @@ -38,13 +38,10 @@ internal static string Decrypt(ECryptoMethod cryptoMethod, string encrypted) { switch (cryptoMethod) { case ECryptoMethod.PlainText: - return encrypted; case ECryptoMethod.AES: - return DecryptAES(encrypted); case ECryptoMethod.ProtectedDataForCurrentUser: - return DecryptProtectedDataForCurrentUser(encrypted); default: ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(cryptoMethod), cryptoMethod)); @@ -62,13 +59,10 @@ internal static string Encrypt(ECryptoMethod cryptoMethod, string decrypted) { switch (cryptoMethod) { case ECryptoMethod.PlainText: - return decrypted; case ECryptoMethod.AES: - return EncryptAES(decrypted); case ECryptoMethod.ProtectedDataForCurrentUser: - return EncryptProtectedDataForCurrentUser(decrypted); default: ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(cryptoMethod), cryptoMethod)); diff --git a/ArchiSteamFarm/ArchiHandler.cs b/ArchiSteamFarm/ArchiHandler.cs index aeef2b3e77a49..8aaa5384285b5 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -851,7 +851,6 @@ internal UserNotificationsCallback([NotNull] JobID jobID, [NotNull] CMsgClientUs case EUserNotification.Items: case EUserNotification.ModeratorMessages: case EUserNotification.Trading: - break; default: ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type)); diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index 45ce321bcc93f..88d9d3992b7b3 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -2463,12 +2463,10 @@ private async Task RegisterApiKey() { switch (result.State) { case ESteamApiKeyState.AccessDenied: - // We succeeded in fetching API key, but it resulted in access denied // Return empty result, API key is unavailable permanently return (true, ""); case ESteamApiKeyState.NotRegisteredYet: - // We succeeded in fetching API key, and it resulted in no key registered yet // Let's try to register a new key if (!await RegisterApiKey().ConfigureAwait(false)) { @@ -2491,16 +2489,13 @@ private async Task RegisterApiKey() { goto case ESteamApiKeyState.Registered; case ESteamApiKeyState.Registered: - // We succeeded in fetching API key, and it resulted in registered key // Cache the result, this is the API key we want return (true, result.Key); case ESteamApiKeyState.Timeout: - // Request timed out, bad luck, we'll try again later return (false, null); default: - // We got an unhandled error, this should never happen Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result.State), result.State)); @@ -2554,17 +2549,13 @@ private async Task RegisterApiKey() { switch (userPrivacy.Settings.Profile) { case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly: case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private: - return (true, false); case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public: - switch (userPrivacy.Settings.Inventory) { case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly: case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private: - return (true, false); case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public: - return (true, true); default: Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userPrivacy.Settings.Inventory), userPrivacy.Settings.Inventory)); diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 87ca8903ad038..e483424acedcb 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -452,10 +452,8 @@ public bool HasPermission(ulong steamID, BotConfig.EPermission permission) { switch (permission) { case BotConfig.EPermission.FamilySharing when SteamFamilySharingIDs.Contains(steamID): - return true; default: - return BotConfig.SteamUserPermissions.TryGetValue(steamID, out BotConfig.EPermission realPermission) && (realPermission >= permission); } } @@ -620,11 +618,9 @@ internal static string FormatBotResponse(string response, string botName) { // We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch switch (releaseState.ToUpperInvariant()) { case "RELEASED": - break; case "PRELOADONLY": case "PRERELEASE": - return (0, DateTime.MaxValue); default: ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(releaseState), releaseState)); @@ -641,7 +637,6 @@ internal static string FormatBotResponse(string response, string botName) { // We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch switch (type.ToUpperInvariant()) { - // Types that can be idled case "APPLICATION": case "EPISODE": case "GAME": @@ -650,16 +645,14 @@ internal static string FormatBotResponse(string response, string botName) { case "SERIES": case "TOOL": case "VIDEO": - + // Types that can be idled return (appID, DateTime.MinValue); - - // Types that can't be idled case "ADVERTISING": case "DEMO": case "DLC": case "GUIDE": case "HARDWARE": - + // Types that can't be idled break; default: ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type)); @@ -710,25 +703,18 @@ internal static string GetFilePath(string botName, EFileType fileType) { switch (fileType) { case EFileType.Config: - return botPath + SharedInfo.ConfigExtension; case EFileType.Database: - return botPath + SharedInfo.DatabaseExtension; case EFileType.KeysToRedeem: - return botPath + SharedInfo.KeysExtension; case EFileType.KeysToRedeemUnused: - return botPath + SharedInfo.KeysExtension + SharedInfo.KeysUnusedExtension; case EFileType.KeysToRedeemUsed: - return botPath + SharedInfo.KeysExtension + SharedInfo.KeysUsedExtension; case EFileType.MobileAuthenticator: - return botPath + SharedInfo.MobileAuthenticatorExtension; case EFileType.SentryFile: - return botPath + SharedInfo.SentryHashExtension; default: ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(fileType), fileType)); @@ -1326,14 +1312,12 @@ internal void SetUserInput(ASF.EUserInputType inputType, string inputValue) { break; case ASF.EUserInputType.Login: - if (BotConfig != null) { BotConfig.SteamLogin = inputValue; } break; case ASF.EUserInputType.Password: - if (BotConfig != null) { BotConfig.DecryptedSteamPassword = inputValue; } @@ -1344,7 +1328,6 @@ internal void SetUserInput(ASF.EUserInputType inputType, string inputValue) { break; case ASF.EUserInputType.SteamParentalCode: - if (BotConfig != null) { BotConfig.SteamParentalCode = inputValue; } @@ -1844,27 +1827,21 @@ private bool IsMasterClanID(ulong steamID) { return steamID == BotConfig.SteamMasterClanID; } - private static bool IsRefundable(EPaymentMethod method) { - if (method == EPaymentMethod.None) { - ASF.ArchiLogger.LogNullError(nameof(method)); + private static bool IsRefundable(EPaymentMethod paymentMethod) { + if (paymentMethod == EPaymentMethod.None) { + ASF.ArchiLogger.LogNullError(nameof(paymentMethod)); return false; } - switch (method) { + switch (paymentMethod) { case EPaymentMethod.ActivationCode: case EPaymentMethod.Complimentary: // This is also a flag case EPaymentMethod.GuestPass: case EPaymentMethod.HardwarePromo: - return false; default: - - if (method.HasFlag(EPaymentMethod.Complimentary)) { - return false; - } - - return true; + return !paymentMethod.HasFlag(EPaymentMethod.Complimentary); } } @@ -1889,7 +1866,9 @@ private async Task JoinMasterChatGroupID() { return; } - await ArchiHandler.JoinChatRoomGroup(MasterChatGroupID).ConfigureAwait(false); + if (!await ArchiHandler.JoinChatRoomGroup(MasterChatGroupID).ConfigureAwait(false)) { + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiHandler.JoinChatRoomGroup))); + } } private static async Task LimitLoginRequestsAsync() { @@ -2052,18 +2031,15 @@ private async void OnDisconnected(SteamClient.DisconnectedCallback callback) { switch (lastLogOnResult) { case EResult.AccountDisabled: - // Do not attempt to reconnect, those failures are permanent return; case EResult.Invalid: - // Invalid means that we didn't get OnLoggedOn() in the first place, so Steam is down // Always reset one-time-only access tokens in this case, as OnLoggedOn() didn't do that for us AuthCode = TwoFactorCode = null; break; case EResult.InvalidPassword: - // If we didn't use login key, it's nearly always rate limiting if (string.IsNullOrEmpty(BotDatabase.LoginKey)) { goto case EResult.RateLimitExceeded; @@ -2144,9 +2120,10 @@ private async void OnFriendsList(SteamFriends.FriendsListCallback callback) { break; default: - if (HasPermission(friend.SteamID, BotConfig.EPermission.FamilySharing)) { - await ArchiHandler.AddFriend(friend.SteamID).ConfigureAwait(false); + if (!await ArchiHandler.AddFriend(friend.SteamID).ConfigureAwait(false)) { + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiHandler.AddFriend))); + } break; } @@ -2154,13 +2131,17 @@ private async void OnFriendsList(SteamFriends.FriendsListCallback callback) { bool acceptFriendRequest = await PluginsCore.OnBotFriendRequest(this, friend.SteamID).ConfigureAwait(false); if (acceptFriendRequest) { - await ArchiHandler.AddFriend(friend.SteamID).ConfigureAwait(false); + if (!await ArchiHandler.AddFriend(friend.SteamID).ConfigureAwait(false)) { + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiHandler.AddFriend))); + } break; } if (BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidFriendInvites)) { - await ArchiHandler.RemoveFriend(friend.SteamID).ConfigureAwait(false); + if (!await ArchiHandler.RemoveFriend(friend.SteamID).ConfigureAwait(false)) { + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiHandler.RemoveFriend))); + } } break; @@ -2326,7 +2307,6 @@ private void OnLoggedOff(SteamUser.LoggedOffCallback callback) { switch (callback.Result) { case EResult.LoggedInElsewhere: - // This result directly indicates that playing was blocked when we got (forcefully) disconnected PlayingWasBlocked = true; @@ -2368,7 +2348,6 @@ private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { switch (callback.Result) { case EResult.AccountDisabled: - // Those failures are permanent, we should Stop() the bot if any of those happen ArchiLogger.LogGenericWarning(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult)); Stop(); @@ -2387,7 +2366,6 @@ private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { break; case EResult.AccountLoginDeniedNeedTwoFactor: - if (!HasMobileAuthenticator) { string twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false); @@ -2485,7 +2463,10 @@ private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { if (BotConfig.SteamMasterClanID != 0) { Utilities.InBackground( async () => { - await ArchiWebHandler.JoinGroup(BotConfig.SteamMasterClanID).ConfigureAwait(false); + if (!await ArchiWebHandler.JoinGroup(BotConfig.SteamMasterClanID).ConfigureAwait(false)) { + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiWebHandler.JoinGroup))); + } + await JoinMasterChatGroupID().ConfigureAwait(false); } ); @@ -2514,7 +2495,6 @@ private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { break; default: - // Unexpected result, shutdown immediately ArchiLogger.LogGenericError(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult)); Stop(); @@ -2817,7 +2797,6 @@ private async Task RedeemGamesInBackground() { case EPurchaseResultDetail.DoesNotOwnRequiredApp: case EPurchaseResultDetail.RestrictedCountry: case EPurchaseResultDetail.Timeout: - break; case EPurchaseResultDetail.BadActivationCode: case EPurchaseResultDetail.DuplicateActivationCode: diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 02273aed50416..e3d9d361cdadf 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -572,6 +572,12 @@ private async Task CheckPage(HtmlDocument htmlDocument) { name = WebUtility.HtmlDecode(name.Substring(nameStartIndex, nameEndIndex - nameStartIndex)); + if (string.IsNullOrEmpty(name)) { + Bot.ArchiLogger.LogNullError(nameof(name)); + + continue; + } + // Levels byte badgeLevel = 0; @@ -626,7 +632,6 @@ private async Task CheckPage(HtmlDocument htmlDocument) { break; default: - if (backgroundTasks == null) { backgroundTasks = new List(); } @@ -1058,7 +1063,6 @@ private async Task SortGamesToFarm() { foreach (BotConfig.EFarmingOrder farmingOrder in Bot.BotConfig.FarmingOrders) { switch (farmingOrder) { case BotConfig.EFarmingOrder.Unordered: - break; case BotConfig.EFarmingOrder.AppIDsAscending: gamesToFarm = gamesToFarm.ThenBy(game => game.AppID); diff --git a/ArchiSteamFarm/Commands.cs b/ArchiSteamFarm/Commands.cs index d146f1dfd140b..3bdefb2a7a977 100644 --- a/ArchiSteamFarm/Commands.cs +++ b/ArchiSteamFarm/Commands.cs @@ -89,85 +89,58 @@ public async Task Response(ulong steamID, string message) { return null; case 1: - switch (args[0].ToUpperInvariant()) { case "2FA": - return await Response2FA(steamID).ConfigureAwait(false); case "2FANO": - return await Response2FAConfirm(steamID, false).ConfigureAwait(false); case "2FAOK": - return await Response2FAConfirm(steamID, true).ConfigureAwait(false); case "BALANCE": - return ResponseWalletBalance(steamID); case "BGR": - return ResponseBackgroundGamesRedeemer(steamID); case "BL": - return ResponseBlacklist(steamID); case "EXIT": - return ResponseExit(steamID); case "FARM": - return await ResponseFarm(steamID).ConfigureAwait(false); case "HELP": - return ResponseHelp(steamID); case "IB": - return ResponseIdleBlacklist(steamID); case "IQ": - return ResponseIdleQueue(steamID); case "LEVEL": - return await ResponseLevel(steamID).ConfigureAwait(false); case "LOOT": - return await ResponseLoot(steamID).ConfigureAwait(false); case "PASSWORD": - return ResponsePassword(steamID); case "PAUSE": - return await ResponsePause(steamID, true).ConfigureAwait(false); case "PAUSE~": - return await ResponsePause(steamID, false).ConfigureAwait(false); case "RESUME": - return ResponseResume(steamID); case "RESTART": - return ResponseRestart(steamID); case "SA": - return await ResponseStatus(steamID, SharedInfo.ASF).ConfigureAwait(false); case "START": - return ResponseStart(steamID); case "STATS": - return ResponseStats(steamID); case "STATUS": - return ResponseStatus(steamID).Response; case "STOP": - return ResponseStop(steamID); case "UNPACK": - return await ResponseUnpackBoosters(steamID).ConfigureAwait(false); case "UPDATE": - return await ResponseUpdate(steamID).ConfigureAwait(false); case "VERSION": - return ResponseVersion(steamID); default: string pluginsResponse = await PluginsCore.OnBotCommand(Bot, steamID, message, args).ConfigureAwait(false); @@ -175,191 +148,130 @@ public async Task Response(ulong steamID, string message) { return !string.IsNullOrEmpty(pluginsResponse) ? pluginsResponse : ResponseUnknown(steamID); } default: - switch (args[0].ToUpperInvariant()) { case "2FA": - return await Response2FA(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "2FANO": - return await Response2FAConfirm(steamID, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false); case "2FAOK": - return await Response2FAConfirm(steamID, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false); case "ADDLICENSE" when args.Length > 2: - return await ResponseAddLicense(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "ADDLICENSE": - return await ResponseAddLicense(steamID, args[1]).ConfigureAwait(false); case "BALANCE": - return await ResponseWalletBalance(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "BGR": - return await ResponseBackgroundGamesRedeemer(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "BL": - return await ResponseBlacklist(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "BLADD" when args.Length > 2: - return await ResponseBlacklistAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "BLADD": - return await ResponseBlacklistAdd(steamID, args[1]).ConfigureAwait(false); case "BLRM" when args.Length > 2: - return await ResponseBlacklistRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "BLRM": - return await ResponseBlacklistRemove(steamID, args[1]).ConfigureAwait(false); case "FARM": - return await ResponseFarm(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "INPUT" when args.Length > 3: - return await ResponseInput(steamID, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false); case "INPUT" when args.Length > 2: - return ResponseInput(steamID, args[1], args[2]); case "IB": - return await ResponseIdleBlacklist(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "IBADD" when args.Length > 2: - return await ResponseIdleBlacklistAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "IBADD": - return await ResponseIdleBlacklistAdd(steamID, args[1]).ConfigureAwait(false); case "IBRM" when args.Length > 2: - return await ResponseIdleBlacklistRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "IBRM": - return await ResponseIdleBlacklistRemove(steamID, args[1]).ConfigureAwait(false); case "IQ": - return await ResponseIdleQueue(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "IQADD" when args.Length > 2: - return await ResponseIdleQueueAdd(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "IQADD": - return await ResponseIdleQueueAdd(steamID, args[1]).ConfigureAwait(false); case "IQRM" when args.Length > 2: - return await ResponseIdleQueueRemove(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "IQRM": - return await ResponseIdleQueueRemove(steamID, args[1]).ConfigureAwait(false); case "LEVEL": - return await ResponseLevel(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "LOOT": - return await ResponseLoot(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "LOOT^" when args.Length > 3: - return await ResponseAdvancedLoot(steamID, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false); case "LOOT^" when args.Length > 2: - return await ResponseAdvancedLoot(steamID, args[1], args[2]).ConfigureAwait(false); case "LOOT@" when args.Length > 2: - return await ResponseLootByRealAppIDs(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "LOOT@": - return await ResponseLootByRealAppIDs(steamID, args[1]).ConfigureAwait(false); case "NICKNAME" when args.Length > 2: - return await ResponseNickname(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false); case "NICKNAME": - return ResponseNickname(steamID, args[1]); case "OA": - return await ResponseOwns(steamID, SharedInfo.ASF, Utilities.GetArgsAsText(message, 1)).ConfigureAwait(false); case "OWNS" when args.Length > 2: - return await ResponseOwns(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false); case "OWNS": - return (await ResponseOwns(steamID, args[1]).ConfigureAwait(false)).Response; case "PASSWORD": - return await ResponsePassword(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "PAUSE": - return await ResponsePause(steamID, Utilities.GetArgsAsText(args, 1, ","), true).ConfigureAwait(false); case "PAUSE~": - return await ResponsePause(steamID, Utilities.GetArgsAsText(args, 1, ","), false).ConfigureAwait(false); case "PAUSE&" when args.Length > 2: - return await ResponsePause(steamID, args[1], true, Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false); case "PAUSE&": - return await ResponsePause(steamID, true, args[1]).ConfigureAwait(false); case "PLAY" when args.Length > 2: - return await ResponsePlay(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false); case "PLAY": - return await ResponsePlay(steamID, args[1]).ConfigureAwait(false); case "PRIVACY" when args.Length > 2: - return await ResponsePrivacy(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "PRIVACY": - return await ResponsePrivacy(steamID, args[1]).ConfigureAwait(false); case "R" when args.Length > 2: case "REDEEM" when args.Length > 2: - return await ResponseRedeem(steamID, args[1], Utilities.GetArgsAsText(args, 2, ",")).ConfigureAwait(false); case "R": case "REDEEM": - return await ResponseRedeem(steamID, args[1]).ConfigureAwait(false); case "R^" when args.Length > 3: case "REDEEM^" when args.Length > 3: - return await ResponseAdvancedRedeem(steamID, args[1], args[2], Utilities.GetArgsAsText(args, 3, ",")).ConfigureAwait(false); case "R^" when args.Length > 2: case "REDEEM^" when args.Length > 2: - return await ResponseAdvancedRedeem(steamID, args[1], args[2]).ConfigureAwait(false); case "RESUME": - return await ResponseResume(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "START": - return await ResponseStart(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "STATUS": - return await ResponseStatus(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "STOP": - return await ResponseStop(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); case "TRANSFER" when args.Length > 2: - return await ResponseTransfer(steamID, args[1], Utilities.GetArgsAsText(message, 2)).ConfigureAwait(false); case "TRANSFER": - return await ResponseTransfer(steamID, args[1]).ConfigureAwait(false); case "TRANSFER^" when args.Length > 4: - return await ResponseAdvancedTransfer(steamID, args[1], args[2], args[3], Utilities.GetArgsAsText(message, 4)).ConfigureAwait(false); case "TRANSFER^" when args.Length > 3: - return await ResponseAdvancedTransfer(steamID, args[1], args[2], args[3]).ConfigureAwait(false); case "TRANSFER@" when args.Length > 3: - return await ResponseTransferByRealAppIDs(steamID, args[1], args[2], Utilities.GetArgsAsText(message, 3)).ConfigureAwait(false); case "TRANSFER@" when args.Length > 2: - return await ResponseTransferByRealAppIDs(steamID, args[1], args[2]).ConfigureAwait(false); case "UNPACK": - return await ResponseUnpackBoosters(steamID, Utilities.GetArgsAsText(args, 1, ",")).ConfigureAwait(false); default: string pluginsResponse = await PluginsCore.OnBotCommand(Bot, steamID, message, args).ConfigureAwait(false); @@ -381,7 +293,10 @@ internal async Task HandleMessage(ulong steamID, string message) { string pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false); if (!string.IsNullOrEmpty(pluginsResponse)) { - await Bot.SendMessage(steamID, pluginsResponse).ConfigureAwait(false); + if (!await Bot.SendMessage(steamID, pluginsResponse).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.Content, pluginsResponse)); + } } return; @@ -395,10 +310,14 @@ internal async Task HandleMessage(ulong steamID, string message) { bool feedback = Bot.HasPermission(steamID, BotConfig.EPermission.FamilySharing); if (feedback && !responseTask.IsCompleted) { - await Bot.SendTypingMessage(steamID).ConfigureAwait(false); + if (!await Bot.SendTypingMessage(steamID).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendTypingMessage))); + } while (!responseTask.IsCompleted && (await Task.WhenAny(responseTask, Task.Delay(SteamTypingStatusDelay)).ConfigureAwait(false) != responseTask)) { - await Bot.SendTypingMessage(steamID).ConfigureAwait(false); + if (!await Bot.SendTypingMessage(steamID).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendTypingMessage))); + } } } @@ -413,7 +332,10 @@ internal async Task HandleMessage(ulong steamID, string message) { response = FormatBotResponse(Strings.UnknownCommand); } - await Bot.SendMessage(steamID, response).ConfigureAwait(false); + if (!await Bot.SendMessage(steamID, response).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response)); + } } internal async Task HandleMessage(ulong chatGroupID, ulong chatID, ulong steamID, string message) { @@ -428,7 +350,10 @@ internal async Task HandleMessage(ulong chatGroupID, ulong chatID, ulong steamID string pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false); if (!string.IsNullOrEmpty(pluginsResponse)) { - await Bot.SendMessage(chatGroupID, chatID, pluginsResponse).ConfigureAwait(false); + if (!await Bot.SendMessage(chatGroupID, chatID, pluginsResponse).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.Content, pluginsResponse)); + } } return; @@ -444,10 +369,14 @@ internal async Task HandleMessage(ulong chatGroupID, ulong chatID, ulong steamID if (feedback && !responseTask.IsCompleted) { string pleaseWaitMessage = FormatBotResponse(Strings.PleaseWait); - await Bot.SendMessage(chatGroupID, chatID, pleaseWaitMessage).ConfigureAwait(false); + if (!await Bot.SendMessage(chatGroupID, chatID, pleaseWaitMessage).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + } while (!responseTask.IsCompleted && (await Task.WhenAny(responseTask, Task.Delay(SteamTypingStatusDelay)).ConfigureAwait(false) != responseTask)) { - await Bot.SendMessage(chatGroupID, chatID, pleaseWaitMessage).ConfigureAwait(false); + if (!await Bot.SendMessage(chatGroupID, chatID, pleaseWaitMessage).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + } } } @@ -462,7 +391,10 @@ internal async Task HandleMessage(ulong chatGroupID, ulong chatID, ulong steamID response = FormatBotResponse(Strings.UnknownCommand); } - await Bot.SendMessage(chatGroupID, chatID, response).ConfigureAwait(false); + if (!await Bot.SendMessage(chatGroupID, chatID, response).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response)); + } } internal void OnNewLicenseList() { @@ -759,7 +691,6 @@ private async Task ResponseAdvancedRedeem(ulong steamID, string options, break; default: - return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, flag)); } } @@ -1981,12 +1912,13 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings // Child setting can't be less restrictive than its parent switch (index) { - case 0: // Profile + case 0: + // Profile profile = privacySetting; break; - case 1: // OwnedGames, child of Profile - + case 1: + // OwnedGames, child of Profile if (profile < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(ownedGames))); } @@ -1994,8 +1926,8 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings ownedGames = privacySetting; break; - case 2: // Playtime, child of OwnedGames - + case 2: + // Playtime, child of OwnedGames if (ownedGames < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(playtime))); } @@ -2003,8 +1935,8 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings playtime = privacySetting; break; - case 3: // FriendsList, child of Profile - + case 3: + // FriendsList, child of Profile if (profile < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(ownedGames))); } @@ -2012,8 +1944,8 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings friendsList = privacySetting; break; - case 4: // Inventory, child of Profile - + case 4: + // Inventory, child of Profile if (profile < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(inventory))); } @@ -2021,8 +1953,8 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings inventory = privacySetting; break; - case 5: // InventoryGifts, child of Inventory - + case 5: + // InventoryGifts, child of Inventory if (inventory < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(inventoryGifts))); } @@ -2030,8 +1962,8 @@ private async Task ResponsePrivacy(ulong steamID, string privacySettings inventoryGifts = privacySetting; break; - case 6: // Comments, child of Profile - + case 6: + // Comments, child of Profile if (profile < privacySetting) { return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, nameof(comments))); } @@ -2124,7 +2056,8 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee StringBuilder response = new StringBuilder(); using (HashSet.Enumerator keysEnumerator = pendingKeys.GetEnumerator()) { - string key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Initial key + // Initial key + string key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; while (!string.IsNullOrEmpty(key)) { string startingKey = key; @@ -2134,19 +2067,24 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee while (!string.IsNullOrEmpty(key) && (currentBot != null)) { if (redeemFlags.HasFlag(ERedeemFlags.Validate) && !Utilities.IsValidCdKey(key)) { - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // Next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; - continue; // Keep current bot + // Keep current bot + continue; } if ((currentBot == Bot) && (redeemFlags.HasFlag(ERedeemFlags.SkipInitial) || rateLimitedBots.Contains(currentBot))) { - currentBot = null; // Either bot will be changed, or loop aborted + // Either bot will be changed, or loop aborted + currentBot = null; } else { ArchiHandler.PurchaseResponseCallback result = await currentBot.Actions.RedeemKey(key).ConfigureAwait(false); if (result == null) { response.AppendLine(FormatBotResponse(string.Format(Strings.BotRedeem, key, EPurchaseResultDetail.Timeout), currentBot.BotName)); - currentBot = null; // Either bot will be changed, or loop aborted + + // Either bot will be changed, or loop aborted + currentBot = null; } else { if ((result.PurchaseResultDetail == EPurchaseResultDetail.CannotRedeemCodeFromClient) && (Bot.WalletCurrency != ECurrencyCode.Invalid)) { // If it's a wallet code, we try to redeem it first, then handle the inner result as our primary one @@ -2154,7 +2092,9 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee if (walletResult != null) { result.Result = walletResult.Value.Result; - result.PurchaseResultDetail = walletResult.Value.PurchaseResult.GetValueOrDefault(walletResult.Value.Result == EResult.OK ? EPurchaseResultDetail.NoDetail : EPurchaseResultDetail.BadActivationCode); // BadActivationCode is our smart guess in this case + + // BadActivationCode is our smart guess in this case + result.PurchaseResultDetail = walletResult.Value.PurchaseResult.GetValueOrDefault(walletResult.Value.Result == EResult.OK ? EPurchaseResultDetail.NoDetail : EPurchaseResultDetail.BadActivationCode); } else { result.Result = EResult.Timeout; result.PurchaseResultDetail = EPurchaseResultDetail.Timeout; @@ -2167,7 +2107,6 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee case EPurchaseResultDetail.DuplicateActivationCode: case EPurchaseResultDetail.NoDetail: // OK case EPurchaseResultDetail.Timeout: - if ((result.Items != null) && (result.Items.Count > 0)) { response.AppendLine(FormatBotResponse(string.Format(Strings.BotRedeemWithItems, key, result.Result + "/" + result.PurchaseResultDetail, string.Join(", ", result.Items)), currentBot.BotName)); } else { @@ -2178,18 +2117,20 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee unusedKeys.Remove(key); } - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // Next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; if (result.PurchaseResultDetail == EPurchaseResultDetail.NoDetail) { - break; // Next bot (if needed) + // Next bot (if needed) + break; } - continue; // Keep current bot + // Keep current bot + continue; case EPurchaseResultDetail.AccountLocked: case EPurchaseResultDetail.AlreadyPurchased: case EPurchaseResultDetail.DoesNotOwnRequiredApp: case EPurchaseResultDetail.RestrictedCountry: - if ((result.Items != null) && (result.Items.Count > 0)) { response.AppendLine(FormatBotResponse(string.Format(Strings.BotRedeemWithItems, key, result.Result + "/" + result.PurchaseResultDetail, string.Join(", ", result.Items)), currentBot.BotName)); } else { @@ -2197,13 +2138,16 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee } if (!forward || (keepMissingGames && (result.PurchaseResultDetail != EPurchaseResultDetail.AlreadyPurchased))) { - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // Next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; - break; // Next bot (if needed) + // Next bot (if needed) + break; } if (distribute) { - break; // Next bot, without changing key + // Next bot, without changing key + break; } Dictionary items = result.Items ?? new Dictionary(); @@ -2223,7 +2167,8 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee case EPurchaseResultDetail.BadActivationCode: case EPurchaseResultDetail.DuplicateActivationCode: case EPurchaseResultDetail.NoDetail: // OK - alreadyHandled = true; // This key is already handled, as we either redeemed it or we're sure it's dupe/invalid + // This key is already handled, as we either redeemed it or we're sure it's dupe/invalid + alreadyHandled = true; unusedKeys.Remove(key); break; @@ -2252,9 +2197,11 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee } } - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // Next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; - break; // Next bot (if needed) + // Next bot (if needed) + break; case EPurchaseResultDetail.RateLimited: rateLimitedBots.Add(currentBot); goto case EPurchaseResultDetail.AccountLocked; @@ -2269,9 +2216,11 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee unusedKeys.Remove(key); - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // Next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; - break; // Next bot (if needed) + // Next bot (if needed) + break; } } } @@ -2286,8 +2235,8 @@ private async Task ResponseRedeem(ulong steamID, string keysText, ERedee } if (key == startingKey) { - // We ran out of bots to try for this key, so change it to avoid infinite loop - key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; // Next key + // We ran out of bots to try for this key, so change it to avoid infinite loop, next key + key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; } } } @@ -2737,12 +2686,16 @@ private async Task ResponseUnpackBoosters(ulong steamID) { } // It'd make sense here to actually check return code of ArchiWebHandler.UnpackBooster(), but it lies most of the time | https://github.com/JustArchi/ArchiSteamFarm/issues/704 + bool completeSuccess = true; + // It'd also make sense to run all of this in parallel, but it seems that Steam has a lot of problems with inventory-related parallel requests | https://steamcommunity.com/groups/ascfarm/discussions/1/3559414588264550284/ foreach (Steam.Asset item in inventory) { - await Bot.ArchiWebHandler.UnpackBooster(item.RealAppID, item.AssetID).ConfigureAwait(false); + if (!await Bot.ArchiWebHandler.UnpackBooster(item.RealAppID, item.AssetID).ConfigureAwait(false)) { + completeSuccess = false; + } } - return FormatBotResponse(Strings.Done); + return FormatBotResponse(completeSuccess ? Strings.Success : Strings.Done); } [ItemCanBeNull] diff --git a/ArchiSteamFarm/Helpers/ArchiCacheable.cs b/ArchiSteamFarm/Helpers/ArchiCacheable.cs index 9f4f039bd9a1e..0bcb082c4aa15 100644 --- a/ArchiSteamFarm/Helpers/ArchiCacheable.cs +++ b/ArchiSteamFarm/Helpers/ArchiCacheable.cs @@ -79,16 +79,14 @@ public void Dispose() { if (!success) { switch (fallback) { case EFallback.DefaultForType: - return (false, default); case EFallback.FailedNow: - return (false, result); case EFallback.SuccessPreviously: - return (false, InitializedValue); default: ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(fallback), fallback)); + goto case EFallback.DefaultForType; } } diff --git a/ArchiSteamFarm/Json/Steam.cs b/ArchiSteamFarm/Json/Steam.cs index 90c2daa2ea49a..605d2cd92dd38 100644 --- a/ArchiSteamFarm/Json/Steam.cs +++ b/ArchiSteamFarm/Json/Steam.cs @@ -515,7 +515,6 @@ internal static (Asset.EType Type, Asset.ERarity Rarity, uint RealAppID) Interpr foreach (Tag tag in tags) { switch (tag.Identifier) { case "cardborder": - switch (tag.Value) { case "cardborder_0": type = Asset.EType.TradingCard; @@ -533,7 +532,6 @@ internal static (Asset.EType Type, Asset.ERarity Rarity, uint RealAppID) Interpr break; case "droprate": - switch (tag.Value) { case "droprate_0": rarity = Asset.ERarity.Common; @@ -555,7 +553,6 @@ internal static (Asset.EType Type, Asset.ERarity Rarity, uint RealAppID) Interpr break; case "Game": - if ((tag.Value.Length <= 4) || !tag.Value.StartsWith("app_", StringComparison.Ordinal)) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value)); @@ -574,12 +571,10 @@ internal static (Asset.EType Type, Asset.ERarity Rarity, uint RealAppID) Interpr break; case "item_class": - switch (tag.Value) { case "item_class_2": - - // This is a fallback in case we'd have no cardborder available to interpret if (type == Asset.EType.Unknown) { + // This is a fallback in case we'd have no cardborder available to interpret type = Asset.EType.TradingCard; } diff --git a/ArchiSteamFarm/NLog/SteamTarget.cs b/ArchiSteamFarm/NLog/SteamTarget.cs index 7b73e1a48b186..537acb7b56603 100644 --- a/ArchiSteamFarm/NLog/SteamTarget.cs +++ b/ArchiSteamFarm/NLog/SteamTarget.cs @@ -22,6 +22,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; +using ArchiSteamFarm.Localization; using JetBrains.Annotations; using NLog; using NLog.Config; @@ -102,7 +103,9 @@ private async Task SendGroupMessage(string message, Bot bot = null) { } } - await bot.SendMessage(ChatGroupID, SteamID, message).ConfigureAwait(false); + if (!await bot.SendMessage(ChatGroupID, SteamID, message).ConfigureAwait(false)) { + bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + } } private async Task SendPrivateMessage(string message, Bot bot = null) { @@ -120,7 +123,9 @@ private async Task SendPrivateMessage(string message, Bot bot = null) { } } - await bot.SendMessage(SteamID, message).ConfigureAwait(false); + if (!await bot.SendMessage(SteamID, message).ConfigureAwait(false)) { + bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.SendMessage))); + } } } } diff --git a/ArchiSteamFarm/OS.cs b/ArchiSteamFarm/OS.cs index 2d0a00d0a5eb9..2ca627ff40620 100644 --- a/ArchiSteamFarm/OS.cs +++ b/ArchiSteamFarm/OS.cs @@ -48,11 +48,9 @@ internal static void Init(bool systemRequired, GlobalConfig.EOptimizationMode op switch (optimizationMode) { case GlobalConfig.EOptimizationMode.MaxPerformance: - // No specific tuning required for now, ASF is optimized for max performance by default break; case GlobalConfig.EOptimizationMode.MinMemoryUsage: - // We can disable regex cache which will slightly lower memory usage (for a huge performance hit) Regex.CacheSize = 0; diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 56c7870face17..19505f7614caa 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -43,7 +43,7 @@ internal static class Program { internal static bool ShutdownSequenceInitialized { get; private set; } // We need to keep this one assigned and not calculated on-demand - private static readonly string ProcessFileName = Process.GetCurrentProcess().MainModule.FileName; + private static readonly string ProcessFileName = Process.GetCurrentProcess().MainModule?.FileName ?? throw new ArgumentNullException(nameof(ProcessFileName)); private static readonly TaskCompletionSource ShutdownResetEvent = new TaskCompletionSource(); private static bool SystemRequired; @@ -430,7 +430,6 @@ private static void ParsePostInitArgs(IReadOnlyCollection args) { break; default: - if (cryptKeyNext) { cryptKeyNext = false; HandleCryptKeyArgument(arg); @@ -459,7 +458,6 @@ private static void ParsePreInitArgs(IReadOnlyCollection args) { break; default: - if (pathNext) { pathNext = false; HandlePathArgument(arg); diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 27ef6d23a5afc..cd93f7c7a9a71 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -56,13 +56,14 @@ internal static class SharedInfo { internal const string UpdateDirectory = "_old"; internal const string WebsiteDirectory = "www"; - internal static string HomeDirectory => Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - internal static Guid ModuleVersion => Assembly.GetEntryAssembly().ManifestModule.ModuleVersionId; + internal static string HomeDirectory => Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location ?? throw new ArgumentNullException(nameof(HomeDirectory))); + internal static Guid ModuleVersion => Assembly.GetEntryAssembly()?.ManifestModule.ModuleVersionId ?? throw new ArgumentNullException(nameof(ModuleVersion)); [NotNull] internal static string PublicIdentifier => AssemblyName + (BuildInfo.IsCustomBuild ? "-custom" : ""); - internal static Version Version => Assembly.GetEntryAssembly().GetName().Version; + [NotNull] + internal static Version Version => Assembly.GetEntryAssembly()?.GetName().Version ?? throw new ArgumentNullException(nameof(Version)); [SuppressMessage("ReSharper", "ConvertToConstant.Global")] internal static class BuildInfo { diff --git a/ArchiSteamFarm/Statistics.cs b/ArchiSteamFarm/Statistics.cs index b500cedb9cd50..549c68b5ade62 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -120,7 +120,11 @@ internal async Task OnHeartBeat() { } } - internal async Task OnLoggedOn() => await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false); + internal async Task OnLoggedOn() { + if (!await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false)) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(ArchiWebHandler.JoinGroup))); + } + } internal async Task OnPersonaState(string nickname = null, string avatarHash = null) { if ((DateTime.UtcNow < LastAnnouncementCheck.AddHours(MinAnnouncementCheckTTL)) && (ShouldSendHeartBeats || (LastHeartBeat == DateTime.MinValue))) { diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 740bfc984bd3c..d6cd1548b20e4 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -302,13 +302,11 @@ internal static bool IsEmptyForMatching(IReadOnlyDictionary fullSet foreach ((ulong classID, uint amount) in tradableSet) { switch (amount) { case 0: - // No tradable items, this should never happen, dictionary should not have this key to begin with ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(amount), amount)); return false; case 1: - // Single tradable item, can be matchable or not depending on the rest of the inventory if (!fullSet.TryGetValue(classID, out uint fullAmount) || (fullAmount == 0) || (fullAmount < amount)) { ASF.ArchiLogger.LogNullError(nameof(fullAmount)); @@ -324,7 +322,6 @@ internal static bool IsEmptyForMatching(IReadOnlyDictionary fullSet // A single exclusive tradable item is not matchable, continue continue; default: - // Any other combination of tradable items is always matchable return false; } @@ -518,11 +515,9 @@ private async Task ParseActiveTrades() { // Check if it's donation trade switch (tradeOffer.ItemsToGive.Count) { case 0 when tradeOffer.ItemsToReceive.Count == 0: - // If it's steam issue, try again later return ParseTradeResult.EResult.TryAgain; case 0: - // Otherwise react accordingly, depending on our preference bool acceptDonations = Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.AcceptDonations); bool acceptBotTrades = !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.DontAcceptBotTrades); diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index 2ade47308940a..70fdb79e60178 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -137,7 +137,6 @@ public static async Task InParallel(IEnumerable tasks) { switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: - foreach (Task task in tasks) { await task.ConfigureAwait(false); } @@ -183,55 +182,7 @@ public static bool IsValidHexadecimalText(string text) { return false; } - if (text.Length % 2 != 0) { - return false; - } - - // ulong is 64-bits wide, each hexadecimal character is 4-bits wide, so we split each 16 - const byte split = 16; - - string lastHex; - - if (text.Length >= split) { - StringBuilder hex = new StringBuilder(split, split); - - foreach (char character in text) { - hex.Append(character); - - if (hex.Length < split) { - continue; - } - - if (!ulong.TryParse(hex.ToString(), NumberStyles.HexNumber, null, out _)) { - return false; - } - - hex.Clear(); - } - - if (hex.Length == 0) { - return true; - } - - lastHex = hex.ToString(); - } else { - lastHex = text; - } - - switch (lastHex.Length) { - case 2: - - return byte.TryParse(lastHex, NumberStyles.HexNumber, null, out _); - case 4: - - return ushort.TryParse(lastHex, NumberStyles.HexNumber, null, out _); - case 8: - - return uint.TryParse(lastHex, NumberStyles.HexNumber, null, out _); - default: - - return false; - } + return (text.Length % 2 == 0) && text.All(Uri.IsHexDigit); } [PublicAPI] diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index 586e9e2a1bdf4..aa78c641d0e84 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -591,14 +591,11 @@ private async Task InternalRequest(Uri requestUri, HttpMeth switch (redirectUri.Scheme) { case "http": case "https": - break; case "steammobile": - // Those redirections are invalid, but we're aware of that and we have extra logic for them return response; default: - // We have no clue about those, but maybe HttpClient can handle them for us ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(redirectUri.Scheme), redirectUri.Scheme));