R# cleanup

This commit is contained in:
JustArchi 2018-12-15 00:27:15 +01:00
parent 39fb21cc83
commit f8aa8babcf
48 changed files with 1510 additions and 32 deletions

View file

@ -263,6 +263,7 @@ namespace ArchiSteamFarm.Tests {
CreateItem(2),
CreateItem(5)
};
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> {
CreateItem(3),
CreateItem(4)

View file

@ -186,7 +186,12 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">END_OF_LINE</s:String>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AFTER_CONTROL_TRANSFER_STATEMENTS/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AFTER_MULTILINE_STATEMENTS/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_FIELD/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_BLOCK_STATEMENTS/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_CONTROL_TRANSFER_STATEMENTS/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_MULTILINE_STATEMENTS/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BEFORE_SINGLE_LINE_COMMENT/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BETWEEN_USING_GROUPS/@EntryValue">0</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_INSIDE_REGION/@EntryValue">0</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/CASE_BLOCK_BRACES/@EntryValue">END_OF_LINE</s:String>

View file

@ -51,6 +51,7 @@ namespace ArchiSteamFarm {
await Utilities.InParallel(Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName).Select(Bot.RegisterBot)).ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return;
}
@ -77,6 +78,7 @@ namespace ArchiSteamFarm {
internal static bool IsOwner(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -107,6 +109,7 @@ namespace ArchiSteamFarm {
// If backup directory from previous update exists, it's a good idea to purge it now
string backupDirectory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.UpdateDirectory);
if (Directory.Exists(backupDirectory)) {
// It's entirely possible that old process is still running, wait a short moment for eventual cleanup
await Task.Delay(5000).ConfigureAwait(false);
@ -115,28 +118,22 @@ namespace ArchiSteamFarm {
Directory.Delete(backupDirectory, true);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
}
// TODO: cleanup from previous update, remove this after next stable
try {
foreach (string file in Directory.EnumerateFiles(SharedInfo.HomeDirectory, "*.old", SearchOption.AllDirectories)) {
File.Delete(file);
}
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
GitHub.ReleaseResponse releaseResponse = await GitHub.GetLatestRelease(Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false);
if (releaseResponse == null) {
ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed);
return null;
}
if (string.IsNullOrEmpty(releaseResponse.Tag)) {
ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed);
return null;
}
@ -151,18 +148,21 @@ namespace ArchiSteamFarm {
if (SharedInfo.Version > newVersion) {
ArchiLogger.LogGenericWarning(Strings.WarningPreReleaseVersion);
await Task.Delay(15 * 1000).ConfigureAwait(false);
return SharedInfo.Version;
}
if (!updateOverride && (Program.GlobalConfig.UpdatePeriod == 0)) {
ArchiLogger.LogGenericInfo(Strings.UpdateNewVersionAvailable);
await Task.Delay(5000).ConfigureAwait(false);
return null;
}
// Auto update logic starts here
if (releaseResponse.Assets == null) {
ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssets);
return null;
}
@ -171,11 +171,13 @@ namespace ArchiSteamFarm {
if (binaryAsset == null) {
ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssetForThisVersion);
return null;
}
if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) {
ArchiLogger.LogNullError(nameof(binaryAsset.DownloadURL));
return null;
}
@ -186,6 +188,7 @@ namespace ArchiSteamFarm {
ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024));
WebBrowser.BinaryResponse response = await Program.WebBrowser.UrlGetToBinaryWithProgress(binaryAsset.DownloadURL).ConfigureAwait(false);
if (response?.Content == null) {
return null;
}
@ -198,17 +201,20 @@ namespace ArchiSteamFarm {
}
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
if (OS.IsUnix) {
string executable = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName);
if (File.Exists(executable)) {
OS.UnixSetFileAccessExecutable(executable);
}
}
ArchiLogger.LogGenericInfo(Strings.UpdateFinished);
return newVersion;
} finally {
UpdateSemaphore.Release();
@ -234,6 +240,7 @@ namespace ArchiSteamFarm {
}
Version newVersion = await Update().ConfigureAwait(false);
if ((newVersion == null) || (newVersion <= SharedInfo.Version)) {
return;
}
@ -244,6 +251,7 @@ namespace ArchiSteamFarm {
private static async Task<bool> CanHandleWriteEvent(string name) {
if (string.IsNullOrEmpty(name)) {
ArchiLogger.LogNullError(nameof(name));
return false;
}
@ -261,6 +269,7 @@ namespace ArchiSteamFarm {
private static bool IsValidBotName(string botName) {
if (string.IsNullOrEmpty(botName)) {
ArchiLogger.LogNullError(nameof(botName));
return false;
}
@ -270,8 +279,10 @@ namespace ArchiSteamFarm {
switch (botName) {
case SharedInfo.ASF:
return false;
default:
return true;
}
}
@ -279,6 +290,7 @@ namespace ArchiSteamFarm {
private static async void OnChanged(object sender, FileSystemEventArgs e) {
if ((sender == null) || (e == null)) {
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
return;
}
@ -288,6 +300,7 @@ namespace ArchiSteamFarm {
private static async Task OnChangedConfigFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
@ -300,9 +313,11 @@ namespace ArchiSteamFarm {
switch (extension) {
case SharedInfo.ConfigExtension:
await OnChangedConfigFile(name, fullPath).ConfigureAwait(false);
break;
case SharedInfo.KeysExtension:
await OnChangedKeysFile(name, fullPath).ConfigureAwait(false);
break;
}
}
@ -310,6 +325,7 @@ namespace ArchiSteamFarm {
private static async Task OnChangedKeysFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
@ -319,6 +335,7 @@ namespace ArchiSteamFarm {
private static async void OnCreated(object sender, FileSystemEventArgs e) {
if ((sender == null) || (e == null)) {
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
return;
}
@ -328,10 +345,12 @@ namespace ArchiSteamFarm {
private static async Task OnCreatedConfigFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
string botName = Path.GetFileNameWithoutExtension(name);
if (string.IsNullOrEmpty(botName) || (botName[0] == '.')) {
return;
}
@ -343,6 +362,7 @@ namespace ArchiSteamFarm {
if (botName.Equals(SharedInfo.ASF)) {
ArchiLogger.LogGenericInfo(Strings.GlobalConfigChanged);
await RestartOrExit().ConfigureAwait(false);
return;
}
@ -360,6 +380,7 @@ namespace ArchiSteamFarm {
private static async Task OnCreatedFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
@ -368,9 +389,11 @@ namespace ArchiSteamFarm {
switch (extension) {
case SharedInfo.ConfigExtension:
await OnCreatedConfigFile(name, fullPath).ConfigureAwait(false);
break;
case SharedInfo.KeysExtension:
await OnCreatedKeysFile(name, fullPath).ConfigureAwait(false);
break;
}
}
@ -378,10 +401,12 @@ namespace ArchiSteamFarm {
private static async Task OnCreatedKeysFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
string botName = Path.GetFileNameWithoutExtension(name);
if (string.IsNullOrEmpty(botName) || (botName[0] == '.')) {
return;
}
@ -400,6 +425,7 @@ namespace ArchiSteamFarm {
private static async void OnDeleted(object sender, FileSystemEventArgs e) {
if ((sender == null) || (e == null)) {
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
return;
}
@ -409,10 +435,12 @@ namespace ArchiSteamFarm {
private static async Task OnDeletedConfigFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
string botName = Path.GetFileNameWithoutExtension(name);
if (string.IsNullOrEmpty(botName)) {
return;
}
@ -429,12 +457,14 @@ namespace ArchiSteamFarm {
// Some editors might decide to delete file and re-create it in order to modify it
// If that's the case, we wait for maximum of 5 seconds before shutting down
await Task.Delay(5000).ConfigureAwait(false);
if (File.Exists(fullPath)) {
return;
}
ArchiLogger.LogGenericError(Strings.ErrorGlobalConfigRemoved);
await Program.Exit(1).ConfigureAwait(false);
return;
}
@ -450,6 +480,7 @@ namespace ArchiSteamFarm {
private static async Task OnDeletedFile(string name, string fullPath) {
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) {
ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath));
return;
}
@ -458,6 +489,7 @@ namespace ArchiSteamFarm {
switch (extension) {
case SharedInfo.ConfigExtension:
await OnDeletedConfigFile(name, fullPath).ConfigureAwait(false);
break;
}
}
@ -465,6 +497,7 @@ namespace ArchiSteamFarm {
private static async void OnRenamed(object sender, RenamedEventArgs e) {
if ((sender == null) || (e == null)) {
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
return;
}
@ -475,6 +508,7 @@ namespace ArchiSteamFarm {
private static bool UpdateFromArchive(ZipArchive archive, string targetDirectory) {
if ((archive == null) || string.IsNullOrEmpty(targetDirectory)) {
ArchiLogger.LogNullError(nameof(archive) + " || " + nameof(targetDirectory));
return false;
}
@ -487,6 +521,7 @@ namespace ArchiSteamFarm {
if (string.IsNullOrEmpty(fileName)) {
ArchiLogger.LogNullError(nameof(fileName));
return false;
}
@ -494,6 +529,7 @@ namespace ArchiSteamFarm {
if (string.IsNullOrEmpty(relativeFilePath)) {
ArchiLogger.LogNullError(nameof(relativeFilePath));
return false;
}
@ -502,18 +538,22 @@ namespace ArchiSteamFarm {
switch (relativeDirectoryName) {
// Files in those directories we want to keep in their current place
case SharedInfo.ConfigDirectory:
continue;
case "":
switch (fileName) {
// Files with those names in root directory we want to keep
case SharedInfo.LogFile:
case "NLog.config":
continue;
}
break;
case null:
ArchiLogger.LogNullError(nameof(relativeDirectoryName));
return false;
}
@ -543,6 +583,7 @@ namespace ArchiSteamFarm {
if (string.IsNullOrEmpty(directory)) {
ArchiLogger.LogNullError(nameof(directory));
return false;
}

View file

@ -68,6 +68,7 @@ namespace ArchiSteamFarm {
}
HashSet<MobileAuthenticator.Confirmation> confirmations = await Bot.BotDatabase.MobileAuthenticator.GetConfirmations(acceptedType).ConfigureAwait(false);
if ((confirmations == null) || (confirmations.Count == 0)) {
continue;
}
@ -125,6 +126,7 @@ namespace ArchiSteamFarm {
}
HashSet<ulong> giftCardIDs = await Bot.ArchiWebHandler.GetDigitalGiftCards().ConfigureAwait(false);
if ((giftCardIDs == null) || (giftCardIDs.Count == 0)) {
return;
}
@ -136,6 +138,7 @@ namespace ArchiSteamFarm {
await LimitGiftsRequestsAsync().ConfigureAwait(false);
bool result = await Bot.ArchiWebHandler.AcceptDigitalGiftCard(giftCardID).ConfigureAwait(false);
if (result) {
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
} else {
@ -150,6 +153,7 @@ namespace ArchiSteamFarm {
internal async Task AcceptGuestPasses(IReadOnlyCollection<ulong> guestPassIDs) {
if ((guestPassIDs == null) || (guestPassIDs.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(guestPassIDs));
return;
}
@ -160,6 +164,7 @@ namespace ArchiSteamFarm {
await LimitGiftsRequestsAsync().ConfigureAwait(false);
ArchiHandler.RedeemGuestPassResponseCallback response = await Bot.ArchiHandler.RedeemGuestPass(guestPassID).ConfigureAwait(false);
if (response != null) {
if (response.Result == EResult.OK) {
Bot.ArchiLogger.LogGenericInfo(Strings.Success);
@ -186,6 +191,7 @@ namespace ArchiSteamFarm {
internal async Task<SemaphoreLock> GetTradingLock() {
await TradingSemaphore.WaitAsync().ConfigureAwait(false);
return new SemaphoreLock(TradingSemaphore);
}
@ -255,12 +261,14 @@ namespace ArchiSteamFarm {
}
Utilities.InBackground(() => Bot.CardsFarmer.Resume(true));
return (true, Strings.BotAutomaticIdlingNowResumed);
}
internal async Task<(bool Success, string Output)> SendTradeOffer(uint appID = Steam.Asset.SteamAppID, byte contextID = Steam.Asset.SteamCommunityContextID, ulong targetSteamID = 0, IReadOnlyCollection<Steam.Asset.EType> wantedTypes = null, IReadOnlyCollection<uint> wantedRealAppIDs = null) {
if ((appID == 0) || (contextID == 0)) {
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(contextID));
return (false, string.Format(Strings.ErrorObjectIsNull, nameof(targetSteamID) + " || " + nameof(appID) + " || " + nameof(contextID)));
}
@ -270,6 +278,7 @@ namespace ArchiSteamFarm {
if (targetSteamID == 0) {
targetSteamID = GetFirstSteamMasterID();
if (targetSteamID == 0) {
return (false, Strings.BotLootingMasterNotDefined);
}
@ -295,6 +304,7 @@ namespace ArchiSteamFarm {
}
HashSet<Steam.Asset> inventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, appID, contextID, true, wantedTypes, wantedRealAppIDs).ConfigureAwait(false);
if ((inventory == null) || (inventory.Count == 0)) {
return (false, string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
}
@ -328,6 +338,7 @@ namespace ArchiSteamFarm {
SkipFirstShutdown = true;
Utilities.InBackground(Bot.Start);
return (true, Strings.Done);
}
@ -337,11 +348,13 @@ namespace ArchiSteamFarm {
}
Bot.Stop();
return (true, Strings.Done);
}
internal static async Task<(bool Success, string Message)> Update() {
Version version = await ASF.Update(true).ConfigureAwait(false);
if (version == null) {
return (false, null);
}
@ -351,6 +364,7 @@ namespace ArchiSteamFarm {
}
Utilities.InBackground(ASF.RestartOrExit);
return (true, version.ToString());
}
@ -362,6 +376,7 @@ namespace ArchiSteamFarm {
}
await GiftsSemaphore.WaitAsync().ConfigureAwait(false);
Utilities.InBackground(
async () => {
await Task.Delay(Program.GlobalConfig.GiftsLimiterDelay * 1000).ConfigureAwait(false);

View file

@ -32,18 +32,23 @@ namespace ArchiSteamFarm {
internal static string Decrypt(ECryptoMethod cryptoMethod, string encrypted) {
if (string.IsNullOrEmpty(encrypted)) {
ASF.ArchiLogger.LogNullError(nameof(encrypted));
return null;
}
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));
return null;
}
}
@ -51,18 +56,23 @@ namespace ArchiSteamFarm {
internal static string Encrypt(ECryptoMethod cryptoMethod, string decrypted) {
if (string.IsNullOrEmpty(decrypted)) {
ASF.ArchiLogger.LogNullError(nameof(decrypted));
return null;
}
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));
return null;
}
}
@ -70,6 +80,7 @@ namespace ArchiSteamFarm {
internal static void SetEncryptionKey(string key) {
if (string.IsNullOrEmpty(key)) {
ASF.ArchiLogger.LogNullError(nameof(key));
return;
}
@ -79,20 +90,24 @@ namespace ArchiSteamFarm {
private static string DecryptAES(string encrypted) {
if (string.IsNullOrEmpty(encrypted)) {
ASF.ArchiLogger.LogNullError(nameof(encrypted));
return null;
}
try {
byte[] key;
using (SHA256 sha256 = SHA256.Create()) {
key = sha256.ComputeHash(EncryptionKey);
}
byte[] decryptedData = Convert.FromBase64String(encrypted);
decryptedData = CryptoHelper.SymmetricDecrypt(decryptedData, key);
return Encoding.UTF8.GetString(decryptedData);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
}
@ -100,6 +115,7 @@ namespace ArchiSteamFarm {
private static string DecryptProtectedDataForCurrentUser(string encrypted) {
if (string.IsNullOrEmpty(encrypted)) {
ASF.ArchiLogger.LogNullError(nameof(encrypted));
return null;
}
@ -113,9 +129,11 @@ namespace ArchiSteamFarm {
return Encoding.UTF8.GetString(decryptedData);
} catch (PlatformNotSupportedException e) {
ASF.ArchiLogger.LogGenericWarningException(e);
return null;
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
}
@ -123,20 +141,24 @@ namespace ArchiSteamFarm {
private static string EncryptAES(string decrypted) {
if (string.IsNullOrEmpty(decrypted)) {
ASF.ArchiLogger.LogNullError(nameof(decrypted));
return null;
}
try {
byte[] key;
using (SHA256 sha256 = SHA256.Create()) {
key = sha256.ComputeHash(EncryptionKey);
}
byte[] encryptedData = Encoding.UTF8.GetBytes(decrypted);
encryptedData = CryptoHelper.SymmetricEncrypt(encryptedData, key);
return Convert.ToBase64String(encryptedData);
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
}
@ -144,6 +166,7 @@ namespace ArchiSteamFarm {
private static string EncryptProtectedDataForCurrentUser(string decrypted) {
if (string.IsNullOrEmpty(decrypted)) {
ASF.ArchiLogger.LogNullError(nameof(decrypted));
return null;
}
@ -157,9 +180,11 @@ namespace ArchiSteamFarm {
return Convert.ToBase64String(encryptedData);
} catch (PlatformNotSupportedException e) {
ASF.ArchiLogger.LogGenericWarningException(e);
return null;
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
}

View file

@ -62,6 +62,7 @@ namespace ArchiSteamFarm {
public override void HandleMsg(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -70,24 +71,31 @@ namespace ArchiSteamFarm {
switch (packetMsg.MsgType) {
case EMsg.ClientItemAnnouncements:
HandleItemAnnouncements(packetMsg);
break;
case EMsg.ClientPlayingSessionState:
HandlePlayingSessionState(packetMsg);
break;
case EMsg.ClientPurchaseResponse:
HandlePurchaseResponse(packetMsg);
break;
case EMsg.ClientRedeemGuestPassResponse:
HandleRedeemGuestPassResponse(packetMsg);
break;
case EMsg.ClientSharedLibraryLockStatus:
HandleSharedLibraryLockStatus(packetMsg);
break;
case EMsg.ClientUserNotifications:
HandleUserNotifications(packetMsg);
break;
case EMsg.ClientVanityURLChangedNotification:
HandleVanityURLChangedNotification(packetMsg);
break;
}
}
@ -95,6 +103,7 @@ namespace ArchiSteamFarm {
internal void AckChatMessage(ulong chatGroupID, ulong chatID, uint timestamp) {
if ((chatGroupID == 0) || (chatID == 0) || (timestamp == 0)) {
ArchiLogger.LogNullError(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(timestamp));
return;
}
@ -114,6 +123,7 @@ namespace ArchiSteamFarm {
internal void AckMessage(ulong steamID, uint timestamp) {
if ((steamID == 0) || (timestamp == 0)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(timestamp));
return;
}
@ -132,6 +142,7 @@ namespace ArchiSteamFarm {
internal void AcknowledgeClanInvite(ulong clanID, bool acceptInvite) {
if (clanID == 0) {
ArchiLogger.LogNullError(nameof(clanID));
return;
}
@ -152,6 +163,7 @@ namespace ArchiSteamFarm {
internal async Task<bool> AddFriend(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -167,11 +179,13 @@ namespace ArchiSteamFarm {
response = await UnifiedPlayerService.SendMessage(x => x.AddFriend(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return false;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return false;
}
@ -181,6 +195,7 @@ namespace ArchiSteamFarm {
internal async Task<ulong> GetClanChatGroupID(ulong steamID) {
if ((steamID == 0) || !new SteamID(steamID).IsClanAccount) {
ArchiLogger.LogNullError(nameof(steamID));
return 0;
}
@ -199,11 +214,13 @@ namespace ArchiSteamFarm {
response = await UnifiedClanChatRoomsService.SendMessage(x => x.GetClanChatRoomInfo(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return 0;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return 0;
}
@ -212,6 +229,7 @@ namespace ArchiSteamFarm {
}
CClanChatRooms_GetClanChatRoomInfo_Response body = response.GetDeserializedResponse<CClanChatRooms_GetClanChatRoomInfo_Response>();
return body.chat_group_summary.chat_group_id;
}
@ -227,11 +245,13 @@ namespace ArchiSteamFarm {
response = await UnifiedPlayerService.SendMessage(x => x.GetGameBadgeLevels(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return null;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return null;
}
@ -240,6 +260,7 @@ namespace ArchiSteamFarm {
}
CPlayer_GetGameBadgeLevels_Response body = response.GetDeserializedResponse<CPlayer_GetGameBadgeLevels_Response>();
return body.player_level;
}
@ -256,11 +277,13 @@ namespace ArchiSteamFarm {
response = await UnifiedChatRoomService.SendMessage(x => x.GetMyChatRoomGroups(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return null;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return null;
}
@ -269,6 +292,7 @@ namespace ArchiSteamFarm {
}
CChatRoom_GetMyChatRoomGroups_Response body = response.GetDeserializedResponse<CChatRoom_GetMyChatRoomGroups_Response>();
return body.chat_room_groups.Select(chatRoom => chatRoom.group_summary.chat_group_id).ToHashSet();
}
@ -285,11 +309,13 @@ namespace ArchiSteamFarm {
response = await UnifiedEconService.SendMessage(x => x.GetTradeOfferAccessToken(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return null;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return null;
}
@ -298,12 +324,14 @@ namespace ArchiSteamFarm {
}
CEcon_GetTradeOfferAccessToken_Response body = response.GetDeserializedResponse<CEcon_GetTradeOfferAccessToken_Response>();
return body.trade_offer_access_token;
}
internal async Task<bool> JoinChatRoomGroup(ulong chatGroupID) {
if (chatGroupID == 0) {
ArchiLogger.LogNullError(nameof(chatGroupID));
return false;
}
@ -319,11 +347,13 @@ namespace ArchiSteamFarm {
response = await UnifiedChatRoomService.SendMessage(x => x.JoinChatRoomGroup(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return false;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return false;
}
@ -333,6 +363,7 @@ namespace ArchiSteamFarm {
internal async Task PlayGames(IEnumerable<uint> gameIDs, string gameName = null) {
if (gameIDs == null) {
ArchiLogger.LogNullError(nameof(gameIDs));
return;
}
@ -378,6 +409,7 @@ namespace ArchiSteamFarm {
internal async Task<RedeemGuestPassResponseCallback> RedeemGuestPass(ulong guestPassID) {
if (guestPassID == 0) {
ArchiLogger.LogNullError(nameof(guestPassID));
return null;
}
@ -396,6 +428,7 @@ namespace ArchiSteamFarm {
return await new AsyncJob<RedeemGuestPassResponseCallback>(Client, request.SourceJobID);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
}
@ -403,6 +436,7 @@ namespace ArchiSteamFarm {
internal async Task<PurchaseResponseCallback> RedeemKey(string key) {
if (string.IsNullOrEmpty(key)) {
ArchiLogger.LogNullError(nameof(key));
return null;
}
@ -421,6 +455,7 @@ namespace ArchiSteamFarm {
return await new AsyncJob<PurchaseResponseCallback>(Client, request.SourceJobID);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
}
@ -428,6 +463,7 @@ namespace ArchiSteamFarm {
internal async Task<bool> RemoveFriend(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -443,11 +479,13 @@ namespace ArchiSteamFarm {
response = await UnifiedPlayerService.SendMessage(x => x.RemoveFriend(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return false;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return false;
}
@ -466,6 +504,7 @@ namespace ArchiSteamFarm {
internal async Task<EResult> SendMessage(ulong steamID, string message) {
if ((steamID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(message));
return EResult.Fail;
}
@ -486,11 +525,13 @@ namespace ArchiSteamFarm {
response = await UnifiedFriendMessagesService.SendMessage(x => x.SendMessage(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return EResult.Timeout;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return EResult.Fail;
}
@ -500,6 +541,7 @@ namespace ArchiSteamFarm {
internal async Task<EResult> SendMessage(ulong chatGroupID, ulong chatID, string message) {
if ((chatGroupID == 0) || (chatID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(message));
return EResult.Fail;
}
@ -519,11 +561,13 @@ namespace ArchiSteamFarm {
response = await UnifiedChatRoomService.SendMessage(x => x.SendChatMessage(request));
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
return EResult.Timeout;
}
if (response == null) {
ArchiLogger.LogNullError(nameof(response));
return EResult.Fail;
}
@ -533,6 +577,7 @@ namespace ArchiSteamFarm {
internal void SetCurrentMode(uint chatMode) {
if (chatMode == 0) {
ArchiLogger.LogNullError(nameof(chatMode));
return;
}
@ -547,6 +592,7 @@ namespace ArchiSteamFarm {
private void HandleItemAnnouncements(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -557,6 +603,7 @@ namespace ArchiSteamFarm {
private void HandlePlayingSessionState(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -567,6 +614,7 @@ namespace ArchiSteamFarm {
private void HandlePurchaseResponse(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -577,6 +625,7 @@ namespace ArchiSteamFarm {
private void HandleRedeemGuestPassResponse(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -587,6 +636,7 @@ namespace ArchiSteamFarm {
private void HandleSharedLibraryLockStatus(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -597,6 +647,7 @@ namespace ArchiSteamFarm {
private void HandleUserNotifications(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -607,6 +658,7 @@ namespace ArchiSteamFarm {
private void HandleVanityURLChangedNotification(IPacketMsg packetMsg) {
if (packetMsg == null) {
ArchiLogger.LogNullError(nameof(packetMsg));
return;
}
@ -632,38 +684,48 @@ namespace ArchiSteamFarm {
if (msg.purchase_receipt_info == null) {
ASF.ArchiLogger.LogNullError(nameof(msg.purchase_receipt_info));
return;
}
KeyValue receiptInfo = new KeyValue();
using (MemoryStream ms = new MemoryStream(msg.purchase_receipt_info)) {
if (!receiptInfo.TryReadAsBinary(ms)) {
ASF.ArchiLogger.LogNullError(nameof(ms));
return;
}
}
List<KeyValue> lineItems = receiptInfo["lineitems"].Children;
if (lineItems.Count == 0) {
return;
}
Items = new Dictionary<uint, string>(lineItems.Count);
foreach (KeyValue lineItem in lineItems) {
uint packageID = lineItem["PackageID"].AsUnsignedInteger();
if (packageID == 0) {
// Coupons have PackageID of -1 (don't ask me why)
// We'll use ItemAppID in this case
packageID = lineItem["ItemAppID"].AsUnsignedInteger();
if (packageID == 0) {
ASF.ArchiLogger.LogNullError(nameof(packageID));
return;
}
}
string gameName = lineItem["ItemDescription"].Value;
if (string.IsNullOrEmpty(gameName)) {
ASF.ArchiLogger.LogNullError(nameof(gameName));
return;
}
@ -749,9 +811,11 @@ namespace ArchiSteamFarm {
case EUserNotification.Items:
case EUserNotification.ModeratorMessages:
case EUserNotification.Trading:
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type));
continue;
}

File diff suppressed because it is too large Load diff

View file

@ -272,6 +272,7 @@ namespace ArchiSteamFarm {
internal async Task AddGamesToRedeemInBackground(IOrderedDictionary gamesToRedeemInBackground) {
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
ArchiLogger.LogNullError(nameof(gamesToRedeemInBackground));
return;
}
@ -313,6 +314,7 @@ namespace ArchiSteamFarm {
return true;
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return false;
}
}
@ -330,6 +332,7 @@ namespace ArchiSteamFarm {
return true;
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return false;
}
}
@ -337,6 +340,7 @@ namespace ArchiSteamFarm {
internal static string FormatBotResponse(string response, string botName) {
if (string.IsNullOrEmpty(response) || string.IsNullOrEmpty(botName)) {
ASF.ArchiLogger.LogNullError(nameof(response) + " || " + nameof(botName));
return null;
}
@ -346,11 +350,13 @@ namespace ArchiSteamFarm {
internal async Task<(uint PlayableAppID, DateTime IgnoredUntil)> GetAppDataForIdling(uint appID, float hoursPlayed, bool allowRecursiveDiscovery = true, bool optimisticDiscovery = true) {
if ((appID == 0) || (hoursPlayed < 0)) {
ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(hoursPlayed));
return (0, DateTime.MaxValue);
}
if ((hoursPlayed < CardsFarmer.HoursForRefund) && !BotConfig.IdleRefundableGames) {
HashSet<uint> packageIDs = Program.GlobalDatabase.GetPackageIDs(appID);
if (packageIDs == null) {
return (0, DateTime.MaxValue);
}
@ -370,6 +376,7 @@ namespace ArchiSteamFarm {
if (mostRecent > DateTime.MinValue) {
DateTime playableIn = mostRecent.AddDays(CardsFarmer.DaysForRefund);
if (playableIn > DateTime.UtcNow) {
return (0, playableIn);
}
@ -401,32 +408,40 @@ namespace ArchiSteamFarm {
}
KeyValue productInfo = productInfoApp.KeyValues;
if (productInfo == KeyValue.Invalid) {
ArchiLogger.LogNullError(nameof(productInfo));
break;
}
KeyValue commonProductInfo = productInfo["common"];
if (commonProductInfo == KeyValue.Invalid) {
continue;
}
string releaseState = commonProductInfo["ReleaseState"].Value;
if (!string.IsNullOrEmpty(releaseState)) {
// 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));
break;
}
}
string type = commonProductInfo["type"].Value;
if (string.IsNullOrEmpty(type)) {
return (appID, DateTime.MinValue);
}
@ -442,6 +457,7 @@ namespace ArchiSteamFarm {
case "SERIES":
case "TOOL":
case "VIDEO":
return (appID, DateTime.MinValue);
// Types that can't be idled
@ -450,9 +466,11 @@ namespace ArchiSteamFarm {
case "DLC":
case "GUIDE":
case "HARDWARE":
break;
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type));
break;
}
@ -461,6 +479,7 @@ namespace ArchiSteamFarm {
}
string listOfDlc = productInfo["extended"]["listofdlc"].Value;
if (string.IsNullOrEmpty(listOfDlc)) {
return (appID, DateTime.MinValue);
}
@ -470,10 +489,12 @@ namespace ArchiSteamFarm {
foreach (string dlcAppIDsText in dlcAppIDsTexts) {
if (!uint.TryParse(dlcAppIDsText, out uint dlcAppID) || (dlcAppID == 0)) {
ArchiLogger.LogNullError(nameof(dlcAppID));
break;
}
(uint playableAppID, _) = await GetAppDataForIdling(dlcAppID, hoursPlayed, false, false).ConfigureAwait(false);
if (playableAppID != 0) {
return (playableAppID, DateTime.MinValue);
}
@ -488,12 +509,14 @@ namespace ArchiSteamFarm {
internal static HashSet<Bot> GetBots(string args) {
if (string.IsNullOrEmpty(args)) {
ASF.ArchiLogger.LogNullError(nameof(args));
return null;
}
string[] botNames = args.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
HashSet<Bot> result = new HashSet<Bot>();
foreach (string botName in botNames) {
if (botName.Equals(SharedInfo.ASF, StringComparison.OrdinalIgnoreCase)) {
foreach (Bot bot in Bots.OrderBy(bot => bot.Key).Select(bot => bot.Value)) {
@ -505,6 +528,7 @@ namespace ArchiSteamFarm {
if (botName.Contains("..")) {
string[] botRange = botName.Split(new[] { ".." }, StringSplitOptions.RemoveEmptyEntries);
if (botRange.Length == 2) {
if (Bots.TryGetValue(botRange[0], out Bot firstBot) && Bots.TryGetValue(botRange[1], out Bot lastBot)) {
bool inRange = false;
@ -534,6 +558,7 @@ namespace ArchiSteamFarm {
result.UnionWith(regexMatches);
} catch (ArgumentException e) {
ASF.ArchiLogger.LogGenericWarningException(e);
return null;
}
}
@ -553,6 +578,7 @@ namespace ArchiSteamFarm {
internal async Task<Dictionary<uint, (uint ChangeNumber, HashSet<uint> AppIDs)>> GetPackagesData(IReadOnlyCollection<uint> packageIDs) {
if ((packageIDs == null) || (packageIDs.Count == 0)) {
ArchiLogger.LogNullError(nameof(packageIDs));
return null;
}
@ -579,6 +605,7 @@ namespace ArchiSteamFarm {
foreach (SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo in productInfoResultSet.Results.SelectMany(productInfoResult => productInfoResult.Packages).Where(productInfoPackages => productInfoPackages.Key != 0).Select(productInfoPackages => productInfoPackages.Value)) {
if (productInfo.KeyValues == KeyValue.Invalid) {
ArchiLogger.LogNullError(nameof(productInfo));
return null;
}
@ -586,6 +613,7 @@ namespace ArchiSteamFarm {
try {
KeyValue appIDs = productInfo.KeyValues["appids"];
if (appIDs == KeyValue.Invalid) {
continue;
}
@ -595,6 +623,7 @@ namespace ArchiSteamFarm {
foreach (string appIDText in appIDs.Children.Select(app => app.Value)) {
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
ArchiLogger.LogNullError(nameof(appID));
return null;
}
@ -611,6 +640,7 @@ namespace ArchiSteamFarm {
internal BotConfig.EPermission GetSteamUserPermission(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return BotConfig.EPermission.None;
}
@ -620,6 +650,7 @@ namespace ArchiSteamFarm {
internal async Task<byte?> GetTradeHoldDuration(ulong steamID, ulong tradeID) {
if ((steamID == 0) || (tradeID == 0)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(tradeID));
return null;
}
@ -628,8 +659,10 @@ namespace ArchiSteamFarm {
}
Bot targetBot = Bots.Values.FirstOrDefault(bot => bot.SteamID == steamID);
if (targetBot != null) {
string targetTradeToken = await targetBot.ArchiHandler.GetTradeToken().ConfigureAwait(false);
if (!string.IsNullOrEmpty(targetTradeToken)) {
return await ArchiWebHandler.GetTradeHoldDurationForUser(steamID, targetTradeToken).ConfigureAwait(false);
}
@ -640,12 +673,14 @@ namespace ArchiSteamFarm {
internal async Task<(Dictionary<string, string> UnusedKeys, Dictionary<string, string> UsedKeys)> GetUsedAndUnusedKeys() {
IList<Dictionary<string, string>> results = await Utilities.InParallel(new[] { KeysToRedeemUnusedFilePath, KeysToRedeemUsedFilePath }.Select(GetKeysFromFile)).ConfigureAwait(false);
return (results[0], results[1]);
}
internal async Task IdleGame(CardsFarmer.Game game) {
if (game == null) {
ArchiLogger.LogNullError(nameof(game));
return;
}
@ -655,6 +690,7 @@ namespace ArchiSteamFarm {
internal async Task IdleGames(IReadOnlyCollection<CardsFarmer.Game> games) {
if ((games == null) || (games.Count == 0)) {
ArchiLogger.LogNullError(nameof(games));
return;
}
@ -664,6 +700,7 @@ namespace ArchiSteamFarm {
internal async Task ImportKeysToRedeem(string filePath) {
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath)) {
ArchiLogger.LogNullError(nameof(filePath));
return;
}
@ -686,6 +723,7 @@ namespace ArchiSteamFarm {
if (parsedArgs.Length < 1) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsInvalid, line));
continue;
}
@ -713,6 +751,7 @@ namespace ArchiSteamFarm {
internal static async Task InitializeSteamConfiguration(ProtocolTypes protocolTypes, uint cellID, IServerListProvider serverListProvider) {
if (serverListProvider == null) {
ASF.ArchiLogger.LogNullError(nameof(serverListProvider));
return;
}
@ -720,6 +759,7 @@ namespace ArchiSteamFarm {
// Ensure that we ask for a list of servers if we don't have any saved servers available
IEnumerable<ServerRecord> servers = await SteamConfiguration.ServerListProvider.FetchServerListAsync().ConfigureAwait(false);
if (servers?.Any() != true) {
ASF.ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory)));
@ -735,6 +775,7 @@ namespace ArchiSteamFarm {
internal bool IsBlacklistedFromIdling(uint appID) {
if (appID == 0) {
ArchiLogger.LogNullError(nameof(appID));
return false;
}
@ -744,6 +785,7 @@ namespace ArchiSteamFarm {
internal bool IsBlacklistedFromTrades(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -753,6 +795,7 @@ namespace ArchiSteamFarm {
internal bool IsFamilySharing(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -762,6 +805,7 @@ namespace ArchiSteamFarm {
internal bool IsMaster(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -771,6 +815,7 @@ namespace ArchiSteamFarm {
internal bool IsPriorityIdling(uint appID) {
if (appID == 0) {
ArchiLogger.LogNullError(nameof(appID));
return false;
}
@ -780,6 +825,7 @@ namespace ArchiSteamFarm {
internal async Task OnConfigChanged(bool deleted) {
if (deleted) {
Destroy();
return;
}
@ -787,6 +833,7 @@ namespace ArchiSteamFarm {
if (botConfig == null) {
Destroy();
return;
}
@ -825,6 +872,7 @@ namespace ArchiSteamFarm {
if (BotConfig.ShutdownOnFarmingFinished) {
if (farmedSomething || (Program.GlobalConfig.IdleFarmingPeriod == 0)) {
Stop();
return;
}
@ -850,11 +898,13 @@ namespace ArchiSteamFarm {
} catch (Exception e) {
ArchiLogger.LogGenericWarningException(e);
await Connect(true).ConfigureAwait(false);
return false;
}
if (string.IsNullOrEmpty(callback?.Nonce)) {
await Connect(true).ConfigureAwait(false);
return false;
}
@ -863,12 +913,14 @@ namespace ArchiSteamFarm {
}
await Connect(true).ConfigureAwait(false);
return false;
}
internal static async Task RegisterBot(string botName) {
if (string.IsNullOrEmpty(botName)) {
ASF.ArchiLogger.LogNullError(nameof(botName));
return;
}
@ -880,8 +932,10 @@ namespace ArchiSteamFarm {
string configFilePath = botPath + SharedInfo.ConfigExtension;
BotConfig botConfig = await BotConfig.Load(botPath + SharedInfo.ConfigExtension).ConfigureAwait(false);
if (botConfig == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorBotConfigInvalid, configFilePath));
return;
}
@ -892,8 +946,10 @@ namespace ArchiSteamFarm {
string databaseFilePath = botPath + SharedInfo.DatabaseExtension;
BotDatabase botDatabase = await BotDatabase.CreateOrLoad(databaseFilePath).ConfigureAwait(false);
if (botDatabase == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, databaseFilePath));
return;
}
@ -928,6 +984,7 @@ namespace ArchiSteamFarm {
internal async Task<bool> SendMessage(ulong steamID, string message) {
if ((steamID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(message));
return false;
}
@ -965,19 +1022,23 @@ namespace ArchiSteamFarm {
switch (result) {
case EResult.OK:
sent = true;
break;
case EResult.RateLimitExceeded:
case EResult.Timeout:
await Task.Delay(5000).ConfigureAwait(false);
continue;
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result), result));
return false;
}
}
if (!sent) {
ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
} finally {
@ -991,6 +1052,7 @@ namespace ArchiSteamFarm {
internal async Task<bool> SendMessage(ulong chatGroupID, ulong chatID, string message) {
if ((chatGroupID == 0) || (chatID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(message));
return false;
}
@ -1028,19 +1090,23 @@ namespace ArchiSteamFarm {
switch (result) {
case EResult.OK:
sent = true;
break;
case EResult.RateLimitExceeded:
case EResult.Timeout:
await Task.Delay(5000).ConfigureAwait(false);
continue;
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result), result));
return false;
}
}
if (!sent) {
ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return false;
}
} finally {
@ -1060,14 +1126,17 @@ namespace ArchiSteamFarm {
switch (inputType) {
case ASF.EUserInputType.DeviceID:
DeviceID = inputValue;
break;
case ASF.EUserInputType.Login:
if (BotConfig != null) {
BotConfig.SteamLogin = inputValue;
}
break;
case ASF.EUserInputType.Password:
if (BotConfig != null) {
BotConfig.DecryptedSteamPassword = inputValue;
}
@ -1075,8 +1144,10 @@ namespace ArchiSteamFarm {
break;
case ASF.EUserInputType.SteamGuard:
AuthCode = inputValue;
break;
case ASF.EUserInputType.SteamParentalCode:
if (BotConfig != null) {
BotConfig.SteamParentalCode = inputValue;
}
@ -1084,9 +1155,11 @@ namespace ArchiSteamFarm {
break;
case ASF.EUserInputType.TwoFactorAuthentication:
TwoFactorCode = inputValue;
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(inputType), inputType));
break;
}
}
@ -1132,6 +1205,7 @@ namespace ArchiSteamFarm {
internal static IOrderedDictionary ValidateGamesToRedeemInBackground(IOrderedDictionary gamesToRedeemInBackground) {
if ((gamesToRedeemInBackground == null) || (gamesToRedeemInBackground.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(gamesToRedeemInBackground));
return null;
}
@ -1141,6 +1215,7 @@ namespace ArchiSteamFarm {
bool invalid = false;
string key = game.Key as string;
if (string.IsNullOrEmpty(key)) {
invalid = true;
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsInvalid, nameof(key)));
@ -1150,6 +1225,7 @@ namespace ArchiSteamFarm {
}
string name = game.Value as string;
if (string.IsNullOrEmpty(name)) {
invalid = true;
ASF.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsInvalid, nameof(name)));
@ -1175,6 +1251,7 @@ namespace ArchiSteamFarm {
if (!IsPlayingPossible) {
ArchiLogger.LogGenericInfo(Strings.BotAccountOccupied);
PlayingWasBlocked = true;
return;
}
@ -1221,6 +1298,7 @@ namespace ArchiSteamFarm {
private static string Escape(string message) {
if (string.IsNullOrEmpty(message)) {
ASF.ArchiLogger.LogNullError(nameof(message));
return null;
}
@ -1230,6 +1308,7 @@ namespace ArchiSteamFarm {
private async Task<Dictionary<string, string>> GetKeysFromFile(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ArchiLogger.LogNullError(nameof(filePath));
return null;
}
@ -1249,14 +1328,18 @@ namespace ArchiSteamFarm {
}
string[] parsedArgs = line.Split(DefaultBackgroundKeysRedeemerSeparator, StringSplitOptions.RemoveEmptyEntries);
if (parsedArgs.Length < 3) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsInvalid, line));
continue;
}
string key = parsedArgs[parsedArgs.Length - 1];
if (!Utilities.IsValidCdKey(key)) {
ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsInvalid, key));
continue;
}
@ -1268,12 +1351,14 @@ namespace ArchiSteamFarm {
return keys;
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return null;
}
}
private void HandleCallbacks() {
TimeSpan timeSpan = TimeSpan.FromMilliseconds(CallbackSleep);
while (KeepRunning || SteamClient.IsConnected) {
if (!CallbackSemaphore.Wait(0)) {
if (Debugging.IsUserDebugging) {
@ -1296,6 +1381,7 @@ namespace ArchiSteamFarm {
private async Task HandleMessage(ulong chatGroupID, ulong chatID, ulong steamID, string message) {
if ((chatGroupID == 0) || (chatID == 0) || (steamID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(chatGroupID) + " || " + nameof(chatID) + " || " + nameof(steamID) + " || " + nameof(message));
return;
}
@ -1312,6 +1398,7 @@ namespace ArchiSteamFarm {
private async Task HandleMessage(ulong steamID, string message) {
if ((steamID == 0) || string.IsNullOrEmpty(message)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(message));
return;
}
@ -1368,11 +1455,13 @@ namespace ArchiSteamFarm {
File.Delete(maFilePath);
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
return;
}
if (BotDatabase.MobileAuthenticator == null) {
ArchiLogger.LogNullError(nameof(BotDatabase.MobileAuthenticator));
return;
}
@ -1380,10 +1469,13 @@ namespace ArchiSteamFarm {
if (!BotDatabase.MobileAuthenticator.HasCorrectDeviceID) {
ArchiLogger.LogGenericWarning(Strings.BotAuthenticatorInvalidDeviceID);
if (string.IsNullOrEmpty(DeviceID)) {
string deviceID = Program.GetUserInput(ASF.EUserInputType.DeviceID, BotName);
if (string.IsNullOrEmpty(deviceID)) {
await BotDatabase.SetMobileAuthenticator().ConfigureAwait(false);
return;
}
@ -1411,6 +1503,7 @@ namespace ArchiSteamFarm {
private async Task InitializeFamilySharing() {
HashSet<ulong> steamIDs = await ArchiWebHandler.GetFamilySharingSteamIDs().ConfigureAwait(false);
if ((steamIDs == null) || (steamIDs.Count == 0)) {
return;
}
@ -1421,6 +1514,7 @@ namespace ArchiSteamFarm {
private bool InitLoginAndPassword(bool requiresPassword) {
if (string.IsNullOrEmpty(BotConfig.SteamLogin)) {
string steamLogin = Program.GetUserInput(ASF.EUserInputType.Login, BotName);
if (string.IsNullOrEmpty(steamLogin)) {
return false;
}
@ -1430,6 +1524,7 @@ namespace ArchiSteamFarm {
if (requiresPassword && string.IsNullOrEmpty(BotConfig.DecryptedSteamPassword)) {
string steamPassword = Program.GetUserInput(ASF.EUserInputType.Password, BotName);
if (string.IsNullOrEmpty(steamPassword)) {
return false;
}
@ -1480,6 +1575,7 @@ namespace ArchiSteamFarm {
private void InitStart() {
if (!BotConfig.Enabled) {
ArchiLogger.LogGenericInfo(Strings.BotInstanceNotStartingBecauseDisabled);
return;
}
@ -1490,6 +1586,7 @@ namespace ArchiSteamFarm {
private bool IsMasterClanID(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -1499,6 +1596,7 @@ namespace ArchiSteamFarm {
private static bool IsRefundable(EPaymentMethod method) {
if (method == EPaymentMethod.None) {
ASF.ArchiLogger.LogNullError(nameof(method));
return false;
}
@ -1507,8 +1605,10 @@ namespace ArchiSteamFarm {
case EPaymentMethod.Complimentary: // This is also a flag
case EPaymentMethod.GuestPass:
case EPaymentMethod.HardwarePromo:
return false;
default:
if (method.HasFlag(EPaymentMethod.Complimentary)) {
return false;
}
@ -1545,6 +1645,7 @@ namespace ArchiSteamFarm {
}
await LoginSemaphore.WaitAsync().ConfigureAwait(false);
Utilities.InBackground(
async () => {
await Task.Delay(Program.GlobalConfig.LoginLimiterDelay * 1000).ConfigureAwait(false);
@ -1556,6 +1657,7 @@ namespace ArchiSteamFarm {
private async void OnConnected(SteamClient.ConnectedCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -1568,6 +1670,7 @@ namespace ArchiSteamFarm {
if (!KeepRunning) {
ArchiLogger.LogGenericInfo(Strings.BotDisconnecting);
Disconnect();
return;
}
@ -1607,6 +1710,7 @@ namespace ArchiSteamFarm {
if (!InitLoginAndPassword(string.IsNullOrEmpty(loginKey))) {
Stop();
return;
}
@ -1614,8 +1718,8 @@ namespace ArchiSteamFarm {
const string nonAsciiPattern = @"[^\u0000-\u007F]+";
string username = Regex.Replace(BotConfig.SteamLogin, nonAsciiPattern, "", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
string password = BotConfig.DecryptedSteamPassword;
if (!string.IsNullOrEmpty(password)) {
password = Regex.Replace(password, nonAsciiPattern, "", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}
@ -1647,6 +1751,7 @@ namespace ArchiSteamFarm {
private async void OnDisconnected(SteamClient.DisconnectedCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -1672,14 +1777,18 @@ 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;
@ -1687,16 +1796,19 @@ namespace ArchiSteamFarm {
await BotDatabase.SetLoginKey().ConfigureAwait(false);
ArchiLogger.LogGenericInfo(Strings.BotRemovedExpiredLoginKey);
break;
case EResult.NoConnection:
case EResult.ServiceUnavailable:
case EResult.Timeout:
case EResult.TryAnotherCM:
await Task.Delay(5000).ConfigureAwait(false);
break;
case EResult.RateLimitExceeded:
ArchiLogger.LogGenericInfo(string.Format(Strings.BotRateLimitExceeded, TimeSpan.FromMinutes(LoginCooldownInMinutes).ToHumanReadable()));
await Task.Delay(LoginCooldownInMinutes * 60 * 1000).ConfigureAwait(false);
break;
}
@ -1711,6 +1823,7 @@ namespace ArchiSteamFarm {
private async void OnFriendsList(SteamFriends.FriendsListCallback callback) {
if (callback?.FriendList == null) {
ArchiLogger.LogNullError(nameof(callback) + " || " + nameof(callback.FriendList));
return;
}
@ -1719,14 +1832,17 @@ namespace ArchiSteamFarm {
case EAccountType.Clan when IsMasterClanID(friend.SteamID):
ArchiHandler.AcknowledgeClanInvite(friend.SteamID, true);
await JoinMasterChatGroupID().ConfigureAwait(false);
break;
case EAccountType.Clan:
if (BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidGroupInvites)) {
ArchiHandler.AcknowledgeClanInvite(friend.SteamID, false);
}
break;
default:
if (IsFamilySharing(friend.SteamID)) {
await ArchiHandler.AddFriend(friend.SteamID).ConfigureAwait(false);
} else if (BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidFriendInvites)) {
@ -1741,6 +1857,7 @@ namespace ArchiSteamFarm {
private async void OnGuestPassList(SteamApps.GuestPassListCallback callback) {
if (callback?.GuestPasses == null) {
ArchiLogger.LogNullError(nameof(callback) + " || " + nameof(callback.GuestPasses));
return;
}
@ -1749,6 +1866,7 @@ namespace ArchiSteamFarm {
}
HashSet<ulong> guestPassIDs = callback.GuestPasses.Select(guestPass => guestPass["gid"].AsUnsignedLong()).Where(gid => gid != 0).ToHashSet();
if (guestPassIDs.Count == 0) {
return;
}
@ -1759,6 +1877,7 @@ namespace ArchiSteamFarm {
private async Task OnIncomingChatMessage(CChatRoom_IncomingChatMessage_Notification notification) {
if (notification == null) {
ArchiLogger.LogNullError(nameof(notification));
return;
}
@ -1794,6 +1913,7 @@ namespace ArchiSteamFarm {
private async Task OnIncomingMessage(CFriendMessages_IncomingMessage_Notification notification) {
if (notification == null) {
ArchiLogger.LogNullError(nameof(notification));
return;
}
@ -1833,6 +1953,7 @@ namespace ArchiSteamFarm {
private async void OnLicenseList(SteamApps.LicenseListCallback callback) {
if (callback?.LicenseList == null) {
ArchiLogger.LogNullError(nameof(callback) + " || " + nameof(callback.LicenseList));
return;
}
@ -1881,6 +2002,7 @@ namespace ArchiSteamFarm {
private void OnLoggedOff(SteamUser.LoggedOffCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -1890,8 +2012,10 @@ namespace ArchiSteamFarm {
switch (callback.Result) {
case EResult.LoggedInElsewhere:
// This result directly indicates that playing was blocked when we got (forcefully) disconnected
PlayingWasBlocked = true;
break;
case EResult.LogonSessionReplaced:
DateTime now = DateTime.UtcNow;
@ -1899,10 +2023,12 @@ namespace ArchiSteamFarm {
if (now.Subtract(LastLogonSessionReplaced).TotalHours < 1) {
ArchiLogger.LogGenericError(Strings.BotLogonSessionReplaced);
Stop();
return;
}
LastLogonSessionReplaced = now;
break;
}
@ -1913,6 +2039,7 @@ namespace ArchiSteamFarm {
private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -1927,24 +2054,32 @@ 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();
break;
case EResult.AccountLogonDenied:
string authCode = Program.GetUserInput(ASF.EUserInputType.SteamGuard, BotName);
if (string.IsNullOrEmpty(authCode)) {
Stop();
break;
}
SetUserInput(ASF.EUserInputType.SteamGuard, authCode);
break;
case EResult.AccountLoginDeniedNeedTwoFactor:
if (!HasMobileAuthenticator) {
string twoFactorCode = Program.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName);
if (string.IsNullOrEmpty(twoFactorCode)) {
Stop();
break;
}
@ -1986,6 +2121,7 @@ namespace ArchiSteamFarm {
if (!HasMobileAuthenticator) {
// Support and convert 2FA files
string maFilePath = Path.Combine(SharedInfo.ConfigDirectory, callback.ClientSteamID.ConvertToUInt64() + ".maFile");
if (File.Exists(maFilePath)) {
await ImportAuthenticator(maFilePath).ConfigureAwait(false);
}
@ -1993,8 +2129,10 @@ namespace ArchiSteamFarm {
if (!string.IsNullOrEmpty(BotConfig.SteamParentalCode) && (BotConfig.SteamParentalCode.Length != 4)) {
string steamParentalCode = Program.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName);
if (string.IsNullOrEmpty(steamParentalCode) || (steamParentalCode.Length != 4)) {
Stop();
break;
}
@ -2065,9 +2203,11 @@ namespace ArchiSteamFarm {
break;
default:
// Unexpected result, shutdown immediately
ArchiLogger.LogGenericError(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult));
Stop();
break;
}
}
@ -2075,6 +2215,7 @@ namespace ArchiSteamFarm {
private async void OnLoginKey(SteamUser.LoginKeyCallback callback) {
if (string.IsNullOrEmpty(callback?.LoginKey)) {
ArchiLogger.LogNullError(nameof(callback) + " || " + nameof(callback.LoginKey));
return;
}
@ -2083,6 +2224,7 @@ namespace ArchiSteamFarm {
}
string loginKey = callback.LoginKey;
if (BotConfig.PasswordFormat != ArchiCryptoHelper.ECryptoMethod.PlainText) {
loginKey = ArchiCryptoHelper.Encrypt(BotConfig.PasswordFormat, loginKey);
}
@ -2094,6 +2236,7 @@ namespace ArchiSteamFarm {
private void OnMachineAuth(SteamUser.UpdateMachineAuthCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2107,6 +2250,7 @@ namespace ArchiSteamFarm {
fileSize = (int) fileStream.Length;
fileStream.Seek(0, SeekOrigin.Begin);
using (SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider()) {
sentryHash = sha.ComputeHash(fileStream);
}
@ -2142,6 +2286,7 @@ namespace ArchiSteamFarm {
private async void OnPersonaState(SteamFriends.PersonaStateCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2171,6 +2316,7 @@ namespace ArchiSteamFarm {
private async void OnPlayingSessionState(ArchiHandler.PlayingSessionStateCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2185,15 +2331,18 @@ namespace ArchiSteamFarm {
private async void OnServiceMethod(SteamUnifiedMessages.ServiceMethodNotification notification) {
if (notification == null) {
ArchiLogger.LogNullError(nameof(notification));
return;
}
switch (notification.MethodName) {
case "ChatRoomClient.NotifyIncomingChatMessage#1":
await OnIncomingChatMessage((CChatRoom_IncomingChatMessage_Notification) notification.Body).ConfigureAwait(false);
break;
case "FriendMessagesClient.IncomingMessage#1":
await OnIncomingMessage((CFriendMessages_IncomingMessage_Notification) notification.Body).ConfigureAwait(false);
break;
}
}
@ -2201,6 +2350,7 @@ namespace ArchiSteamFarm {
private async void OnSharedLibraryLockStatus(ArchiHandler.SharedLibraryLockStatusCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2229,6 +2379,7 @@ namespace ArchiSteamFarm {
private void OnUserNotifications(ArchiHandler.UserNotificationsCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2279,6 +2430,7 @@ namespace ArchiSteamFarm {
private void OnVanityURLChangedCallback(ArchiHandler.VanityURLChangedCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2288,6 +2440,7 @@ namespace ArchiSteamFarm {
private void OnWalletUpdate(SteamUser.WalletInfoCallback callback) {
if (callback == null) {
ArchiLogger.LogNullError(nameof(callback));
return;
}
@ -2311,12 +2464,15 @@ namespace ArchiSteamFarm {
while (IsConnectedAndLoggedOn && BotDatabase.HasGamesToRedeemInBackground) {
(string key, string name) = BotDatabase.GetGameToRedeemInBackground();
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(name)) {
ArchiLogger.LogNullError(nameof(key) + " || " + nameof(name));
break;
}
ArchiHandler.PurchaseResponseCallback result = await Actions.RedeemKey(key).ConfigureAwait(false);
if (result == null) {
continue;
}
@ -2346,17 +2502,21 @@ namespace ArchiSteamFarm {
case EPurchaseResultDetail.DoesNotOwnRequiredApp:
case EPurchaseResultDetail.RestrictedCountry:
case EPurchaseResultDetail.Timeout:
break;
case EPurchaseResultDetail.BadActivationCode:
case EPurchaseResultDetail.DuplicateActivationCode:
case EPurchaseResultDetail.NoDetail: // OK
redeemed = true;
break;
case EPurchaseResultDetail.RateLimited:
rateLimited = true;
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result.PurchaseResultDetail), result.PurchaseResultDetail));
break;
}
@ -2378,6 +2538,7 @@ namespace ArchiSteamFarm {
} catch (Exception e) {
ArchiLogger.LogGenericException(e);
ArchiLogger.LogGenericError(string.Format(Strings.Content, logEntry));
break;
}
}
@ -2442,6 +2603,7 @@ namespace ArchiSteamFarm {
private static string UnEscape(string message) {
if (string.IsNullOrEmpty(message)) {
ASF.ArchiLogger.LogNullError(nameof(message));
return null;
}

View file

@ -153,8 +153,10 @@ namespace ArchiSteamFarm {
}
string decryptedPassword = ArchiCryptoHelper.Decrypt(PasswordFormat, SteamPassword);
if (string.IsNullOrEmpty(decryptedPassword)) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SteamPassword)));
return null;
}
@ -163,6 +165,7 @@ namespace ArchiSteamFarm {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
@ -179,6 +182,7 @@ namespace ArchiSteamFarm {
[JsonProperty]
internal string SteamLogin {
get => _SteamLogin;
set {
IsSteamLoginSet = true;
_SteamLogin = value;
@ -191,6 +195,7 @@ namespace ArchiSteamFarm {
[JsonProperty]
internal string SteamParentalCode {
get => _SteamParentalCode;
set {
IsSteamParentalCodeSet = true;
_SteamParentalCode = value;
@ -200,6 +205,7 @@ namespace ArchiSteamFarm {
[JsonProperty]
internal string SteamPassword {
get => _SteamPassword;
set {
IsSteamPasswordSet = true;
_SteamPassword = value;
@ -214,9 +220,11 @@ namespace ArchiSteamFarm {
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamMasterClanID), Required = Required.DisallowNull)]
private string SSteamMasterClanID {
get => SteamMasterClanID.ToString();
set {
if (string.IsNullOrEmpty(value) || !ulong.TryParse(value, out ulong result)) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SSteamMasterClanID)));
return;
}
@ -281,6 +289,7 @@ namespace ArchiSteamFarm {
internal static async Task<BotConfig> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
}
@ -294,28 +303,34 @@ namespace ArchiSteamFarm {
botConfig = JsonConvert.DeserializeObject<BotConfig>(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
if (botConfig == null) {
ASF.ArchiLogger.LogNullError(nameof(botConfig));
return null;
}
(bool valid, string errorMessage) = botConfig.CheckValidation();
if (!valid) {
ASF.ArchiLogger.LogGenericError(errorMessage);
return null;
}
botConfig.ShouldSerializeEverything = false;
botConfig.ShouldSerializeSensitiveDetails = false;
return botConfig;
}
internal static async Task<bool> Write(string filePath, BotConfig botConfig) {
if (string.IsNullOrEmpty(filePath) || (botConfig == null)) {
ASF.ArchiLogger.LogNullError(nameof(filePath) + " || " + nameof(botConfig));
return false;
}
@ -334,6 +349,7 @@ namespace ArchiSteamFarm {
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return false;
} finally {
WriteSemaphore.Release();

View file

@ -79,6 +79,7 @@ namespace ArchiSteamFarm {
internal async Task AddBlacklistedFromTradesSteamIDs(IReadOnlyCollection<ulong> steamIDs) {
if ((steamIDs == null) || (steamIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(steamIDs));
return;
}
@ -90,6 +91,7 @@ namespace ArchiSteamFarm {
internal async Task AddGamesToRedeemInBackground(IOrderedDictionary games) {
if ((games == null) || (games.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(games));
return;
}
@ -114,6 +116,7 @@ namespace ArchiSteamFarm {
internal async Task AddIdlingBlacklistedAppIDs(IReadOnlyCollection<uint> appIDs) {
if ((appIDs == null) || (appIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(appIDs));
return;
}
@ -125,6 +128,7 @@ namespace ArchiSteamFarm {
internal async Task AddIdlingPriorityAppIDs(IReadOnlyCollection<uint> appIDs) {
if ((appIDs == null) || (appIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(appIDs));
return;
}
@ -136,6 +140,7 @@ namespace ArchiSteamFarm {
internal async Task CorrectMobileAuthenticatorDeviceID(string deviceID) {
if (string.IsNullOrEmpty(deviceID) || (MobileAuthenticator == null)) {
ASF.ArchiLogger.LogNullError(nameof(deviceID) + " || " + nameof(MobileAuthenticator));
return;
}
@ -147,6 +152,7 @@ namespace ArchiSteamFarm {
internal static async Task<BotDatabase> CreateOrLoad(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
}
@ -160,15 +166,18 @@ namespace ArchiSteamFarm {
botDatabase = JsonConvert.DeserializeObject<BotDatabase>(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
if (botDatabase == null) {
ASF.ArchiLogger.LogNullError(nameof(botDatabase));
return null;
}
botDatabase.FilePath = filePath;
return botDatabase;
}
@ -190,6 +199,7 @@ namespace ArchiSteamFarm {
internal bool IsBlacklistedFromIdling(uint appID) {
if (appID == 0) {
ASF.ArchiLogger.LogNullError(nameof(appID));
return false;
}
@ -199,6 +209,7 @@ namespace ArchiSteamFarm {
internal bool IsBlacklistedFromTrades(ulong steamID) {
if (steamID == 0) {
ASF.ArchiLogger.LogNullError(nameof(steamID));
return false;
}
@ -208,6 +219,7 @@ namespace ArchiSteamFarm {
internal bool IsPriorityIdling(uint appID) {
if (appID == 0) {
ASF.ArchiLogger.LogNullError(nameof(appID));
return false;
}
@ -235,6 +247,7 @@ namespace ArchiSteamFarm {
internal async Task RemoveBlacklistedFromTradesSteamIDs(IReadOnlyCollection<ulong> steamIDs) {
if ((steamIDs == null) || (steamIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(steamIDs));
return;
}
@ -246,6 +259,7 @@ namespace ArchiSteamFarm {
internal async Task RemoveGameToRedeemInBackground(string key) {
if (string.IsNullOrEmpty(key)) {
ASF.ArchiLogger.LogNullError(nameof(key));
return;
}
@ -263,6 +277,7 @@ namespace ArchiSteamFarm {
internal async Task RemoveIdlingBlacklistedAppIDs(IReadOnlyCollection<uint> appIDs) {
if ((appIDs == null) || (appIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(appIDs));
return;
}
@ -274,6 +289,7 @@ namespace ArchiSteamFarm {
internal async Task RemoveIdlingPriorityAppIDs(IReadOnlyCollection<uint> appIDs) {
if ((appIDs == null) || (appIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(appIDs));
return;
}
@ -306,8 +322,10 @@ namespace ArchiSteamFarm {
}
string json = JsonConvert.SerializeObject(this);
if (string.IsNullOrEmpty(json)) {
ASF.ArchiLogger.LogNullError(nameof(json));
return;
}

View file

@ -31,6 +31,7 @@ namespace ArchiSteamFarm.CMsgs {
void ISteamSerializable.Deserialize(Stream stream) {
if (stream == null) {
ASF.ArchiLogger.LogNullError(nameof(stream));
return;
}
@ -44,6 +45,7 @@ namespace ArchiSteamFarm.CMsgs {
void ISteamSerializable.Serialize(Stream stream) {
if (stream == null) {
ASF.ArchiLogger.LogNullError(nameof(stream));
return;
}

View file

@ -135,6 +135,7 @@ namespace ArchiSteamFarm {
// If we're not farming yet, obviously it's worth it to make a check
if (!NowFarming) {
await StartFarming().ConfigureAwait(false);
return;
}
@ -192,6 +193,7 @@ namespace ArchiSteamFarm {
if (PermanentlyPaused) {
if (!userAction) {
Bot.ArchiLogger.LogGenericInfo(Strings.IgnoredPermanentPauseEnabled);
return false;
}
@ -209,6 +211,7 @@ namespace ArchiSteamFarm {
}
await StartFarming().ConfigureAwait(false);
return true;
}
@ -224,6 +227,7 @@ namespace ArchiSteamFarm {
if (!Bot.CanReceiveSteamCards) {
await Bot.OnFarmingFinished(false).ConfigureAwait(false);
return;
}
@ -235,24 +239,28 @@ namespace ArchiSteamFarm {
}
bool? isAnythingToFarm = await IsAnythingToFarm().ConfigureAwait(false);
if (isAnythingToFarm == null) {
if (!isAnythingToFarm.HasValue) {
return;
}
if (!isAnythingToFarm.Value) {
Bot.ArchiLogger.LogGenericInfo(Strings.NothingToIdle);
await Bot.OnFarmingFinished(false).ConfigureAwait(false);
return;
}
if (GamesToFarm.Count == 0) {
Bot.ArchiLogger.LogNullError(nameof(GamesToFarm));
return;
}
// This is the last moment for final check if we can farm
if (!Bot.IsPlayingPossible) {
Bot.ArchiLogger.LogGenericInfo(Strings.PlayingNotAvailable);
return;
}
@ -263,6 +271,7 @@ namespace ArchiSteamFarm {
if (!Bot.IsPlayingPossible) {
Bot.ArchiLogger.LogGenericInfo(Strings.PlayingNotAvailable);
return;
}
}
@ -310,12 +319,15 @@ namespace ArchiSteamFarm {
private async Task CheckGame(uint appID, string name, float hours, byte badgeLevel) {
if ((appID == 0) || string.IsNullOrEmpty(name) || (hours < 0)) {
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(name) + " || " + nameof(hours));
return;
}
ushort? cardsRemaining = await GetCardsRemaining(appID).ConfigureAwait(false);
if (!cardsRemaining.HasValue) {
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningCouldNotCheckCardsStatus, appID, name));
return;
}
@ -337,10 +349,12 @@ namespace ArchiSteamFarm {
private async Task CheckPage(HtmlDocument htmlDocument) {
if (htmlDocument == null) {
Bot.ArchiLogger.LogNullError(nameof(htmlDocument));
return;
}
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='badge_row_inner']");
if (htmlNodes == null) {
// No eligible badges whatsoever
return;
@ -350,22 +364,26 @@ namespace ArchiSteamFarm {
foreach (HtmlNode htmlNode in htmlNodes) {
HtmlNode statsNode = htmlNode.SelectSingleNode(".//div[@class='badge_title_stats_content']");
HtmlNode appIDNode = statsNode?.SelectSingleNode(".//div[@class='card_drop_info_dialog']");
if (appIDNode == null) {
// It's just a badge, nothing more
continue;
}
string appIDText = appIDNode.GetAttributeValue("id", null);
if (string.IsNullOrEmpty(appIDText)) {
Bot.ArchiLogger.LogNullError(nameof(appIDText));
continue;
}
string[] appIDSplitted = appIDText.Split('_');
if (appIDSplitted.Length < 5) {
Bot.ArchiLogger.LogNullError(nameof(appIDSplitted));
continue;
}
@ -373,6 +391,7 @@ namespace ArchiSteamFarm {
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
Bot.ArchiLogger.LogNullError(nameof(appID));
continue;
}
@ -393,14 +412,18 @@ namespace ArchiSteamFarm {
// Cards
HtmlNode progressNode = statsNode.SelectSingleNode(".//span[@class='progress_info_bold']");
if (progressNode == null) {
Bot.ArchiLogger.LogNullError(nameof(progressNode));
continue;
}
string progressText = progressNode.InnerText;
if (string.IsNullOrEmpty(progressText)) {
Bot.ArchiLogger.LogNullError(nameof(progressText));
continue;
}
@ -411,6 +434,7 @@ namespace ArchiSteamFarm {
if (progressMatch.Success) {
if (!ushort.TryParse(progressMatch.Value, out cardsRemaining) || (cardsRemaining == 0)) {
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
continue;
}
}
@ -427,25 +451,32 @@ namespace ArchiSteamFarm {
// To save us on extra work, check cards earned so far first
HtmlNode cardsEarnedNode = statsNode.SelectSingleNode(".//div[@class='card_drop_info_header']");
if (cardsEarnedNode == null) {
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedNode));
continue;
}
string cardsEarnedText = cardsEarnedNode.InnerText;
if (string.IsNullOrEmpty(cardsEarnedText)) {
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedText));
continue;
}
Match cardsEarnedMatch = Regex.Match(cardsEarnedText, @"\d+");
if (!cardsEarnedMatch.Success) {
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedMatch));
continue;
}
if (!ushort.TryParse(cardsEarnedMatch.Value, out ushort cardsEarned)) {
Bot.ArchiLogger.LogNullError(nameof(cardsEarned));
continue;
}
@ -465,14 +496,18 @@ namespace ArchiSteamFarm {
// Hours
HtmlNode timeNode = statsNode.SelectSingleNode(".//div[@class='badge_title_stats_playtime']");
if (timeNode == null) {
Bot.ArchiLogger.LogNullError(nameof(timeNode));
continue;
}
string hoursText = timeNode.InnerText;
if (string.IsNullOrEmpty(hoursText)) {
Bot.ArchiLogger.LogNullError(nameof(hoursText));
continue;
}
@ -483,29 +518,37 @@ namespace ArchiSteamFarm {
if (hoursMatch.Success) {
if (!float.TryParse(hoursMatch.Value, NumberStyles.Number, CultureInfo.InvariantCulture, out hours) || (hours <= 0.0F)) {
Bot.ArchiLogger.LogNullError(nameof(hours));
continue;
}
}
// Names
HtmlNode nameNode = statsNode.SelectSingleNode("(.//div[@class='card_drop_info_body'])[last()]");
if (nameNode == null) {
Bot.ArchiLogger.LogNullError(nameof(nameNode));
continue;
}
string name = nameNode.InnerText;
if (string.IsNullOrEmpty(name)) {
Bot.ArchiLogger.LogNullError(nameof(name));
continue;
}
// We handle two cases here - normal one, and no card drops remaining
int nameStartIndex = name.IndexOf(" by playing ", StringComparison.Ordinal);
if (nameStartIndex <= 0) {
nameStartIndex = name.IndexOf("You don't have any more drops remaining for ", StringComparison.Ordinal);
if (nameStartIndex <= 0) {
Bot.ArchiLogger.LogNullError(nameof(nameStartIndex));
continue;
}
@ -515,8 +558,10 @@ namespace ArchiSteamFarm {
nameStartIndex += 12;
int nameEndIndex = name.LastIndexOf('.');
if (nameEndIndex <= nameStartIndex) {
Bot.ArchiLogger.LogNullError(nameof(nameEndIndex));
continue;
}
@ -526,29 +571,38 @@ namespace ArchiSteamFarm {
byte badgeLevel = 0;
HtmlNode levelNode = htmlNode.SelectSingleNode(".//div[@class='badge_info_description']/div[2]");
if (levelNode != null) {
// There is no levelNode if we didn't craft that badge yet (level 0)
string levelText = levelNode.InnerText;
if (string.IsNullOrEmpty(levelText)) {
Bot.ArchiLogger.LogNullError(nameof(levelText));
continue;
}
int levelIndex = levelText.IndexOf("Level ", StringComparison.OrdinalIgnoreCase);
if (levelIndex < 0) {
Bot.ArchiLogger.LogNullError(nameof(levelIndex));
continue;
}
levelIndex += 6;
if (levelText.Length <= levelIndex) {
Bot.ArchiLogger.LogNullError(nameof(levelIndex));
continue;
}
levelText = levelText.Substring(levelIndex, 1);
if (!byte.TryParse(levelText, out badgeLevel) || (badgeLevel == 0) || (badgeLevel > 5)) {
Bot.ArchiLogger.LogNullError(nameof(badgeLevel));
continue;
}
}
@ -564,13 +618,16 @@ namespace ArchiSteamFarm {
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
await task.ConfigureAwait(false);
break;
default:
if (backgroundTasks == null) {
backgroundTasks = new List<Task>();
}
backgroundTasks.Add(task);
break;
}
}
@ -585,10 +642,12 @@ namespace ArchiSteamFarm {
private async Task CheckPage(byte page) {
if (page == 0) {
Bot.ArchiLogger.LogNullError(nameof(page));
return;
}
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(page).ConfigureAwait(false);
if (htmlDocument == null) {
return;
}
@ -616,15 +675,18 @@ namespace ArchiSteamFarm {
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
innerGamesToFarm.Remove(game);
continue;
}
if (await FarmSolo(game).ConfigureAwait(false)) {
innerGamesToFarm.Remove(game);
continue;
}
NowFarming = false;
return;
}
@ -635,6 +697,7 @@ namespace ArchiSteamFarm {
foreach (Game game in GamesToFarm.OrderByDescending(game => game.HoursPlayed).ToList()) {
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue;
}
@ -656,6 +719,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", innerGamesToFarm.Select(game => game.AppID))));
} else {
NowFarming = false;
return;
}
}
@ -669,6 +733,7 @@ namespace ArchiSteamFarm {
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue;
}
@ -677,6 +742,7 @@ namespace ArchiSteamFarm {
}
NowFarming = false;
return;
}
}
@ -691,6 +757,7 @@ namespace ArchiSteamFarm {
private async Task<bool> FarmCards(Game game) {
if (game == null) {
Bot.ArchiLogger.LogNullError(nameof(game));
return false;
}
@ -707,6 +774,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName));
DateTime startFarmingPeriod = DateTime.UtcNow;
if (await FarmingResetSemaphore.WaitAsync(Program.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) {
success = KeepFarming;
}
@ -720,39 +788,47 @@ namespace ArchiSteamFarm {
}
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StoppedIdling, game.AppID, game.GameName));
return success;
}
private async Task<bool> FarmHours(IReadOnlyCollection<Game> games) {
if ((games == null) || (games.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(games));
return false;
}
float maxHour = games.Max(game => game.HoursPlayed);
if (maxHour < 0) {
Bot.ArchiLogger.LogNullError(nameof(maxHour));
return false;
}
if (maxHour >= Bot.BotConfig.HoursUntilCardDrops) {
Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(maxHour)));
return true;
}
await Bot.IdleGames(games).ConfigureAwait(false);
bool success = true;
while (maxHour < Bot.BotConfig.HoursUntilCardDrops) {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdlingList, string.Join(", ", games.Select(game => game.AppID))));
DateTime startFarmingPeriod = DateTime.UtcNow;
if (await FarmingResetSemaphore.WaitAsync(Program.GlobalConfig.FarmingDelay * 60 * 1000 + ExtraFarmingDelaySeconds * 1000).ConfigureAwait(false)) {
success = KeepFarming;
}
// Don't forget to update our GamesToFarm hours
float timePlayed = (float) DateTime.UtcNow.Subtract(startFarmingPeriod).TotalHours;
foreach (Game game in games) {
game.HoursPlayed += timePlayed;
}
@ -765,12 +841,14 @@ namespace ArchiSteamFarm {
}
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StoppedIdlingList, string.Join(", ", games.Select(game => game.AppID))));
return success;
}
private async Task<bool> FarmMultiple(IReadOnlyCollection<Game> games) {
if ((games == null) || (games.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(games));
return false;
}
@ -780,12 +858,14 @@ namespace ArchiSteamFarm {
bool result = await FarmHours(games).ConfigureAwait(false);
CurrentGamesFarming.Clear();
return result;
}
private async Task<bool> FarmSolo(Game game) {
if (game == null) {
Bot.ArchiLogger.LogNullError(nameof(game));
return true;
}
@ -803,35 +883,42 @@ namespace ArchiSteamFarm {
GamesToFarm.Remove(game);
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGame, game.AppID, game.GameName, TimeSpan.FromHours(game.HoursPlayed).ToHumanReadable()));
return true;
}
private async Task<ushort?> GetCardsRemaining(uint appID) {
if (appID == 0) {
Bot.ArchiLogger.LogNullError(nameof(appID));
return 0;
}
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
HtmlNode progressNode = htmlDocument?.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
if (progressNode == null) {
return null;
}
string progress = progressNode.InnerText;
if (string.IsNullOrEmpty(progress)) {
Bot.ArchiLogger.LogNullError(nameof(progress));
return null;
}
Match match = Regex.Match(progress, @"\d+");
if (!match.Success) {
return 0;
}
if (!ushort.TryParse(match.Value, out ushort cardsRemaining) || (cardsRemaining == 0)) {
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
return null;
}
@ -842,23 +929,29 @@ namespace ArchiSteamFarm {
// Find the number of badge pages
Bot.ArchiLogger.LogGenericInfo(Strings.CheckingFirstBadgePage);
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetBadgePage(1).ConfigureAwait(false);
if (htmlDocument == null) {
Bot.ArchiLogger.LogGenericWarning(Strings.WarningCouldNotCheckBadges);
return null;
}
byte maxPages = 1;
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("(//a[@class='pagelink'])[last()]");
if (htmlNode != null) {
string lastPage = htmlNode.InnerText;
if (string.IsNullOrEmpty(lastPage)) {
Bot.ArchiLogger.LogNullError(nameof(lastPage));
return null;
}
if (!byte.TryParse(lastPage, out maxPages) || (maxPages == 0)) {
Bot.ArchiLogger.LogNullError(nameof(maxPages));
return null;
}
}
@ -894,46 +987,56 @@ namespace ArchiSteamFarm {
}
await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
if (GamesToFarm.Count == 0) {
ShouldResumeFarming = false;
return false;
}
ShouldResumeFarming = true;
await SortGamesToFarm().ConfigureAwait(false);
return true;
}
private async Task<bool> IsPlayableGame(Game game) {
(uint playableAppID, DateTime ignoredUntil) = await Bot.GetAppDataForIdling(game.AppID, game.HoursPlayed).ConfigureAwait(false);
if (playableAppID == 0) {
IgnoredAppIDs[game.AppID] = ignoredUntil < DateTime.MaxValue ? ignoredUntil : DateTime.UtcNow.AddHours(HoursToIgnore);
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingGameNotPossible, game.AppID, game.GameName));
return false;
}
game.PlayableAppID = playableAppID;
return true;
}
private async Task<bool?> ShouldFarm(Game game) {
if (game == null) {
Bot.ArchiLogger.LogNullError(nameof(game));
return false;
}
ushort? cardsRemaining = await GetCardsRemaining(game.AppID).ConfigureAwait(false);
if (!cardsRemaining.HasValue) {
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningCouldNotCheckCardsStatus, game.AppID, game.GameName));
return null;
}
game.CardsRemaining = cardsRemaining.Value;
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingStatusForGame, game.AppID, game.GameName, game.CardsRemaining));
return game.CardsRemaining > 0;
}
@ -944,24 +1047,31 @@ 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);
break;
case BotConfig.EFarmingOrder.AppIDsDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => game.AppID);
break;
case BotConfig.EFarmingOrder.BadgeLevelsAscending:
gamesToFarm = gamesToFarm.ThenBy(game => game.BadgeLevel);
break;
case BotConfig.EFarmingOrder.BadgeLevelsDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => game.BadgeLevel);
break;
case BotConfig.EFarmingOrder.CardDropsAscending:
gamesToFarm = gamesToFarm.ThenBy(game => game.CardsRemaining);
break;
case BotConfig.EFarmingOrder.CardDropsDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => game.CardsRemaining);
break;
case BotConfig.EFarmingOrder.MarketableAscending:
case BotConfig.EFarmingOrder.MarketableDescending:
@ -971,12 +1081,15 @@ namespace ArchiSteamFarm {
switch (farmingOrder) {
case BotConfig.EFarmingOrder.MarketableAscending:
gamesToFarm = gamesToFarm.ThenBy(game => marketableAppIDs.Contains(game.AppID));
break;
case BotConfig.EFarmingOrder.MarketableDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => marketableAppIDs.Contains(game.AppID));
break;
default:
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(farmingOrder), farmingOrder));
return;
}
}
@ -984,18 +1097,23 @@ namespace ArchiSteamFarm {
break;
case BotConfig.EFarmingOrder.HoursAscending:
gamesToFarm = gamesToFarm.ThenBy(game => game.HoursPlayed);
break;
case BotConfig.EFarmingOrder.HoursDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => game.HoursPlayed);
break;
case BotConfig.EFarmingOrder.NamesAscending:
gamesToFarm = gamesToFarm.ThenBy(game => game.GameName);
break;
case BotConfig.EFarmingOrder.NamesDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => game.GameName);
break;
case BotConfig.EFarmingOrder.Random:
gamesToFarm = gamesToFarm.ThenBy(game => Utilities.RandomNext());
break;
case BotConfig.EFarmingOrder.RedeemDateTimesAscending:
case BotConfig.EFarmingOrder.RedeemDateTimesDescending:
@ -1023,18 +1141,22 @@ namespace ArchiSteamFarm {
switch (farmingOrder) {
case BotConfig.EFarmingOrder.RedeemDateTimesAscending:
gamesToFarm = gamesToFarm.ThenBy(game => redeemDates[game.AppID]);
break;
case BotConfig.EFarmingOrder.RedeemDateTimesDescending:
gamesToFarm = gamesToFarm.ThenByDescending(game => redeemDates[game.AppID]);
break;
default:
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(farmingOrder), farmingOrder));
return;
}
break;
default:
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(farmingOrder), farmingOrder));
return;
}
}

View file

@ -54,26 +54,31 @@ namespace ArchiSteamFarm.Collections {
public bool IsProperSubsetOf(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count > Count) && IsSubsetOf(otherSet);
}
public bool IsProperSupersetOf(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count < Count) && IsSupersetOf(otherSet);
}
public bool IsSubsetOf(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return this.All(otherSet.Contains);
}
public bool IsSupersetOf(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return otherSet.All(Contains);
}
public bool Overlaps(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return otherSet.Any(Contains);
}
@ -81,13 +86,14 @@ namespace ArchiSteamFarm.Collections {
public bool SetEquals(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
return (otherSet.Count == Count) && otherSet.All(Contains);
}
public void SymmetricExceptWith(IEnumerable<T> other) {
ISet<T> otherSet = other as ISet<T> ?? other.ToHashSet();
HashSet<T> removed = new HashSet<T>();
foreach (T item in otherSet.Where(Contains)) {
removed.Add(item);
Remove(item);
@ -119,6 +125,7 @@ namespace ArchiSteamFarm.Collections {
}
ReplaceWith(other);
return true;
}

View file

@ -218,22 +218,22 @@ namespace ArchiSteamFarm.Collections {
public T Current => Enumerator.Current;
private readonly IEnumerator<T> Enumerator;
private readonly SemaphoreSlim SemaphoreSlim;
private readonly SemaphoreSlim Semaphore;
object IEnumerator.Current => Current;
internal ConcurrentEnumerator(IReadOnlyCollection<T> collection, SemaphoreSlim semaphoreSlim) {
if ((collection == null) || (semaphoreSlim == null)) {
throw new ArgumentNullException(nameof(collection) + " || " + nameof(semaphoreSlim));
internal ConcurrentEnumerator(IReadOnlyCollection<T> collection, SemaphoreSlim semaphore) {
if ((collection == null) || (semaphore == null)) {
throw new ArgumentNullException(nameof(collection) + " || " + nameof(semaphore));
}
SemaphoreSlim = semaphoreSlim;
semaphoreSlim.Wait();
Semaphore = semaphore;
semaphore.Wait();
Enumerator = collection.GetEnumerator();
}
public void Dispose() => SemaphoreSlim.Release();
public void Dispose() => Semaphore.Release();
public bool MoveNext() => Enumerator.MoveNext();
public void Reset() => Enumerator.Reset();
}

View file

@ -30,9 +30,11 @@ namespace ArchiSteamFarm.Collections {
internal byte MaxCount {
get => _MaxCount;
set {
if (value == 0) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,7 @@ namespace ArchiSteamFarm {
public void WriteLine(string category, string msg) {
if (string.IsNullOrEmpty(category) && string.IsNullOrEmpty(msg)) {
ASF.ArchiLogger.LogNullError(nameof(category) + " && " + nameof(msg));
return;
}

View file

@ -41,12 +41,14 @@ namespace ArchiSteamFarm {
}
List<ReleaseResponse> response = await GetReleasesFromURL(releaseURL).ConfigureAwait(false);
return response?.FirstOrDefault();
}
internal static async Task<ReleaseResponse> GetRelease(string version) {
if (string.IsNullOrEmpty(version)) {
ASF.ArchiLogger.LogNullError(nameof(version));
return null;
}
@ -56,16 +58,19 @@ namespace ArchiSteamFarm {
internal static async Task<List<ReleaseResponse>> GetReleases(byte count) {
if (count == 0) {
ASF.ArchiLogger.LogNullError(nameof(count));
return null;
}
string releaseURL = SharedInfo.GithubReleaseURL + "?per_page=" + count;
return await GetReleasesFromURL(releaseURL).ConfigureAwait(false);
}
private static MarkdownDocument ExtractChangelogFromBody(string markdownText) {
if (string.IsNullOrEmpty(markdownText)) {
ASF.ArchiLogger.LogNullError(nameof(markdownText));
return null;
}
@ -84,20 +89,24 @@ namespace ArchiSteamFarm {
private static async Task<ReleaseResponse> GetReleaseFromURL(string releaseURL) {
if (string.IsNullOrEmpty(nameof(releaseURL))) {
ASF.ArchiLogger.LogNullError(nameof(releaseURL));
return null;
}
WebBrowser.ObjectResponse<ReleaseResponse> objectResponse = await Program.WebBrowser.UrlGetToJsonObject<ReleaseResponse>(releaseURL).ConfigureAwait(false);
return objectResponse?.Content;
}
private static async Task<List<ReleaseResponse>> GetReleasesFromURL(string releaseURL) {
if (string.IsNullOrEmpty(nameof(releaseURL))) {
ASF.ArchiLogger.LogNullError(nameof(releaseURL));
return null;
}
WebBrowser.ObjectResponse<List<ReleaseResponse>> objectResponse = await Program.WebBrowser.UrlGetToJsonObject<List<ReleaseResponse>>(releaseURL).ConfigureAwait(false);
return objectResponse?.Content;
}
@ -123,6 +132,7 @@ namespace ArchiSteamFarm {
if (Changelog == null) {
ASF.ArchiLogger.LogNullError(nameof(Changelog));
return null;
}
@ -144,6 +154,7 @@ namespace ArchiSteamFarm {
if (Changelog == null) {
ASF.ArchiLogger.LogNullError(nameof(Changelog));
return null;
}

View file

@ -156,6 +156,7 @@ namespace ArchiSteamFarm {
uri = new Uri(WebProxyText);
} catch (UriFormatException e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
@ -195,6 +196,7 @@ namespace ArchiSteamFarm {
[JsonProperty]
internal string WebProxyPassword {
get => _WebProxyPassword;
set {
IsWebProxyPasswordSet = true;
_WebProxyPassword = value;
@ -208,9 +210,11 @@ namespace ArchiSteamFarm {
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamOwnerID), Required = Required.DisallowNull)]
private string SSteamOwnerID {
get => SteamOwnerID.ToString();
set {
if (string.IsNullOrEmpty(value) || !ulong.TryParse(value, out ulong result)) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SSteamOwnerID)));
return;
}
@ -255,6 +259,7 @@ namespace ArchiSteamFarm {
internal static async Task<GlobalConfig> Load(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
}
@ -268,28 +273,34 @@ namespace ArchiSteamFarm {
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
if (globalConfig == null) {
ASF.ArchiLogger.LogNullError(nameof(globalConfig));
return null;
}
(bool valid, string errorMessage) = globalConfig.CheckValidation();
if (!valid) {
ASF.ArchiLogger.LogGenericError(errorMessage);
return null;
}
globalConfig.ShouldSerializeEverything = false;
globalConfig.ShouldSerializeSensitiveDetails = false;
return globalConfig;
}
internal static async Task<bool> Write(string filePath, GlobalConfig globalConfig) {
if (string.IsNullOrEmpty(filePath) || (globalConfig == null)) {
ASF.ArchiLogger.LogNullError(nameof(filePath) + " || " + nameof(globalConfig));
return false;
}
@ -308,6 +319,7 @@ namespace ArchiSteamFarm {
}
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return false;
} finally {
WriteSemaphore.Release();

View file

@ -72,6 +72,7 @@ namespace ArchiSteamFarm {
internal static async Task<GlobalDatabase> CreateOrLoad(string filePath) {
if (string.IsNullOrEmpty(filePath)) {
ASF.ArchiLogger.LogNullError(nameof(filePath));
return null;
}
@ -85,21 +86,25 @@ namespace ArchiSteamFarm {
globalDatabase = JsonConvert.DeserializeObject<GlobalDatabase>(await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false));
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
if (globalDatabase == null) {
ASF.ArchiLogger.LogNullError(nameof(globalDatabase));
return null;
}
globalDatabase.FilePath = filePath;
return globalDatabase;
}
internal HashSet<uint> GetPackageIDs(uint appID) {
if (appID == 0) {
ASF.ArchiLogger.LogNullError(nameof(appID));
return null;
}
@ -109,6 +114,7 @@ namespace ArchiSteamFarm {
internal async Task RefreshPackages(Bot bot, IReadOnlyDictionary<uint, uint> packages) {
if ((bot == null) || (packages == null) || (packages.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(bot) + " || " + nameof(packages));
return;
}
@ -122,6 +128,7 @@ namespace ArchiSteamFarm {
}
Dictionary<uint, (uint ChangeNumber, HashSet<uint> AppIDs)> packagesData = await bot.GetPackagesData(packageIDs).ConfigureAwait(false);
if ((packagesData == null) || (packagesData.Count == 0)) {
return;
}
@ -149,8 +156,10 @@ namespace ArchiSteamFarm {
private async Task Save() {
string json = JsonConvert.SerializeObject(this);
if (string.IsNullOrEmpty(json)) {
ASF.ArchiLogger.LogNullError(nameof(json));
return;
}

View file

@ -66,6 +66,7 @@ namespace ArchiSteamFarm.Helpers {
}
(bool success, T result) = await ResolveFunction().ConfigureAwait(false);
if (!success) {
return (false, InitializedValue);
}

View file

@ -62,6 +62,7 @@ namespace ArchiSteamFarm.IPC {
IWebHostBuilder builder = new WebHostBuilder();
string customDirectory = Path.Combine(Directory.GetCurrentDirectory(), SharedInfo.WebsiteDirectory);
if (Directory.Exists(customDirectory)) {
WebsiteDirectory = customDirectory;
}
@ -106,6 +107,7 @@ namespace ArchiSteamFarm.IPC {
} catch (Exception e) {
ASF.ArchiLogger.LogGenericException(e);
kestrelWebHost.Dispose();
return;
}

View file

@ -39,6 +39,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
uint memoryUsage = (uint) GC.GetTotalMemory(false) / 1024;
ASFResponse result = new ASFResponse(SharedInfo.BuildInfo.Variant, Program.GlobalConfig, memoryUsage, RuntimeCompatibility.ProcessStartTime, SharedInfo.Version);
return Ok(new GenericResponse<ASFResponse>(result));
}
@ -51,10 +52,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> ASFPost([FromBody] ASFRequest request) {
if (request == null) {
ASF.ArchiLogger.LogNullError(nameof(request));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(request))));
}
(bool valid, string errorMessage) = request.GlobalConfig.CheckValidation();
if (!valid) {
return BadRequest(new GenericResponse(false, errorMessage));
}
@ -69,6 +72,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
string filePath = Path.Combine(SharedInfo.ConfigDirectory, SharedInfo.GlobalConfigFileName);
bool result = await GlobalConfig.Write(filePath, request.GlobalConfig).ConfigureAwait(false);
return Ok(new GenericResponse(result));
}
@ -79,6 +83,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
[ProducesResponseType(typeof(GenericResponse), 200)]
public ActionResult<GenericResponse> ExitPost() {
(bool success, string output) = Actions.Exit();
return Ok(new GenericResponse(success, output));
}
@ -89,6 +94,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
[ProducesResponseType(typeof(GenericResponse), 200)]
public ActionResult<GenericResponse> RestartPost() {
(bool success, string output) = Actions.Restart();
return Ok(new GenericResponse(success, output));
}

View file

@ -41,15 +41,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> BotDelete(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<bool> results = await Utilities.InParallel(bots.Select(bot => bot.DeleteAllRelatedFiles())).ConfigureAwait(false);
return Ok(new GenericResponse(results.All(result => result)));
}
@ -61,10 +64,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public ActionResult<GenericResponse<IReadOnlyDictionary<string, Bot>>> BotGet(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, Bot>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if (bots == null) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, Bot>>(false, string.Format(Strings.ErrorIsInvalid, nameof(bots))));
}
@ -81,10 +86,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, bool>>>> BotPost(string botNames, [FromBody] BotRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, bool>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
}
(bool valid, string errorMessage) = request.BotConfig.CheckValidation();
if (!valid) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, bool>>(false, errorMessage));
}
@ -138,15 +145,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> GamesToRedeemInBackgroundDelete(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<bool> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.DeleteRedeemedKeysFiles))).ConfigureAwait(false);
return Ok(results.All(result => result) ? new GenericResponse(true) : new GenericResponse(false, Strings.WarningFailed));
}
@ -158,10 +168,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>>> GamesToRedeemInBackgroundGet(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, GamesToRedeemInBackgroundResponse>>(false, string.Format(Strings.BotNotFound, botNames)));
}
@ -187,6 +199,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>>> GamesToRedeemInBackgroundPost(string botNames, [FromBody] BotGamesToRedeemInBackgroundRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
}
@ -195,11 +208,13 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.BotNotFound, botNames)));
}
IOrderedDictionary validGamesToRedeemInBackground = Bot.ValidateGamesToRedeemInBackground(request.GamesToRedeemInBackground);
if ((validGamesToRedeemInBackground == null) || (validGamesToRedeemInBackground.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IOrderedDictionary>>(false, string.Format(Strings.ErrorIsEmpty, nameof(validGamesToRedeemInBackground))));
}
@ -224,15 +239,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> PausePost(string botNames, [FromBody] BotPauseRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => bot.Actions.Pause(request.Permanent, request.ResumeInSeconds))).ConfigureAwait(false);
return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output))));
}
@ -249,6 +267,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>>> RedeemPost(string botNames, [FromBody] BotRedeemRequest request) {
if (string.IsNullOrEmpty(botNames) || (request == null)) {
ASF.ArchiLogger.LogNullError(nameof(botNames) + " || " + nameof(request));
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames) + " || " + nameof(request))));
}
@ -257,6 +276,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyDictionary<string, IReadOnlyDictionary<string, ArchiHandler.PurchaseResponseCallback>>>(false, string.Format(Strings.BotNotFound, botNames)));
}
@ -287,15 +307,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> ResumePost(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Resume))).ConfigureAwait(false);
return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output))));
}
@ -307,15 +330,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> StartPost(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Start))).ConfigureAwait(false);
return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output))));
}
@ -327,15 +353,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse>> StopPost(string botNames) {
if (string.IsNullOrEmpty(botNames)) {
ASF.ArchiLogger.LogNullError(nameof(botNames));
return BadRequest(new GenericResponse(false, string.Format(Strings.ErrorIsEmpty, nameof(botNames))));
}
HashSet<Bot> bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return BadRequest(new GenericResponse(false, string.Format(Strings.BotNotFound, botNames)));
}
IList<(bool Success, string Output)> results = await Utilities.InParallel(bots.Select(bot => Task.Run(bot.Actions.Stop))).ConfigureAwait(false);
return Ok(new GenericResponse(results.All(result => result.Success), string.Join(Environment.NewLine, results.Select(result => result.Output))));
}
}

View file

@ -41,6 +41,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<string>>> CommandPost(string command) {
if (string.IsNullOrEmpty(command)) {
ASF.ArchiLogger.LogNullError(nameof(command));
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsEmpty, nameof(command))));
}
@ -49,6 +50,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
Bot targetBot = Bot.Bots.OrderBy(bot => bot.Key).Select(bot => bot.Value).FirstOrDefault();
if (targetBot == null) {
return BadRequest(new GenericResponse<string>(false, Strings.ErrorNoBotsDefined));
}
@ -58,6 +60,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
string response = await targetBot.Commands.Response(Program.GlobalConfig.SteamOwnerID, command).ConfigureAwait(false);
return Ok(new GenericResponse<string>(response));
}
}

View file

@ -55,8 +55,10 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
try {
using (WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync().ConfigureAwait(false)) {
SemaphoreSlim sendSemaphore = new SemaphoreSlim(1, 1);
if (!ActiveLogWebSockets.TryAdd(webSocket, sendSemaphore)) {
sendSemaphore.Dispose();
return new EmptyResult();
}
@ -72,10 +74,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
if (result.MessageType != WebSocketMessageType.Close) {
await webSocket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "You're not supposed to be sending any message but Close!", CancellationToken.None).ConfigureAwait(false);
break;
}
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None).ConfigureAwait(false);
break;
}
} finally {
@ -95,6 +99,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
internal static async void OnNewHistoryEntry(object sender, HistoryTarget.NewHistoryEntryArgs newHistoryEntryArgs) {
if ((sender == null) || (newHistoryEntryArgs == null)) {
ASF.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(newHistoryEntryArgs));
return;
}
@ -109,6 +114,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
private static async Task PostLoggedJsonUpdate(WebSocket webSocket, SemaphoreSlim sendSemaphore, string json) {
if ((webSocket == null) || (sendSemaphore == null) || string.IsNullOrEmpty(json)) {
ASF.ArchiLogger.LogNullError(nameof(webSocket) + " || " + nameof(sendSemaphore) + " || " + nameof(json));
return;
}
@ -134,6 +140,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
private static async Task PostLoggedMessageUpdate(WebSocket webSocket, SemaphoreSlim sendSemaphore, string loggedMessage) {
if ((webSocket == null) || (sendSemaphore == null) || string.IsNullOrEmpty(loggedMessage)) {
ASF.ArchiLogger.LogNullError(nameof(webSocket) + " || " + nameof(sendSemaphore) + " || " + nameof(loggedMessage));
return;
}

View file

@ -38,6 +38,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public ActionResult<GenericResponse<object>> StructureGet(string structure) {
if (string.IsNullOrEmpty(structure)) {
ASF.ArchiLogger.LogNullError(nameof(structure));
return BadRequest(new GenericResponse<object>(false, string.Format(Strings.ErrorIsEmpty, nameof(structure))));
}

View file

@ -42,6 +42,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public ActionResult<GenericResponse<TypeResponse>> TypeGet(string type) {
if (string.IsNullOrEmpty(type)) {
ASF.ArchiLogger.LogNullError(nameof(type));
return BadRequest(new GenericResponse<TypeResponse>(false, string.Format(Strings.ErrorIsEmpty, nameof(type))));
}
@ -85,6 +86,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
TypeResponse.TypeProperties properties = new TypeResponse.TypeProperties(baseType, customAttributes.Count > 0 ? customAttributes : null, underlyingType);
TypeResponse response = new TypeResponse(body, properties);
return Ok(new GenericResponse<TypeResponse>(response));
}
}

View file

@ -43,10 +43,12 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public ActionResult<GenericResponse<IReadOnlyCollection<string>>> DirectoryGet(string directory) {
if (string.IsNullOrEmpty(directory)) {
ASF.ArchiLogger.LogNullError(nameof(directory));
return BadRequest(new GenericResponse<IReadOnlyCollection<string>>(false, string.Format(Strings.ErrorIsEmpty, nameof(directory))));
}
string directoryPath = Path.Combine(ArchiKestrel.WebsiteDirectory, directory);
if (!Directory.Exists(directoryPath)) {
return BadRequest(new GenericResponse<IReadOnlyCollection<string>>(false, string.Format(Strings.ErrorIsInvalid, directory)));
}
@ -60,6 +62,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
HashSet<string> result = files.Select(Path.GetFileName).ToHashSet();
return Ok(new GenericResponse<IReadOnlyCollection<string>>(result));
}
@ -77,11 +80,13 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
List<GitHub.ReleaseResponse> response = await GitHub.GetReleases(count).ConfigureAwait(false);
if ((response == null) || (response.Count == 0)) {
return BadRequest(new GenericResponse<IReadOnlyCollection<GitHub.ReleaseResponse>>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
List<GitHubReleaseResponse> result = response.Select(singleResponse => new GitHubReleaseResponse(singleResponse)).ToList();
return Ok(new GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>(result));
}
@ -99,6 +104,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
GitHub.ReleaseResponse releaseResponse = await GitHub.GetRelease(version).ConfigureAwait(false);
if (releaseResponse == null) {
return BadRequest(new GenericResponse<GitHubReleaseResponse>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}
@ -118,6 +124,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
public async Task<ActionResult<GenericResponse<string>>> SendPost([FromBody] WWWSendRequest request) {
if (request == null) {
ASF.ArchiLogger.LogNullError(nameof(request));
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorIsEmpty, nameof(request))));
}
@ -126,6 +133,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
}
WebBrowser.StringResponse urlResponse = await Program.WebBrowser.UrlGetToString(request.URL).ConfigureAwait(false);
if (urlResponse?.Content == null) {
return BadRequest(new GenericResponse<string>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
}

View file

@ -57,6 +57,7 @@ namespace ArchiSteamFarm.IPC.Middleware {
public async Task InvokeAsync(HttpContext context) {
if (context == null) {
ASF.ArchiLogger.LogNullError(nameof(context));
return;
}
@ -64,6 +65,7 @@ namespace ArchiSteamFarm.IPC.Middleware {
if (authenticationStatus != HttpStatusCode.OK) {
await context.Response.Generate(authenticationStatus).ConfigureAwait(false);
return;
}
@ -73,6 +75,7 @@ namespace ArchiSteamFarm.IPC.Middleware {
private static async Task<HttpStatusCode> GetAuthenticationStatus(HttpContext context) {
if (context == null) {
ASF.ArchiLogger.LogNullError(nameof(context));
return HttpStatusCode.InternalServerError;
}

View file

@ -62,6 +62,7 @@ namespace ArchiSteamFarm.IPC.Responses {
if (!string.IsNullOrEmpty(message)) {
Message = message;
return;
}

View file

@ -41,6 +41,7 @@ namespace ArchiSteamFarm.IPC {
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
if ((app == null) || (env == null)) {
ASF.ArchiLogger.LogNullError(nameof(app) + " || " + nameof(env));
return;
}
@ -48,6 +49,7 @@ namespace ArchiSteamFarm.IPC {
// Add workaround for missing PathBase feature, https://github.com/aspnet/Hosting/issues/1120
PathString pathBase = Configuration.GetSection("Kestrel").GetValue<PathString>("PathBase");
if (!string.IsNullOrEmpty(pathBase) && (pathBase != "/")) {
app.UsePathBase(pathBase);
}
@ -87,6 +89,7 @@ namespace ArchiSteamFarm.IPC {
public void ConfigureServices(IServiceCollection services) {
if (services == null) {
ASF.ArchiLogger.LogNullError(nameof(services));
return;
}
@ -127,6 +130,7 @@ namespace ArchiSteamFarm.IPC {
c.DescribeAllEnumsAsStrings();
c.EnableAnnotations();
c.SwaggerDoc(
SharedInfo.ASF, new OpenApiInfo {
Contact = new OpenApiContact {

View file

@ -30,6 +30,7 @@ namespace ArchiSteamFarm.IPC {
internal static async Task Generate(this HttpResponse httpResponse, HttpStatusCode statusCode) {
if (httpResponse == null) {
ASF.ArchiLogger.LogNullError(nameof(httpResponse));
return;
}
@ -42,6 +43,7 @@ namespace ArchiSteamFarm.IPC {
internal static string GetUnifiedName(this Type type) {
if (type == null) {
ASF.ArchiLogger.LogNullError(nameof(type));
return null;
}
@ -51,10 +53,12 @@ namespace ArchiSteamFarm.IPC {
internal static Type ParseType(string typeText) {
if (string.IsNullOrEmpty(typeText)) {
ASF.ArchiLogger.LogNullError(nameof(typeText));
return null;
}
Type targetType = Type.GetType(typeText);
if (targetType != null) {
return targetType;
}

View file

@ -54,11 +54,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!uint.TryParse(value, out uint amount) || (amount == 0)) {
ASF.ArchiLogger.LogNullError(nameof(amount));
return;
}
@ -73,11 +75,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!ulong.TryParse(value, out ulong assetID) || (assetID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(assetID));
return;
}
@ -92,6 +96,7 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
@ -110,11 +115,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!ulong.TryParse(value, out ulong contextID) || (contextID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(contextID));
return;
}
@ -176,12 +183,15 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
HtmlDocument htmlDocument = WebBrowser.StringToHtmlDocument(value);
if (htmlDocument == null) {
ASF.ArchiLogger.LogNullError(nameof(htmlDocument));
return;
}
@ -189,32 +199,42 @@ namespace ArchiSteamFarm.Json {
Type = EType.Trade;
HtmlNode tradeOfferNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='tradeoffer']");
if (tradeOfferNode == null) {
ASF.ArchiLogger.LogNullError(nameof(tradeOfferNode));
return;
}
string idText = tradeOfferNode.GetAttributeValue("id", null);
if (string.IsNullOrEmpty(idText)) {
ASF.ArchiLogger.LogNullError(nameof(idText));
return;
}
int index = idText.IndexOf('_');
if (index < 0) {
ASF.ArchiLogger.LogNullError(nameof(index));
return;
}
index++;
if (idText.Length <= index) {
ASF.ArchiLogger.LogNullError(nameof(idText.Length));
return;
}
idText = idText.Substring(index);
if (!ulong.TryParse(idText, out ulong tradeOfferID) || (tradeOfferID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(tradeOfferID));
return;
}
@ -275,11 +295,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!ulong.TryParse(value, out ulong lastAssetID) || (lastAssetID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(lastAssetID));
return;
}
@ -313,11 +335,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!ulong.TryParse(value, out ulong classID) || (classID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(classID));
return;
}
@ -354,12 +378,15 @@ namespace ArchiSteamFarm.Json {
switch (value) {
case 0:
Success = false;
break;
case 1:
Success = true;
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}
@ -414,6 +441,7 @@ namespace ArchiSteamFarm.Json {
internal bool IsValidSteamItemsRequest(IReadOnlyCollection<Asset.EType> acceptedTypes) {
if ((acceptedTypes == null) || (acceptedTypes.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(acceptedTypes));
return false;
}
@ -471,11 +499,13 @@ namespace ArchiSteamFarm.Json {
set {
if (string.IsNullOrEmpty(value)) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
if (!ulong.TryParse(value, out ulong tradeOfferID) || (tradeOfferID == 0)) {
ASF.ArchiLogger.LogNullError(nameof(tradeOfferID));
return;
}

View file

@ -68,6 +68,7 @@ namespace ArchiSteamFarm {
internal bool CorrectDeviceID(string deviceID) {
if (string.IsNullOrEmpty(deviceID)) {
Bot.ArchiLogger.LogNullError(nameof(deviceID));
return false;
}
@ -76,13 +77,16 @@ namespace ArchiSteamFarm {
}
DeviceID = deviceID;
return true;
}
internal async Task<string> GenerateToken() {
uint time = await GetSteamTime().ConfigureAwait(false);
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return null;
}
@ -92,45 +96,57 @@ namespace ArchiSteamFarm {
internal async Task<Steam.ConfirmationDetails> GetConfirmationDetails(Confirmation confirmation) {
if (confirmation == null) {
Bot.ArchiLogger.LogNullError(nameof(confirmation));
return null;
}
if (!HasCorrectDeviceID) {
Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID);
return null;
}
uint time = await GetSteamTime().ConfigureAwait(false);
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return null;
}
string confirmationHash = GenerateConfirmationHash(time, "conf");
if (string.IsNullOrEmpty(confirmationHash)) {
Bot.ArchiLogger.LogNullError(nameof(confirmationHash));
return null;
}
Steam.ConfirmationDetails response = await Bot.ArchiWebHandler.GetConfirmationDetails(DeviceID, confirmationHash, time, confirmation).ConfigureAwait(false);
return response?.Success == true ? response : null;
}
internal async Task<HashSet<Confirmation>> GetConfirmations(Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown) {
if (!HasCorrectDeviceID) {
Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID);
return null;
}
uint time = await GetSteamTime().ConfigureAwait(false);
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return null;
}
string confirmationHash = GenerateConfirmationHash(time, "conf");
if (string.IsNullOrEmpty(confirmationHash)) {
Bot.ArchiLogger.LogNullError(nameof(confirmationHash));
return null;
}
@ -139,6 +155,7 @@ namespace ArchiSteamFarm {
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetConfirmations(DeviceID, confirmationHash, time).ConfigureAwait(false);
HtmlNodeCollection confirmationNodes = htmlDocument?.DocumentNode.SelectNodes("//div[@class='mobileconf_list_entry']");
if (confirmationNodes == null) {
return null;
}
@ -147,40 +164,50 @@ namespace ArchiSteamFarm {
foreach (HtmlNode confirmationNode in confirmationNodes) {
string idText = confirmationNode.GetAttributeValue("data-confid", null);
if (string.IsNullOrEmpty(idText)) {
Bot.ArchiLogger.LogNullError(nameof(idText));
return null;
}
if (!ulong.TryParse(idText, out ulong id) || (id == 0)) {
Bot.ArchiLogger.LogNullError(nameof(id));
return null;
}
string keyText = confirmationNode.GetAttributeValue("data-key", null);
if (string.IsNullOrEmpty(keyText)) {
Bot.ArchiLogger.LogNullError(nameof(keyText));
return null;
}
if (!ulong.TryParse(keyText, out ulong key) || (key == 0)) {
Bot.ArchiLogger.LogNullError(nameof(key));
return null;
}
string typeText = confirmationNode.GetAttributeValue("data-type", null);
if (string.IsNullOrEmpty(typeText)) {
Bot.ArchiLogger.LogNullError(nameof(typeText));
return null;
}
if (!Enum.TryParse(typeText, out Steam.ConfirmationDetails.EType type) || (type == Steam.ConfirmationDetails.EType.Unknown)) {
Bot.ArchiLogger.LogNullError(nameof(type));
return null;
}
if (!Enum.IsDefined(typeof(Steam.ConfirmationDetails.EType), type)) {
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(type), type));
return null;
}
@ -197,27 +224,34 @@ namespace ArchiSteamFarm {
internal async Task<bool> HandleConfirmations(IReadOnlyCollection<Confirmation> confirmations, bool accept) {
if ((confirmations == null) || (confirmations.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(confirmations));
return false;
}
if (!HasCorrectDeviceID) {
Bot.ArchiLogger.LogGenericError(Strings.ErrorMobileAuthenticatorInvalidDeviceID);
return false;
}
uint time = await GetSteamTime().ConfigureAwait(false);
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return false;
}
string confirmationHash = GenerateConfirmationHash(time, "conf");
if (string.IsNullOrEmpty(confirmationHash)) {
Bot.ArchiLogger.LogNullError(nameof(confirmationHash));
return false;
}
bool? result = await Bot.ArchiWebHandler.HandleConfirmations(DeviceID, confirmationHash, time, confirmations, accept).ConfigureAwait(false);
if (!result.HasValue) {
// Request timed out
return false;
@ -233,6 +267,7 @@ namespace ArchiSteamFarm {
// We totally ignore actual result returned by those calls, abort only if request timed out
foreach (Confirmation confirmation in confirmations) {
bool? confirmationResult = await Bot.ArchiWebHandler.HandleConfirmation(DeviceID, confirmationHash, time, confirmation.ID, confirmation.Key, accept).ConfigureAwait(false);
if (!confirmationResult.HasValue) {
return false;
}
@ -246,6 +281,7 @@ namespace ArchiSteamFarm {
private string GenerateConfirmationHash(uint time, string tag = null) {
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return null;
}
@ -256,15 +292,18 @@ namespace ArchiSteamFarm {
} catch (FormatException e) {
Bot.ArchiLogger.LogGenericException(e);
Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(IdentitySecret)));
return null;
}
byte bufferSize = 8;
if (!string.IsNullOrEmpty(tag)) {
bufferSize += (byte) Math.Min(32, tag.Length);
}
byte[] timeArray = BitConverter.GetBytes((long) time);
if (BitConverter.IsLittleEndian) {
Array.Reverse(timeArray);
}
@ -272,11 +311,13 @@ namespace ArchiSteamFarm {
byte[] buffer = new byte[bufferSize];
Array.Copy(timeArray, buffer, 8);
if (!string.IsNullOrEmpty(tag)) {
Array.Copy(Encoding.UTF8.GetBytes(tag), 0, buffer, 8, bufferSize - 8);
}
byte[] hash;
using (HMACSHA1 hmac = new HMACSHA1(identitySecret)) {
hash = hmac.ComputeHash(buffer);
}
@ -287,6 +328,7 @@ namespace ArchiSteamFarm {
private string GenerateTokenForTime(uint time) {
if (time == 0) {
Bot.ArchiLogger.LogNullError(nameof(time));
return null;
}
@ -297,15 +339,18 @@ namespace ArchiSteamFarm {
} catch (FormatException e) {
Bot.ArchiLogger.LogGenericException(e);
Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SharedSecret)));
return null;
}
byte[] timeArray = BitConverter.GetBytes((long) time / CodeInterval);
if (BitConverter.IsLittleEndian) {
Array.Reverse(timeArray);
}
byte[] hash;
using (HMACSHA1 hmac = new HMACSHA1(sharedSecret)) {
hash = hmac.ComputeHash(timeArray);
}
@ -348,6 +393,7 @@ namespace ArchiSteamFarm {
}
uint serverTime = await Bot.ArchiWebHandler.GetServerTime().ConfigureAwait(false);
if (serverTime == 0) {
return Utilities.GetUnixTime();
}
@ -367,6 +413,7 @@ namespace ArchiSteamFarm {
}
await ConfirmationsSemaphore.WaitAsync().ConfigureAwait(false);
Utilities.InBackground(
async () => {
await Task.Delay(Program.GlobalConfig.ConfirmationsLimiterDelay * 1000).ConfigureAwait(false);

View file

@ -41,6 +41,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogChatMessage(bool echo, string message, ulong chatGroupID = 0, ulong chatID = 0, ulong steamID = 0, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message) || (((chatGroupID == 0) || (chatID == 0)) && (steamID == 0))) {
LogNullError(nameof(message) + " || " + "((" + nameof(chatGroupID) + " || " + nameof(chatID) + ") && " + nameof(steamID) + ")");
return;
}
@ -69,6 +70,7 @@ namespace ArchiSteamFarm.NLog {
internal async Task LogFatalException(Exception exception, [CallerMemberName] string previousMethodName = null) {
if (exception == null) {
LogNullError(nameof(exception));
return;
}
@ -85,13 +87,13 @@ namespace ArchiSteamFarm.NLog {
try {
await RuntimeCompatibility.File.WriteAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
} catch {
// Ignored, we can't do anything with this
// Ignored, we can't do anything about this
}
try {
Console.Write(message);
} catch {
// Ignored, we can't do anything with this
// Ignored, we can't do anything about this
}
while (true) {
@ -100,17 +102,18 @@ namespace ArchiSteamFarm.NLog {
try {
await RuntimeCompatibility.File.AppendAllTextAsync(SharedInfo.LogFile, message).ConfigureAwait(false);
} catch {
// Ignored, we can't do anything with this
// Ignored, we can't do anything about this
}
try {
Console.Write(message);
} catch {
// Ignored, we can't do anything with this
// Ignored, we can't do anything about this
}
if (exception.InnerException != null) {
exception = exception.InnerException;
continue;
}
@ -121,6 +124,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericDebug(string message, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message));
return;
}
@ -130,6 +134,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericDebuggingException(Exception exception, [CallerMemberName] string previousMethodName = null) {
if (exception == null) {
LogNullError(nameof(exception));
return;
}
@ -143,6 +148,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericError(string message, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message));
return;
}
@ -152,6 +158,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericException(Exception exception, [CallerMemberName] string previousMethodName = null) {
if (exception == null) {
LogNullError(nameof(exception));
return;
}
@ -161,6 +168,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericInfo(string message, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message));
return;
}
@ -170,6 +178,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericTrace(string message, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message));
return;
}
@ -179,6 +188,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericWarning(string message, [CallerMemberName] string previousMethodName = null) {
if (string.IsNullOrEmpty(message)) {
LogNullError(nameof(message));
return;
}
@ -188,6 +198,7 @@ namespace ArchiSteamFarm.NLog {
internal void LogGenericWarningException(Exception exception, [CallerMemberName] string previousMethodName = null) {
if (exception == null) {
LogNullError(nameof(exception));
return;
}

View file

@ -41,9 +41,11 @@ namespace ArchiSteamFarm.NLog {
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public byte MaxCount {
get => HistoryQueue.MaxCount;
set {
if (value == 0) {
ASF.ArchiLogger.LogNullError(nameof(value));
return;
}
@ -61,6 +63,7 @@ namespace ArchiSteamFarm.NLog {
protected override void Write(LogEventInfo logEvent) {
if (logEvent == null) {
ASF.ArchiLogger.LogNullError(nameof(logEvent));
return;
}

View file

@ -42,6 +42,7 @@ namespace ArchiSteamFarm.NLog {
}
bool reload = false;
foreach (LoggingRule rule in LogManager.Configuration.LoggingRules.Where(rule => rule.IsLoggingEnabledForLevel(LogLevel.Debug) && !rule.IsLoggingEnabledForLevel(LogLevel.Trace))) {
rule.EnableLoggingForLevel(LogLevel.Trace);
reload = true;
@ -57,6 +58,7 @@ namespace ArchiSteamFarm.NLog {
IsUsingCustomConfiguration = true;
InitConsoleLoggers();
LogManager.ConfigurationChanged += OnConfigurationChanged;
return;
}
@ -89,7 +91,6 @@ namespace ArchiSteamFarm.NLog {
HistoryTarget historyTarget = LogManager.Configuration.AllTargets.OfType<HistoryTarget>().FirstOrDefault();
if ((historyTarget == null) && !IsUsingCustomConfiguration) {
// TODO: We could use some nice HTML layout for this
historyTarget = new HistoryTarget("History") {
Layout = GeneralLayout,
MaxCount = 20
@ -154,6 +155,7 @@ namespace ArchiSteamFarm.NLog {
private static void OnConfigurationChanged(object sender, LoggingConfigurationChangedEventArgs e) {
if ((sender == null) || (e == null)) {
ASF.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
return;
}

View file

@ -56,6 +56,7 @@ namespace ArchiSteamFarm.NLog {
protected override async void Write(LogEventInfo logEvent) {
if (logEvent == null) {
ASF.ArchiLogger.LogNullError(nameof(logEvent));
return;
}
@ -89,6 +90,7 @@ namespace ArchiSteamFarm.NLog {
private async Task SendGroupMessage(string message, Bot bot = null) {
if (string.IsNullOrEmpty(message)) {
ASF.ArchiLogger.LogNullError(nameof(message));
return;
}
@ -106,6 +108,7 @@ namespace ArchiSteamFarm.NLog {
private async Task SendPrivateMessage(string message, Bot bot = null) {
if (string.IsNullOrEmpty(message)) {
ASF.ArchiLogger.LogNullError(nameof(message));
return;
}

View file

@ -41,14 +41,18 @@ 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;
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(optimizationMode), optimizationMode));
return;
}
}
@ -56,6 +60,7 @@ namespace ArchiSteamFarm {
internal static void UnixSetFileAccessExecutable(string path) {
if (string.IsNullOrEmpty(path) || !File.Exists(path)) {
ASF.ArchiLogger.LogNullError(nameof(path));
return;
}
@ -75,6 +80,7 @@ namespace ArchiSteamFarm {
if (!NativeMethods.GetConsoleMode(consoleHandle, out uint consoleMode)) {
ASF.ArchiLogger.LogGenericError(Strings.WarningFailed);
return;
}

View file

@ -72,6 +72,7 @@ namespace ArchiSteamFarm {
if (GlobalConfig.Headless) {
ASF.ArchiLogger.LogGenericWarning(Strings.ErrorUserInputRunningInHeadlessMode);
return null;
}
@ -85,31 +86,38 @@ namespace ArchiSteamFarm {
case ASF.EUserInputType.DeviceID:
Console.Write(Bot.FormatBotResponse(Strings.UserInputDeviceID, botName));
result = Console.ReadLine();
break;
case ASF.EUserInputType.Login:
Console.Write(Bot.FormatBotResponse(Strings.UserInputSteamLogin, botName));
result = Console.ReadLine();
break;
case ASF.EUserInputType.Password:
Console.Write(Bot.FormatBotResponse(Strings.UserInputSteamPassword, botName));
result = Utilities.ReadLineMasked();
break;
case ASF.EUserInputType.SteamGuard:
Console.Write(Bot.FormatBotResponse(Strings.UserInputSteamGuard, botName));
result = Console.ReadLine();
break;
case ASF.EUserInputType.SteamParentalCode:
Console.Write(Bot.FormatBotResponse(Strings.UserInputSteamParentalCode, botName));
result = Utilities.ReadLineMasked();
break;
case ASF.EUserInputType.TwoFactorAuthentication:
Console.Write(Bot.FormatBotResponse(Strings.UserInputSteam2FA, botName));
result = Console.ReadLine();
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userInputType), userInputType));
Console.Write(Bot.FormatBotResponse(string.Format(Strings.UserInputUnknown, userInputType), botName));
result = Console.ReadLine();
break;
}
@ -119,6 +127,7 @@ namespace ArchiSteamFarm {
} catch (Exception e) {
Logging.OnUserInputEnd();
ASF.ArchiLogger.LogGenericException(e);
return null;
}
@ -134,8 +143,10 @@ namespace ArchiSteamFarm {
}
string executableName = Path.GetFileNameWithoutExtension(ProcessFileName);
if (string.IsNullOrEmpty(executableName)) {
ASF.ArchiLogger.LogNullError(nameof(executableName));
return;
}
@ -157,6 +168,7 @@ namespace ArchiSteamFarm {
private static void HandleCryptKeyArgument(string cryptKey) {
if (string.IsNullOrEmpty(cryptKey)) {
ASF.ArchiLogger.LogNullError(nameof(cryptKey));
return;
}
@ -166,6 +178,7 @@ namespace ArchiSteamFarm {
private static void HandlePathArgument(string path) {
if (string.IsNullOrEmpty(path)) {
ASF.ArchiLogger.LogNullError(nameof(path));
return;
}
@ -217,6 +230,7 @@ namespace ArchiSteamFarm {
// Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up
for (byte i = 0; i < 4; i++) {
Directory.SetCurrentDirectory("..");
if (Directory.Exists(SharedInfo.ConfigDirectory)) {
break;
}
@ -241,10 +255,12 @@ namespace ArchiSteamFarm {
if (File.Exists(globalConfigFile)) {
GlobalConfig = await GlobalConfig.Load(globalConfigFile).ConfigureAwait(false);
if (GlobalConfig == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorGlobalConfigNotLoaded, globalConfigFile));
await Task.Delay(5 * 1000).ConfigureAwait(false);
await Exit(1).ConfigureAwait(false);
return;
}
} else {
@ -270,24 +286,31 @@ namespace ArchiSteamFarm {
}
ResourceSet defaultResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-US"), true, true);
if (defaultResourceSet == null) {
ASF.ArchiLogger.LogNullError(nameof(defaultResourceSet));
return;
}
HashSet<DictionaryEntry> defaultStringObjects = defaultResourceSet.Cast<DictionaryEntry>().ToHashSet();
if (defaultStringObjects.Count == 0) {
ASF.ArchiLogger.LogNullError(nameof(defaultStringObjects));
return;
}
ResourceSet currentResourceSet = Strings.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
if (currentResourceSet == null) {
ASF.ArchiLogger.LogNullError(nameof(currentResourceSet));
return;
}
HashSet<DictionaryEntry> currentStringObjects = currentResourceSet.Cast<DictionaryEntry>().ToHashSet();
if (currentStringObjects.Count >= defaultStringObjects.Count) {
// Either we have 100% finished translation, or we're missing it entirely and using en-US
HashSet<DictionaryEntry> testStringObjects = currentStringObjects.ToHashSet();
@ -317,10 +340,12 @@ namespace ArchiSteamFarm {
}
GlobalDatabase = await GlobalDatabase.CreateOrLoad(globalDatabaseFile).ConfigureAwait(false);
if (GlobalDatabase == null) {
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorDatabaseInvalid, globalDatabaseFile));
await Task.Delay(5 * 1000).ConfigureAwait(false);
await Exit(1).ConfigureAwait(false);
return;
}
@ -372,6 +397,7 @@ namespace ArchiSteamFarm {
}
LogManager.Flush();
return true;
}
@ -388,6 +414,7 @@ namespace ArchiSteamFarm {
private static async void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) {
if (e?.ExceptionObject == null) {
ASF.ArchiLogger.LogNullError(nameof(e) + " || " + nameof(e.ExceptionObject));
return;
}
@ -398,6 +425,7 @@ namespace ArchiSteamFarm {
private static async void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) {
if (e?.Exception == null) {
ASF.ArchiLogger.LogNullError(nameof(e) + " || " + nameof(e.Exception));
return;
}
@ -411,6 +439,7 @@ namespace ArchiSteamFarm {
private static void ParsePostInitArgs(IReadOnlyCollection<string> args) {
if (args == null) {
ASF.ArchiLogger.LogNullError(nameof(args));
return;
}
@ -420,17 +449,22 @@ namespace ArchiSteamFarm {
switch (arg) {
case "--cryptkey" when !cryptKeyNext:
cryptKeyNext = true;
break;
case "--no-restart" when !cryptKeyNext:
RestartAllowed = false;
break;
case "--process-required" when !cryptKeyNext:
ProcessRequired = true;
break;
case "--system-required" when !cryptKeyNext:
SystemRequired = true;
break;
default:
if (cryptKeyNext) {
cryptKeyNext = false;
HandleCryptKeyArgument(arg);
@ -446,6 +480,7 @@ namespace ArchiSteamFarm {
private static void ParsePreInitArgs(IReadOnlyCollection<string> args) {
if (args == null) {
ASF.ArchiLogger.LogNullError(nameof(args));
return;
}
@ -455,8 +490,10 @@ namespace ArchiSteamFarm {
switch (arg) {
case "--path" when !pathNext:
pathNext = true;
break;
default:
if (pathNext) {
pathNext = false;
HandlePathArgument(arg);

View file

@ -94,6 +94,7 @@ namespace ArchiSteamFarm {
}
const string request = URL + "/Api/HeartBeat";
Dictionary<string, string> data = new Dictionary<string, string>(2) {
{ "SteamID", Bot.SteamID.ToString() },
{ "Guid", Program.GlobalDatabase.Guid.ToString("N") }
@ -123,17 +124,21 @@ namespace ArchiSteamFarm {
// Don't announce if we don't meet conditions
string tradeToken;
if (!await IsEligibleForMatching().ConfigureAwait(false) || string.IsNullOrEmpty(tradeToken = await Bot.ArchiHandler.GetTradeToken().ConfigureAwait(false))) {
LastAnnouncementCheck = DateTime.UtcNow;
ShouldSendHeartBeats = false;
return;
}
HashSet<Steam.Asset.EType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(type => AcceptedMatchableTypes.Contains(type)).ToHashSet();
if (acceptedMatchableTypes.Count == 0) {
Bot.ArchiLogger.LogNullError(nameof(acceptedMatchableTypes));
LastAnnouncementCheck = DateTime.UtcNow;
ShouldSendHeartBeats = false;
return;
}
@ -142,6 +147,7 @@ namespace ArchiSteamFarm {
// This is actually inventory failure, so we'll stop sending heartbeats but not record it as valid check
if (inventory == null) {
ShouldSendHeartBeats = false;
return;
}
@ -149,10 +155,12 @@ namespace ArchiSteamFarm {
if (inventory.Count < MinItemsCount) {
LastAnnouncementCheck = DateTime.UtcNow;
ShouldSendHeartBeats = false;
return;
}
const string request = URL + "/Api/Announce";
Dictionary<string, string> data = new Dictionary<string, string>(9) {
{ "SteamID", Bot.SteamID.ToString() },
{ "Guid", Program.GlobalDatabase.Guid.ToString("N") },
@ -179,6 +187,7 @@ namespace ArchiSteamFarm {
const string request = URL + "/Api/Bots";
WebBrowser.ObjectResponse<HashSet<ListedUser>> objectResponse = await Program.WebBrowser.UrlGetToJsonObject<HashSet<ListedUser>>(request).ConfigureAwait(false);
return objectResponse?.Content;
}
@ -186,30 +195,35 @@ namespace ArchiSteamFarm {
// Bot must have ASF 2FA
if (!Bot.HasMobileAuthenticator) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.HasMobileAuthenticator) + ": " + Bot.HasMobileAuthenticator));
return false;
}
// Bot must have STM enable in TradingPreferences
if (!Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.BotConfig.TradingPreferences) + ": " + Bot.BotConfig.TradingPreferences));
return false;
}
// Bot must have at least one accepted matchable type set
if ((Bot.BotConfig.MatchableTypes.Count == 0) || Bot.BotConfig.MatchableTypes.All(type => !AcceptedMatchableTypes.Contains(type))) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.BotConfig.MatchableTypes) + ": " + Bot.BotConfig.MatchableTypes));
return false;
}
// Bot must have public inventory
if (!await Bot.ArchiWebHandler.HasPublicInventory().ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.ArchiWebHandler.HasPublicInventory) + ": " + false));
return false;
}
// Bot must have valid API key (e.g. not being restricted account)
if (!await Bot.ArchiWebHandler.HasValidApiKey().ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.WarningFailedWithError, nameof(Bot.ArchiWebHandler.HasValidApiKey) + ": " + false));
return false;
}
@ -219,17 +233,21 @@ namespace ArchiSteamFarm {
private async Task MatchActively() {
if (!Bot.IsConnectedAndLoggedOn || Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) || !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively) || !await IsEligibleForMatching().ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
return;
}
HashSet<Steam.Asset.EType> acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(type => AcceptedMatchableTypes.Contains(type)).ToHashSet();
if (acceptedMatchableTypes.Count == 0) {
Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
return;
}
if (!await MatchActivelySemaphore.WaitAsync(0).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
return;
}
@ -248,6 +266,7 @@ namespace ArchiSteamFarm {
if (!Bot.IsConnectedAndLoggedOn || Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) || !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively) || !await IsEligibleForMatching().ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
break;
}
@ -268,12 +287,15 @@ namespace ArchiSteamFarm {
private async Task<bool> MatchActivelyRound(IReadOnlyCollection<Steam.Asset.EType> acceptedMatchableTypes, IDictionary<ulong, (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs)> triedSteamIDs) {
if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0) || (triedSteamIDs == null)) {
Bot.ArchiLogger.LogNullError(nameof(acceptedMatchableTypes) + " || " + nameof(triedSteamIDs));
return false;
}
HashSet<Steam.Asset> ourInventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, wantedTypes: acceptedMatchableTypes).ConfigureAwait(false);
if ((ourInventory == null) || (ourInventory.Count == 0)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(ourInventory)));
return false;
}
@ -282,12 +304,15 @@ namespace ArchiSteamFarm {
if (Trading.IsEmptyForMatching(fullState, tradableState)) {
// User doesn't have any more dupes in the inventory
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(fullState) + " || " + nameof(tradableState)));
return false;
}
HashSet<ListedUser> listedUsers = await GetListedUsers().ConfigureAwait(false);
if ((listedUsers == null) || (listedUsers.Count == 0)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(listedUsers)));
return false;
}
@ -298,8 +323,10 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericTrace(listedUser.SteamID + "...");
HashSet<Steam.Asset> theirInventory = await Bot.ArchiWebHandler.GetInventory(listedUser.SteamID, tradable: true, wantedSets: fullState.Keys, skippedSets: skippedSetsThisRound).ConfigureAwait(false);
if ((theirInventory == null) || (theirInventory.Count == 0)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(theirInventory)));
continue;
}
@ -333,6 +360,7 @@ namespace ArchiSteamFarm {
foreach (KeyValuePair<ulong, uint> pastChange in pastChanges) {
if (!ourFullSet.TryGetValue(pastChange.Key, out uint fullAmount) || (fullAmount == 0) || (fullAmount < pastChange.Value)) {
Bot.ArchiLogger.LogNullError(nameof(fullAmount));
return false;
}
@ -344,6 +372,7 @@ namespace ArchiSteamFarm {
if (!ourTradableSet.TryGetValue(pastChange.Key, out uint tradableAmount) || (tradableAmount == 0) || (tradableAmount < pastChange.Value)) {
Bot.ArchiLogger.LogNullError(nameof(tradableAmount));
return false;
}
@ -406,6 +435,7 @@ namespace ArchiSteamFarm {
// Update their state based on taken items
if (!theirItems.TryGetValue(theirItem.Key, out uint theirAmount) || (theirAmount == 0)) {
Bot.ArchiLogger.LogNullError(nameof(theirAmount));
return false;
}
@ -418,6 +448,7 @@ namespace ArchiSteamFarm {
itemsInTrade += 2;
match = true;
break;
}
@ -434,6 +465,7 @@ namespace ArchiSteamFarm {
if (skippedSetsThisTrade.Count == 0) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(skippedSetsThisTrade)));
break;
}
@ -443,6 +475,7 @@ namespace ArchiSteamFarm {
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairTypesExchange(itemsToGive, itemsToReceive)) {
// Failsafe
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningFailedWithError, Strings.ErrorAborted));
return false;
}
@ -450,6 +483,7 @@ namespace ArchiSteamFarm {
if (itemsToGive.Select(item => item.AssetID).All(previousAttempt.GivenAssetIDs.Contains) && itemsToReceive.Select(item => item.AssetID).All(previousAttempt.ReceivedAssetIDs.Contains)) {
// This user didn't respond in our previous round, avoid him for remaining ones
triedSteamIDs[listedUser.SteamID] = (byte.MaxValue, previousAttempt.GivenAssetIDs, previousAttempt.ReceivedAssetIDs);
break;
}
@ -471,12 +505,14 @@ namespace ArchiSteamFarm {
if ((mobileTradeOfferIDs != null) && (mobileTradeOfferIDs.Count > 0) && Bot.HasMobileAuthenticator) {
if (!await Bot.Actions.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed);
return false;
}
}
if (!success) {
Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed);
break;
}
@ -514,6 +550,7 @@ namespace ArchiSteamFarm {
}
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ActivelyMatchingItemsRound, skippedSetsThisRound.Count));
return skippedSetsThisRound.Count > 0;
}
@ -550,12 +587,15 @@ namespace ArchiSteamFarm {
switch (value) {
case 0:
MatchableTypes.Remove(Steam.Asset.EType.ProfileBackground);
break;
case 1:
MatchableTypes.Add(Steam.Asset.EType.ProfileBackground);
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}
@ -567,12 +607,15 @@ namespace ArchiSteamFarm {
switch (value) {
case 0:
MatchableTypes.Remove(Steam.Asset.EType.TradingCard);
break;
case 1:
MatchableTypes.Add(Steam.Asset.EType.TradingCard);
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}
@ -584,12 +627,15 @@ namespace ArchiSteamFarm {
switch (value) {
case 0:
MatchableTypes.Remove(Steam.Asset.EType.Emoticon);
break;
case 1:
MatchableTypes.Add(Steam.Asset.EType.Emoticon);
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}
@ -601,12 +647,15 @@ namespace ArchiSteamFarm {
switch (value) {
case 0:
MatchableTypes.Remove(Steam.Asset.EType.FoilTradingCard);
break;
case 1:
MatchableTypes.Add(Steam.Asset.EType.FoilTradingCard);
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}
@ -618,12 +667,15 @@ namespace ArchiSteamFarm {
switch (value) {
case 0:
MatchEverything = false;
break;
case 1:
MatchEverything = true;
break;
default:
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(value), value));
return;
}
}

View file

@ -37,6 +37,7 @@ namespace ArchiSteamFarm.SteamKit2 {
public Task UpdateServerListAsync(IEnumerable<ServerRecord> endpoints) {
if (endpoints == null) {
ASF.ArchiLogger.LogNullError(nameof(endpoints));
return Task.CompletedTask;
}
@ -47,6 +48,7 @@ namespace ArchiSteamFarm.SteamKit2 {
}
ServerListUpdated?.Invoke(this, EventArgs.Empty);
return Task.CompletedTask;
}

View file

@ -24,7 +24,7 @@ using Newtonsoft.Json;
using SteamKit2;
namespace ArchiSteamFarm.SteamKit2 {
internal sealed class ServerRecordEndPoint {
internal sealed class ServerRecordEndPoint : IEquatable<ServerRecordEndPoint> {
[JsonProperty(Required = Required.Always)]
internal readonly string Host;
@ -46,9 +46,8 @@ namespace ArchiSteamFarm.SteamKit2 {
private ServerRecordEndPoint() { }
public bool Equals(ServerRecordEndPoint other) => (Host == other.Host) && (Port == other.Port) && (ProtocolTypes == other.ProtocolTypes);
public override bool Equals(object obj) => (obj != null) && ((obj == this) || (obj is ServerRecordEndPoint serverRecord && Equals(serverRecord)));
public override int GetHashCode() => (Host, Port, ProtocolTypes).GetHashCode();
private bool Equals(ServerRecordEndPoint other) => string.Equals(Host, other.Host) && (Port == other.Port) && (ProtocolTypes == other.ProtocolTypes);
public override int GetHashCode() => RuntimeCompatibility.HashCode.Combine(Host, Port, ProtocolTypes);
}
}

View file

@ -55,8 +55,10 @@ namespace ArchiSteamFarm {
for (byte i = 0; (i < MaxSingleQueuesDaily) && (await IsDiscoveryQueueAvailable().ConfigureAwait(false)).GetValueOrDefault(); i++) {
HashSet<uint> queue = await Bot.ArchiWebHandler.GenerateNewDiscoveryQueue().ConfigureAwait(false);
if ((queue == null) || (queue.Count == 0)) {
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(queue)));
break;
}
@ -69,6 +71,7 @@ namespace ArchiSteamFarm {
}
Bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
return;
}
@ -80,19 +83,23 @@ namespace ArchiSteamFarm {
private async Task<bool?> IsDiscoveryQueueAvailable() {
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetDiscoveryQueuePage().ConfigureAwait(false);
if (htmlDocument == null) {
return null;
}
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='subtext']");
if (htmlNode == null) {
// Valid, no cards for exploring the queue available
return false;
}
string text = htmlNode.InnerText;
if (string.IsNullOrEmpty(text)) {
Bot.ArchiLogger.LogNullError(nameof(text));
return null;
}
@ -110,6 +117,7 @@ namespace ArchiSteamFarm {
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetSteamAwardsPage().ConfigureAwait(false);
HtmlNodeCollection nominationNodes = htmlDocument?.DocumentNode.SelectNodes("//div[@class='vote_nominations store_horizontal_autoslider']");
if (nominationNodes == null) {
// Event ended, error or likewise
return;
@ -117,25 +125,31 @@ namespace ArchiSteamFarm {
foreach (HtmlNode nominationNode in nominationNodes) {
HtmlNode myVoteNode = nominationNode.SelectSingleNode("./div[@class='vote_nomination your_vote']");
if (myVoteNode != null) {
// Already voted
continue;
}
string voteIDText = nominationNode.GetAttributeValue("data-voteid", null);
if (string.IsNullOrEmpty(voteIDText)) {
Bot.ArchiLogger.LogNullError(nameof(voteIDText));
return;
}
if (!byte.TryParse(voteIDText, out byte voteID) || (voteID == 0)) {
Bot.ArchiLogger.LogNullError(nameof(voteID));
return;
}
HtmlNodeCollection voteNodes = nominationNode.SelectNodes("./div[starts-with(@class, 'vote_nomination')]");
if (voteNodes == null) {
Bot.ArchiLogger.LogNullError(nameof(voteNodes));
return;
}
@ -143,13 +157,16 @@ namespace ArchiSteamFarm {
HtmlNode voteNode = voteNodes[Utilities.RandomNext(voteNodes.Count)];
string appIDText = voteNode.GetAttributeValue("data-vote-appid", null);
if (string.IsNullOrEmpty(appIDText)) {
Bot.ArchiLogger.LogNullError(nameof(appIDText));
return;
}
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
Bot.ArchiLogger.LogNullError(nameof(appID));
return;
}

View file

@ -47,6 +47,7 @@ namespace ArchiSteamFarm {
internal static (Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> FullState, Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> TradableState) GetDividedInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
if ((inventory == null) || (inventory.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(inventory));
return (null, null);
}
@ -87,6 +88,7 @@ namespace ArchiSteamFarm {
internal static Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> GetInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
if ((inventory == null) || (inventory.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(inventory));
return null;
}
@ -112,6 +114,7 @@ namespace ArchiSteamFarm {
internal static HashSet<Steam.Asset> GetTradableItemsFromInventory(IReadOnlyCollection<Steam.Asset> inventory, IDictionary<ulong, uint> classIDs) {
if ((inventory == null) || (inventory.Count == 0) || (classIDs == null) || (classIDs.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(inventory) + " || " + nameof(classIDs));
return null;
}
@ -141,12 +144,14 @@ namespace ArchiSteamFarm {
internal static bool IsEmptyForMatching(IReadOnlyDictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> fullState, IReadOnlyDictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> tradableState) {
if ((fullState == null) || (tradableState == null)) {
ASF.ArchiLogger.LogNullError(nameof(fullState) + " || " + nameof(tradableState));
return false;
}
foreach (KeyValuePair<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> tradableSet in tradableState) {
if (!fullState.TryGetValue(tradableSet.Key, out Dictionary<ulong, uint> fullSet) || (fullSet == null) || (fullSet.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(fullSet));
return false;
}
@ -162,19 +167,24 @@ namespace ArchiSteamFarm {
internal static bool IsEmptyForMatching(IReadOnlyDictionary<ulong, uint> fullSet, IReadOnlyDictionary<ulong, uint> tradableSet) {
if ((fullSet == null) || (tradableSet == null)) {
ASF.ArchiLogger.LogNullError(nameof(fullSet) + " || " + nameof(tradableSet));
return false;
}
foreach (KeyValuePair<ulong, uint> tradableItem in tradableSet) {
switch (tradableItem.Value) {
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(tradableItem.Value), tradableItem.Value));
return false;
case 1:
// Single tradable item, can be matchable or not depending on the rest of the inventory
if (!fullSet.TryGetValue(tradableItem.Key, out uint fullAmount) || (fullAmount == 0) || (fullAmount < tradableItem.Value)) {
ASF.ArchiLogger.LogNullError(nameof(fullAmount));
return false;
}
@ -186,6 +196,7 @@ namespace ArchiSteamFarm {
// A single exclusive tradable item is not matchable, continue
continue;
default:
// Any other combination of tradable items is always matchable
return false;
}
@ -198,10 +209,12 @@ namespace ArchiSteamFarm {
internal static bool IsFairTypesExchange(IReadOnlyCollection<Steam.Asset> itemsToGive, IReadOnlyCollection<Steam.Asset> itemsToReceive) {
if ((itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(itemsToGive) + " || " + nameof(itemsToReceive));
return false;
}
Dictionary<uint, Dictionary<Steam.Asset.EType, uint>> itemsToGivePerGame = new Dictionary<uint, Dictionary<Steam.Asset.EType, uint>>();
foreach (Steam.Asset item in itemsToGive) {
if (itemsToGivePerGame.TryGetValue(item.RealAppID, out Dictionary<Steam.Asset.EType, uint> itemsPerType)) {
itemsPerType[item.Type] = itemsPerType.TryGetValue(item.Type, out uint amount) ? amount + item.Amount : item.Amount;
@ -212,6 +225,7 @@ namespace ArchiSteamFarm {
}
Dictionary<uint, Dictionary<Steam.Asset.EType, uint>> itemsToReceivePerGame = new Dictionary<uint, Dictionary<Steam.Asset.EType, uint>>();
foreach (Steam.Asset item in itemsToReceive) {
if (itemsToReceivePerGame.TryGetValue(item.RealAppID, out Dictionary<Steam.Asset.EType, uint> itemsPerType)) {
itemsPerType[item.Type] = itemsPerType.TryGetValue(item.Type, out uint amount) ? amount + item.Amount : item.Amount;
@ -275,16 +289,19 @@ namespace ArchiSteamFarm {
private static Dictionary<(uint AppID, Steam.Asset.EType Type), List<uint>> GetInventorySets(IReadOnlyCollection<Steam.Asset> inventory) {
if ((inventory == null) || (inventory.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(inventory));
return null;
}
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> sets = GetInventoryState(inventory);
return sets.ToDictionary(set => set.Key, set => set.Value.Values.OrderBy(amount => amount).ToList());
}
private static bool IsTradeNeutralOrBetter(HashSet<Steam.Asset> inventory, IReadOnlyCollection<Steam.Asset> itemsToGive, IReadOnlyCollection<Steam.Asset> itemsToReceive) {
if ((inventory == null) || (inventory.Count == 0) || (itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) {
ASF.ArchiLogger.LogNullError(nameof(inventory) + " || " + nameof(itemsToGive) + " || " + nameof(itemsToReceive));
return false;
}
@ -319,6 +336,7 @@ namespace ArchiSteamFarm {
if (amountToGive > 0) {
ASF.ArchiLogger.LogNullError(nameof(amountToGive));
return false;
}
@ -385,6 +403,7 @@ namespace ArchiSteamFarm {
private async Task ParseActiveTrades() {
HashSet<Steam.TradeOffer> tradeOffers = await Bot.ArchiWebHandler.GetActiveTradeOffers().ConfigureAwait(false);
if ((tradeOffers == null) || (tradeOffers.Count == 0)) {
return;
}
@ -402,6 +421,7 @@ namespace ArchiSteamFarm {
if (Bot.HasMobileAuthenticator) {
HashSet<ulong> mobileTradeOfferIDs = results.Where(result => (result.TradeResult != null) && (result.TradeResult.Result == ParseTradeResult.EResult.Accepted) && result.RequiresMobileConfirmation).Select(result => result.TradeResult.TradeOfferID).ToHashSet();
if (mobileTradeOfferIDs.Count > 0) {
if (!await Bot.Actions.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false)) {
return;
@ -418,11 +438,13 @@ namespace ArchiSteamFarm {
private async Task<(ParseTradeResult TradeResult, bool RequiresMobileConfirmation)> ParseTrade(Steam.TradeOffer tradeOffer) {
if (tradeOffer == null) {
Bot.ArchiLogger.LogNullError(nameof(tradeOffer));
return (null, false);
}
if (tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active) {
Bot.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, tradeOffer.State));
return (null, false);
}
@ -430,12 +452,15 @@ namespace ArchiSteamFarm {
// We've already seen this trade
IgnoredTrades.Add(tradeOffer.TradeOfferID);
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IgnoringTrade, tradeOffer.TradeOfferID));
return (new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently), false);
}
ParseTradeResult result = await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false);
if (result == null) {
Bot.ArchiLogger.LogNullError(nameof(result));
return (null, false);
}
@ -456,15 +481,18 @@ namespace ArchiSteamFarm {
case ParseTradeResult.EResult.RejectedPermanently when Bot.BotConfig.BotBehaviour.HasFlag(BotConfig.EBotBehaviour.RejectInvalidTrades):
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.RejectingTrade, tradeOffer.TradeOfferID));
await Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false);
return (result, false);
case ParseTradeResult.EResult.RejectedPermanently:
IgnoredTrades.Add(tradeOffer.TradeOfferID);
goto case ParseTradeResult.EResult.RejectedTemporarily;
case ParseTradeResult.EResult.RejectedTemporarily:
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IgnoringTrade, tradeOffer.TradeOfferID));
return (result, false);
default:
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(result.Result), result.Result));
return (null, false);
}
}
@ -472,6 +500,7 @@ namespace ArchiSteamFarm {
private async Task<ParseTradeResult> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
if (tradeOffer == null) {
Bot.ArchiLogger.LogNullError(nameof(tradeOffer));
return null;
}
@ -490,9 +519,11 @@ namespace ArchiSteamFarm {
// Check if it's donation trade
switch (tradeOffer.ItemsToGive.Count) {
case 0 when tradeOffer.ItemsToReceive.Count == 0:
// If it's steam issue, temporarily ignore it
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
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);
@ -509,6 +540,7 @@ namespace ArchiSteamFarm {
// Otherwise we either accept donations but not bot trades, or we accept bot trades but not donations
bool isBotTrade = (tradeOffer.OtherSteamID64 != 0) && Bot.Bots.Values.Any(bot => bot.SteamID == tradeOffer.OtherSteamID64);
return new ParseTradeResult(tradeOffer.TradeOfferID, (acceptDonations && !isBotTrade) || (acceptBotTrades && isBotTrade) ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.RejectedPermanently, tradeOffer.ItemsToReceive);
}
@ -531,6 +563,7 @@ namespace ArchiSteamFarm {
// Fetch trade hold duration
byte? holdDuration = await Bot.GetTradeHoldDuration(tradeOffer.OtherSteamID64, tradeOffer.TradeOfferID).ConfigureAwait(false);
if (!holdDuration.HasValue) {
// If we can't get trade hold duration, reject trade temporarily
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
@ -558,9 +591,11 @@ namespace ArchiSteamFarm {
// Now check if it's worth for us to do the trade
HashSet<Steam.Asset> inventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, wantedSets: wantedSets).ConfigureAwait(false);
if ((inventory == null) || (inventory.Count == 0)) {
// If we can't check our inventory when not using MatchEverything, this is a temporary failure
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily, tradeOffer.ItemsToReceive);
}

View file

@ -39,6 +39,7 @@ namespace ArchiSteamFarm {
internal static string GetArgsAsText(string[] args, byte argsToSkip, string delimiter) {
if ((args == null) || (args.Length <= argsToSkip) || string.IsNullOrEmpty(delimiter)) {
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(argsToSkip) + " || " + nameof(delimiter));
return null;
}
@ -48,16 +49,19 @@ namespace ArchiSteamFarm {
internal static string GetArgsAsText(string text, byte argsToSkip) {
if (string.IsNullOrEmpty(text)) {
ASF.ArchiLogger.LogNullError(nameof(text));
return null;
}
string[] args = text.Split((char[]) null, argsToSkip + 1, StringSplitOptions.RemoveEmptyEntries);
return args[args.Length - 1];
}
internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) {
if ((cookieContainer == null) || string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) {
ASF.ArchiLogger.LogNullError(nameof(cookieContainer) + " || " + nameof(url) + " || " + nameof(name));
return null;
}
@ -67,10 +71,12 @@ namespace ArchiSteamFarm {
uri = new Uri(url);
} catch (UriFormatException e) {
ASF.ArchiLogger.LogGenericException(e);
return null;
}
CookieCollection cookies = cookieContainer.GetCookies(uri);
return cookies.Count > 0 ? (from Cookie cookie in cookies where cookie.Name.Equals(name) select cookie.Value).FirstOrDefault() : null;
}
@ -79,6 +85,7 @@ namespace ArchiSteamFarm {
internal static void InBackground(Action action, bool longRunning = false) {
if (action == null) {
ASF.ArchiLogger.LogNullError(nameof(action));
return;
}
@ -94,6 +101,7 @@ namespace ArchiSteamFarm {
internal static void InBackground<T>(Func<T> function, bool longRunning = false) {
if (function == null) {
ASF.ArchiLogger.LogNullError(nameof(function));
return;
}
@ -109,6 +117,7 @@ namespace ArchiSteamFarm {
internal static async Task<IList<T>> InParallel<T>(IEnumerable<Task<T>> tasks) {
if (tasks == null) {
ASF.ArchiLogger.LogNullError(nameof(tasks));
return null;
}
@ -125,6 +134,7 @@ namespace ArchiSteamFarm {
break;
default:
results = await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
@ -134,11 +144,13 @@ namespace ArchiSteamFarm {
internal static async Task InParallel(IEnumerable<Task> tasks) {
if (tasks == null) {
ASF.ArchiLogger.LogNullError(nameof(tasks));
return;
}
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
foreach (Task task in tasks) {
await task.ConfigureAwait(false);
}
@ -146,6 +158,7 @@ namespace ArchiSteamFarm {
break;
default:
await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
}
@ -153,6 +166,7 @@ namespace ArchiSteamFarm {
internal static bool IsValidCdKey(string key) {
if (string.IsNullOrEmpty(key)) {
ASF.ArchiLogger.LogNullError(nameof(key));
return false;
}
@ -162,10 +176,12 @@ namespace ArchiSteamFarm {
internal static bool IsValidHexadecimalString(string text) {
if (string.IsNullOrEmpty(text)) {
ASF.ArchiLogger.LogNullError(nameof(text));
return false;
}
const byte split = 16;
for (byte i = 0; i < text.Length; i += split) {
string textPart = string.Join("", text.Skip(i).Take(split));
@ -186,6 +202,7 @@ namespace ArchiSteamFarm {
internal static int RandomNext(int maxWithout) {
if (maxWithout <= 0) {
ASF.ArchiLogger.LogNullError(nameof(maxWithout));
return -1;
}
@ -202,6 +219,7 @@ namespace ArchiSteamFarm {
StringBuilder result = new StringBuilder();
ConsoleKeyInfo keyInfo;
while ((keyInfo = Console.ReadKey(true)).Key != ConsoleKey.Enter) {
if (!char.IsControl(keyInfo.KeyChar)) {
result.Append(keyInfo.KeyChar);
@ -221,6 +239,7 @@ namespace ArchiSteamFarm {
}
Console.WriteLine();
return result.ToString();
}

View file

@ -89,6 +89,7 @@ namespace ArchiSteamFarm {
internal static HtmlDocument StringToHtmlDocument(string html) {
if (html == null) {
ASF.ArchiLogger.LogNullError(nameof(html));
return null;
}
@ -101,6 +102,7 @@ namespace ArchiSteamFarm {
internal async Task<BinaryResponse> UrlGetToBinaryWithProgress(string request, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -126,6 +128,7 @@ namespace ArchiSteamFarm {
while (contentStream.CanRead) {
int read = await contentStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
if (read == 0) {
break;
}
@ -148,10 +151,12 @@ namespace ArchiSteamFarm {
}
} catch (Exception e) {
ArchiLogger.LogGenericDebuggingException(e);
return null;
}
ArchiLogger.LogGenericDebug("100%");
return new BinaryResponse(response, ms.ToArray());
}
}
@ -168,16 +173,19 @@ namespace ArchiSteamFarm {
internal async Task<HtmlDocumentResponse> UrlGetToHtmlDocument(string request, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
StringResponse response = await UrlGetToString(request, referer, maxTries).ConfigureAwait(false);
return response != null ? new HtmlDocumentResponse(response) : null;
}
internal async Task<ObjectResponse<T>> UrlGetToJsonObject<T>(string request, string referer = null, byte maxTries = MaxTries) where T : class {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -216,6 +224,7 @@ namespace ArchiSteamFarm {
internal async Task<StringResponse> UrlGetToString(string request, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -240,6 +249,7 @@ namespace ArchiSteamFarm {
internal async Task<XmlDocumentResponse> UrlGetToXmlDocument(string request, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -256,6 +266,7 @@ namespace ArchiSteamFarm {
xmlDocument.LoadXml(response.Content);
} catch (XmlException e) {
ArchiLogger.LogGenericWarningException(e);
continue;
}
@ -273,6 +284,7 @@ namespace ArchiSteamFarm {
internal async Task<BasicResponse> UrlHead(string request, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -297,6 +309,7 @@ namespace ArchiSteamFarm {
internal async Task<BasicResponse> UrlPost(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -321,16 +334,19 @@ namespace ArchiSteamFarm {
internal async Task<HtmlDocumentResponse> UrlPostToHtmlDocument(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
StringResponse response = await UrlPostToString(request, data, referer, maxTries).ConfigureAwait(false);
return response != null ? new HtmlDocumentResponse(response) : null;
}
internal async Task<ObjectResponse<T>> UrlPostToJsonObject<T>(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, byte maxTries = MaxTries) where T : class {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}
@ -369,6 +385,7 @@ namespace ArchiSteamFarm {
private async Task<HttpResponseMessage> InternalGet(string request, string referer = null, HttpCompletionOption httpCompletionOptions = HttpCompletionOption.ResponseContentRead) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
@ -378,6 +395,7 @@ namespace ArchiSteamFarm {
private async Task<HttpResponseMessage> InternalHead(string request, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
@ -387,6 +405,7 @@ namespace ArchiSteamFarm {
private async Task<HttpResponseMessage> InternalPost(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null) {
if (string.IsNullOrEmpty(request)) {
ArchiLogger.LogNullError(nameof(request));
return null;
}
@ -396,6 +415,7 @@ namespace ArchiSteamFarm {
private async Task<HttpResponseMessage> InternalRequest(Uri requestUri, HttpMethod httpMethod, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, byte maxRedirections = MaxTries) {
if ((requestUri == null) || (httpMethod == null)) {
ArchiLogger.LogNullError(nameof(requestUri) + " || " + nameof(httpMethod));
return null;
}
@ -407,6 +427,7 @@ namespace ArchiSteamFarm {
request.Content = new FormUrlEncodedContent(data);
} catch (UriFormatException e) {
ArchiLogger.LogGenericException(e);
return null;
}
}
@ -423,6 +444,7 @@ namespace ArchiSteamFarm {
response = await HttpClient.SendAsync(request, httpCompletionOption).ConfigureAwait(false);
} catch (Exception e) {
ArchiLogger.LogGenericDebuggingException(e);
return null;
}
}
@ -451,13 +473,17 @@ 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));
break;
}
} else {
@ -465,6 +491,7 @@ namespace ArchiSteamFarm {
}
response.Dispose();
return await InternalRequest(redirectUri, httpMethod, data, referer, httpCompletionOption, --maxRedirections).ConfigureAwait(false);
}
@ -480,6 +507,7 @@ namespace ArchiSteamFarm {
private async Task<StringResponse> UrlPostToString(string request, IReadOnlyCollection<KeyValuePair<string, string>> data = null, string referer = null, byte maxTries = MaxTries) {
if (string.IsNullOrEmpty(request) || (maxTries == 0)) {
ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries));
return null;
}