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 ab4385218..8b5a47b41 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ExamplePlugin.cs @@ -55,8 +55,8 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { // 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 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { // 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 e6c9a3698..c2a288a8e 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 c309b3a6d..24c3ef8f0 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -81,10 +81,8 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { switch (botName) { case SharedInfo.ASF: - return false; default: - return true; } } @@ -687,28 +683,22 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { // 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 f34be03ce..b0712f198 100644 --- a/ArchiSteamFarm/ArchiCryptoHelper.cs +++ b/ArchiSteamFarm/ArchiCryptoHelper.cs @@ -38,13 +38,10 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 aeef2b3e7..8aaa53842 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -851,7 +851,6 @@ namespace ArchiSteamFarm { 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 45ce321bc..88d9d3992 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -2463,12 +2463,10 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 87ca8903a..e483424ac 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -452,10 +452,8 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { // 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 @@ namespace ArchiSteamFarm { // 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; case ASF.EUserInputType.SteamParentalCode: - if (BotConfig != null) { BotConfig.SteamParentalCode = inputValue; } @@ -1844,27 +1827,21 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; case EResult.AccountLoginDeniedNeedTwoFactor: - if (!HasMobileAuthenticator) { string twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false); @@ -2485,7 +2463,10 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; default: - // Unexpected result, shutdown immediately ArchiLogger.LogGenericError(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult)); Stop(); @@ -2817,7 +2797,6 @@ namespace ArchiSteamFarm { 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 02273aed5..e3d9d361c 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -572,6 +572,12 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; default: - if (backgroundTasks == null) { backgroundTasks = new List(); } @@ -1058,7 +1063,6 @@ namespace ArchiSteamFarm { 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 d146f1dfd..3bdefb2a7 100644 --- a/ArchiSteamFarm/Commands.cs +++ b/ArchiSteamFarm/Commands.cs @@ -89,85 +89,58 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; default: - return FormatBotResponse(string.Format(Strings.ErrorIsInvalid, flag)); } } @@ -1981,12 +1912,13 @@ namespace ArchiSteamFarm { // 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { } 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { } } - 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 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { } 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 @@ namespace ArchiSteamFarm { } // 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 9f4f039bd..0bcb082c4 100644 --- a/ArchiSteamFarm/Helpers/ArchiCacheable.cs +++ b/ArchiSteamFarm/Helpers/ArchiCacheable.cs @@ -79,16 +79,14 @@ namespace ArchiSteamFarm.Helpers { 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 90c2daa2e..605d2cd92 100644 --- a/ArchiSteamFarm/Json/Steam.cs +++ b/ArchiSteamFarm/Json/Steam.cs @@ -515,7 +515,6 @@ namespace ArchiSteamFarm.Json { foreach (Tag tag in tags) { switch (tag.Identifier) { case "cardborder": - switch (tag.Value) { case "cardborder_0": type = Asset.EType.TradingCard; @@ -533,7 +532,6 @@ namespace ArchiSteamFarm.Json { break; case "droprate": - switch (tag.Value) { case "droprate_0": rarity = Asset.ERarity.Common; @@ -555,7 +553,6 @@ namespace ArchiSteamFarm.Json { 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 @@ namespace ArchiSteamFarm.Json { 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 7b73e1a48..537acb7b5 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 @@ namespace ArchiSteamFarm.NLog { } } - 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 @@ namespace ArchiSteamFarm.NLog { } } - 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 2d0a00d0a..2ca627ff4 100644 --- a/ArchiSteamFarm/OS.cs +++ b/ArchiSteamFarm/OS.cs @@ -48,11 +48,9 @@ namespace ArchiSteamFarm { 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 56c7870fa..19505f761 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -43,7 +43,7 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { break; default: - if (cryptKeyNext) { cryptKeyNext = false; HandleCryptKeyArgument(arg); @@ -459,7 +458,6 @@ namespace ArchiSteamFarm { break; default: - if (pathNext) { pathNext = false; HandlePathArgument(arg); diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 27ef6d23a..cd93f7c7a 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -56,13 +56,14 @@ namespace ArchiSteamFarm { 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 b500cedb9..549c68b5a 100644 --- a/ArchiSteamFarm/Statistics.cs +++ b/ArchiSteamFarm/Statistics.cs @@ -120,7 +120,11 @@ namespace ArchiSteamFarm { } } - 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 740bfc984..d6cd1548b 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -302,13 +302,11 @@ namespace ArchiSteamFarm { 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 @@ namespace ArchiSteamFarm { // 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 @@ namespace ArchiSteamFarm { // 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 2ade47308..70fdb79e6 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -137,7 +137,6 @@ namespace ArchiSteamFarm { switch (ASF.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: - foreach (Task task in tasks) { await task.ConfigureAwait(false); } @@ -183,55 +182,7 @@ namespace ArchiSteamFarm { 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 586e9e2a1..aa78c641d 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -591,14 +591,11 @@ namespace ArchiSteamFarm { 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));