mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +00:00
Big code review
This commit is contained in:
@@ -26,6 +26,7 @@ using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class ArchiHandler : ClientMsgHandler {
|
||||
@@ -39,7 +40,7 @@ namespace ArchiSteamFarm {
|
||||
*/
|
||||
|
||||
internal sealed class NotificationsCallback : CallbackMsg {
|
||||
internal class Notification {
|
||||
internal sealed class Notification {
|
||||
internal enum ENotificationType {
|
||||
Unknown = 0,
|
||||
Trading = 1,
|
||||
@@ -48,7 +49,7 @@ namespace ArchiSteamFarm {
|
||||
internal ENotificationType NotificationType { get; set; }
|
||||
}
|
||||
|
||||
internal List<Notification> Notifications { get; private set; }
|
||||
internal readonly List<Notification> Notifications;
|
||||
|
||||
internal NotificationsCallback(JobID jobID, CMsgClientUserNotifications msg) {
|
||||
JobID = jobID;
|
||||
@@ -67,8 +68,8 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
internal sealed class OfflineMessageCallback : CallbackMsg {
|
||||
internal uint OfflineMessages { get; private set; }
|
||||
internal List<uint> Users { get; private set; }
|
||||
internal readonly uint OfflineMessages;
|
||||
internal readonly List<uint> Users;
|
||||
|
||||
internal OfflineMessageCallback(JobID jobID, CMsgClientOfflineMessageNotification msg) {
|
||||
JobID = jobID;
|
||||
@@ -94,10 +95,10 @@ namespace ArchiSteamFarm {
|
||||
OnCooldown = 53
|
||||
}
|
||||
|
||||
internal EResult Result { get; private set; }
|
||||
internal EPurchaseResult PurchaseResult { get; private set; }
|
||||
internal KeyValue ReceiptInfo { get; private set; }
|
||||
internal Dictionary<uint, string> Items { get; private set; }
|
||||
internal readonly EResult Result;
|
||||
internal readonly EPurchaseResult PurchaseResult;
|
||||
internal readonly KeyValue ReceiptInfo;
|
||||
internal readonly Dictionary<uint, string> Items;
|
||||
|
||||
internal PurchaseResponseCallback(JobID jobID, CMsgClientPurchaseResponse msg) {
|
||||
JobID = jobID;
|
||||
@@ -106,21 +107,22 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
ReceiptInfo = new KeyValue();
|
||||
Items = new Dictionary<uint, string>();
|
||||
|
||||
Result = (EResult) msg.eresult;
|
||||
PurchaseResult = (EPurchaseResult) msg.purchase_result_details;
|
||||
|
||||
ReceiptInfo = new KeyValue();
|
||||
using (MemoryStream ms = new MemoryStream(msg.purchase_receipt_info)) {
|
||||
if (!ReceiptInfo.TryReadAsBinary(ms)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValue lineItem in ReceiptInfo["lineitems"].Children) {
|
||||
List<KeyValue> lineItems = ReceiptInfo["lineitems"].Children;
|
||||
Items = new Dictionary<uint, string>(lineItems.Count);
|
||||
|
||||
foreach (KeyValue lineItem in lineItems) {
|
||||
uint appID = (uint) lineItem["PackageID"].AsUnsignedLong();
|
||||
string gameName = lineItem["ItemDescription"].AsString();
|
||||
gameName = Utilities.UrlDecode(gameName); // Apparently steam expects client to decode sent HTML
|
||||
gameName = WebUtility.UrlDecode(gameName); // Apparently steam expects client to decode sent HTML
|
||||
Items.Add(appID, gameName);
|
||||
}
|
||||
}
|
||||
@@ -180,7 +182,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
internal void PlayGames(ICollection<uint> gameIDs) {
|
||||
if (!Client.IsConnected) {
|
||||
if (gameIDs == null || gameIDs.Count == 0 || !Client.IsConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ using HtmlAgilityPack;
|
||||
using SteamKit2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
@@ -39,60 +38,9 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly string ApiKey;
|
||||
private readonly Dictionary<string, string> Cookie = new Dictionary<string, string>();
|
||||
private readonly Dictionary<string, string> Cookie = new Dictionary<string, string>(3);
|
||||
|
||||
private ulong SteamID;
|
||||
private string VanityURL;
|
||||
|
||||
// This is required because home_process request must be done on final URL
|
||||
private string GetHomeProcess() {
|
||||
if (!string.IsNullOrEmpty(VanityURL)) {
|
||||
return "https://steamcommunity.com/id/" + VanityURL + "/home_process";
|
||||
} else if (SteamID != 0) {
|
||||
return "https://steamcommunity.com/profiles/" + SteamID + "/home_process";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UnlockParentalAccount(string parentalPin) {
|
||||
if (string.IsNullOrEmpty(parentalPin) || parentalPin.Equals("0")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Unlocking parental account...", Bot.BotName);
|
||||
Dictionary<string, string> data = new Dictionary<string, string>() {
|
||||
{ "pin", parentalPin }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost("https://steamcommunity.com/parental/ajaxunlock", data, Cookie, "https://steamcommunity.com/").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<string> setCookieValues;
|
||||
if (!response.Headers.TryGetValues("Set-Cookie", out setCookieValues)) {
|
||||
Logging.LogNullError("setCookieValues", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string setCookieValue in setCookieValues) {
|
||||
if (setCookieValue.Contains("steamparental=")) {
|
||||
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=") + 14);
|
||||
setCookie = setCookie.Substring(0, setCookie.IndexOf(';'));
|
||||
Cookie["steamparental"] = setCookie;
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.LogGenericWarning("Failed to unlock parental account!", Bot.BotName);
|
||||
}
|
||||
|
||||
internal ArchiWebHandler(Bot bot, string apiKey) {
|
||||
Bot = bot;
|
||||
@@ -102,13 +50,12 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<bool> Init(SteamClient steamClient, string webAPIUserNonce, string vanityURL, string parentalPin) {
|
||||
internal async Task<bool> Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) {
|
||||
if (steamClient == null || steamClient.SteamID == null || string.IsNullOrEmpty(webAPIUserNonce)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SteamID = steamClient.SteamID;
|
||||
VanityURL = vanityURL;
|
||||
|
||||
string sessionID = Convert.ToBase64String(Encoding.UTF8.GetBytes(SteamID.ToString()));
|
||||
|
||||
@@ -161,7 +108,6 @@ namespace ArchiSteamFarm {
|
||||
Cookie["sessionid"] = sessionID;
|
||||
Cookie["steamLogin"] = steamLogin;
|
||||
Cookie["steamLoginSecure"] = steamLoginSecure;
|
||||
Cookie["birthtime"] = "-473356799";
|
||||
|
||||
await UnlockParentalAccount(parentalPin).ConfigureAwait(false);
|
||||
return true;
|
||||
@@ -229,28 +175,16 @@ namespace ArchiSteamFarm {
|
||||
SteamTradeOffer tradeOffer = new SteamTradeOffer {
|
||||
tradeofferid = trade["tradeofferid"].AsString(),
|
||||
accountid_other = trade["accountid_other"].AsInteger(),
|
||||
message = trade["message"].AsString(),
|
||||
expiration_time = trade["expiration_time"].AsInteger(),
|
||||
trade_offer_state = trade["trade_offer_state"].AsEnum<SteamTradeOffer.ETradeOfferState>(),
|
||||
items_to_give = new List<SteamItem>(),
|
||||
items_to_receive = new List<SteamItem>(),
|
||||
is_our_offer = trade["is_our_offer"].AsBoolean(),
|
||||
time_created = trade["time_created"].AsInteger(),
|
||||
time_updated = trade["time_updated"].AsInteger(),
|
||||
from_real_time_trade = trade["from_real_time_trade"].AsBoolean(),
|
||||
escrow_end_date = trade["escrow_end_date"].AsInteger(),
|
||||
confirmation_method = trade["confirmation_method"].AsEnum<SteamTradeOffer.ETradeOfferConfirmationMethod>()
|
||||
trade_offer_state = trade["trade_offer_state"].AsEnum<SteamTradeOffer.ETradeOfferState>()
|
||||
};
|
||||
foreach (KeyValue item in trade["items_to_give"].Children) {
|
||||
tradeOffer.items_to_give.Add(new SteamItem {
|
||||
appid = item["appid"].AsString(),
|
||||
contextid = item["contextid"].AsString(),
|
||||
assetid = item["assetid"].AsString(),
|
||||
currencyid = item["currencyid"].AsString(),
|
||||
classid = item["classid"].AsString(),
|
||||
instanceid = item["instanceid"].AsString(),
|
||||
amount = item["amount"].AsString(),
|
||||
missing = item["missing"].AsBoolean()
|
||||
});
|
||||
}
|
||||
foreach (KeyValue item in trade["items_to_receive"].Children) {
|
||||
@@ -258,11 +192,9 @@ namespace ArchiSteamFarm {
|
||||
appid = item["appid"].AsString(),
|
||||
contextid = item["contextid"].AsString(),
|
||||
assetid = item["assetid"].AsString(),
|
||||
currencyid = item["currencyid"].AsString(),
|
||||
classid = item["classid"].AsString(),
|
||||
instanceid = item["instanceid"].AsString(),
|
||||
amount = item["amount"].AsString(),
|
||||
missing = item["missing"].AsBoolean()
|
||||
});
|
||||
}
|
||||
result.Add(tradeOffer);
|
||||
@@ -283,7 +215,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
string request = "https://steamcommunity.com/gid/" + clanID;
|
||||
|
||||
Dictionary<string, string> data = new Dictionary<string, string>() {
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(2) {
|
||||
{"sessionID", sessionID},
|
||||
{"action", "join"}
|
||||
};
|
||||
@@ -301,36 +233,6 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task<bool> LeaveClan(ulong clanID) {
|
||||
if (clanID == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string sessionID;
|
||||
if (!Cookie.TryGetValue("sessionid", out sessionID)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string request = GetHomeProcess();
|
||||
Dictionary<string, string> data = new Dictionary<string, string>() {
|
||||
{"sessionID", sessionID},
|
||||
{"action", "leaveGroup"},
|
||||
{"groupId", clanID.ToString()}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task<bool> AcceptTradeOffer(ulong tradeID) {
|
||||
if (tradeID == 0) {
|
||||
return false;
|
||||
@@ -344,7 +246,7 @@ namespace ArchiSteamFarm {
|
||||
string referer = "https://steamcommunity.com/tradeoffer/" + tradeID;
|
||||
string request = referer + "/accept";
|
||||
|
||||
Dictionary<string, string> data = new Dictionary<string, string>() {
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
||||
{"sessionid", sessionID},
|
||||
{"serverid", "1"},
|
||||
{"tradeofferid", tradeID.ToString()}
|
||||
@@ -404,11 +306,19 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<SteamItem> result = new List<SteamItem>();
|
||||
|
||||
IEnumerable<JToken> jTokens = jObject.SelectTokens("$.rgInventory.*");
|
||||
if (jTokens == null) {
|
||||
Logging.LogNullError("jTokens", Bot.BotName);
|
||||
return null;
|
||||
}
|
||||
|
||||
List<SteamItem> result = new List<SteamItem>();
|
||||
foreach (JToken jToken in jTokens) {
|
||||
result.Add(JsonConvert.DeserializeObject<SteamItem>(jToken.ToString()));
|
||||
try {
|
||||
result.Add(JsonConvert.DeserializeObject<SteamItem>(jToken.ToString()));
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, Bot.BotName);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -424,7 +334,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<SteamTradeOfferRequest> trades = new List<SteamTradeOfferRequest>();
|
||||
List<SteamTradeOfferRequest> trades = new List<SteamTradeOfferRequest>(1 + inventory.Count / Trading.MaxItemsPerTrade);
|
||||
|
||||
SteamTradeOfferRequest singleTrade = null;
|
||||
for (ushort i = 0; i < inventory.Count; i++) {
|
||||
@@ -450,7 +360,7 @@ namespace ArchiSteamFarm {
|
||||
string request = referer + "/send";
|
||||
|
||||
foreach (SteamTradeOfferRequest trade in trades) {
|
||||
Dictionary<string, string> data = new Dictionary<string, string>() {
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(6) {
|
||||
{"sessionid", sessionID},
|
||||
{"serverid", "1"},
|
||||
{"partner", partnerID.ToString()},
|
||||
@@ -508,5 +418,44 @@ namespace ArchiSteamFarm {
|
||||
|
||||
return htmlDocument;
|
||||
}
|
||||
|
||||
private async Task UnlockParentalAccount(string parentalPin) {
|
||||
if (string.IsNullOrEmpty(parentalPin) || parentalPin.Equals("0")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Unlocking parental account...", Bot.BotName);
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
||||
{ "pin", parentalPin }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost("https://steamcommunity.com/parental/ajaxunlock", data, Cookie, "https://steamcommunity.com/").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<string> setCookieValues;
|
||||
if (!response.Headers.TryGetValues("Set-Cookie", out setCookieValues)) {
|
||||
Logging.LogNullError("setCookieValues", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string setCookieValue in setCookieValues) {
|
||||
if (setCookieValue.Contains("steamparental=")) {
|
||||
string setCookie = setCookieValue.Substring(setCookieValue.IndexOf("steamparental=") + 14);
|
||||
setCookie = setCookie.Substring(0, setCookie.IndexOf(';'));
|
||||
Cookie["steamparental"] = setCookie;
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.LogGenericWarning("Failed to unlock parental account!", Bot.BotName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,14 +41,19 @@ namespace ArchiSteamFarm {
|
||||
private const ulong ArchiSCFarmGroup = 103582791440160998;
|
||||
private const ushort CallbackSleep = 500; // In miliseconds
|
||||
|
||||
private static readonly uint LoginID = MsgClientLogon.ObfuscationMask; // This must be the same for all ASF bots and all ASF processes
|
||||
|
||||
internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>();
|
||||
internal static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 303700, 335590, 368020, 425280 };
|
||||
|
||||
private static readonly uint LoginID = MsgClientLogon.ObfuscationMask; // This must be the same for all ASF bots and all ASF processes
|
||||
|
||||
private readonly string ConfigFile, LoginKeyFile, MobileAuthenticatorFile, SentryFile;
|
||||
private readonly Timer SendItemsTimer;
|
||||
|
||||
internal readonly string BotName;
|
||||
internal readonly ArchiHandler ArchiHandler;
|
||||
internal readonly ArchiWebHandler ArchiWebHandler;
|
||||
internal readonly SteamClient SteamClient;
|
||||
|
||||
private readonly CallbackManager CallbackManager;
|
||||
private readonly CardsFarmer CardsFarmer;
|
||||
private readonly SteamApps SteamApps;
|
||||
@@ -56,15 +61,6 @@ namespace ArchiSteamFarm {
|
||||
private readonly SteamUser SteamUser;
|
||||
private readonly Trading Trading;
|
||||
|
||||
internal readonly string BotName;
|
||||
internal readonly ArchiHandler ArchiHandler;
|
||||
internal readonly ArchiWebHandler ArchiWebHandler;
|
||||
internal readonly SteamClient SteamClient;
|
||||
|
||||
private bool InvalidPassword = false;
|
||||
private bool LoggedInElsewhere = false;
|
||||
private string AuthCode, LoginKey, TwoFactorAuth;
|
||||
|
||||
internal bool KeepRunning { get; private set; } = false;
|
||||
internal SteamGuardAccount SteamGuardAccount { get; private set; }
|
||||
|
||||
@@ -88,19 +84,12 @@ namespace ArchiSteamFarm {
|
||||
internal bool SendOnFarmingFinished { get; private set; } = false;
|
||||
internal string SteamTradeToken { get; private set; } = "null";
|
||||
internal byte SendTradePeriod { get; private set; } = 0;
|
||||
internal HashSet<uint> Blacklist { get; private set; } = new HashSet<uint>();
|
||||
internal HashSet<uint> Blacklist { get; } = new HashSet<uint>();
|
||||
internal bool Statistics { get; private set; } = true;
|
||||
|
||||
private static bool IsValidCdKey(string key) {
|
||||
if (string.IsNullOrEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steam keys are offered in many formats: https://support.steampowered.com/kb_article.php?ref=7480-WUSF-3601
|
||||
// It's pointless to implement them all, so we'll just do a simple check if key is supposed to be valid
|
||||
// Every valid key, apart from Prey one has at least two dashes
|
||||
return Utilities.GetCharCountInString(key, '-') >= 2;
|
||||
}
|
||||
private bool InvalidPassword = false;
|
||||
private bool LoggedInElsewhere = false;
|
||||
private string AuthCode, LoginKey, TwoFactorAuth;
|
||||
|
||||
internal static string GetAnyBotName() {
|
||||
foreach (string botName in Bots.Keys) {
|
||||
@@ -130,6 +119,17 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValidCdKey(string key) {
|
||||
if (string.IsNullOrEmpty(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Steam keys are offered in many formats: https://support.steampowered.com/kb_article.php?ref=7480-WUSF-3601
|
||||
// It's pointless to implement them all, so we'll just do a simple check if key is supposed to be valid
|
||||
// Every valid key, apart from Prey one has at least two dashes
|
||||
return Utilities.GetCharCountInString(key, '-') >= 2;
|
||||
}
|
||||
|
||||
internal Bot(string botName) {
|
||||
if (Bots.ContainsKey(botName)) {
|
||||
return;
|
||||
@@ -137,10 +137,11 @@ namespace ArchiSteamFarm {
|
||||
|
||||
BotName = botName;
|
||||
|
||||
ConfigFile = Path.Combine(Program.ConfigDirectory, botName + ".xml");
|
||||
LoginKeyFile = Path.Combine(Program.ConfigDirectory, botName + ".key");
|
||||
MobileAuthenticatorFile = Path.Combine(Program.ConfigDirectory, botName + ".auth");
|
||||
SentryFile = Path.Combine(Program.ConfigDirectory, botName + ".bin");
|
||||
string botPath = Path.Combine(Program.ConfigDirectory, botName);
|
||||
ConfigFile = botPath + ".xml";
|
||||
LoginKeyFile = botPath + ".key";
|
||||
MobileAuthenticatorFile = botPath + ".auth";
|
||||
SentryFile = botPath + ".bin";
|
||||
|
||||
if (!ReadConfig()) {
|
||||
return;
|
||||
@@ -234,181 +235,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private bool LinkMobileAuthenticator() {
|
||||
if (SteamGuardAccount != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Linking new ASF MobileAuthenticator...", BotName);
|
||||
UserLogin userLogin = new UserLogin(SteamLogin, SteamPassword);
|
||||
LoginResult loginResult;
|
||||
while ((loginResult = userLogin.DoLogin()) != LoginResult.LoginOkay) {
|
||||
switch (loginResult) {
|
||||
case LoginResult.NeedEmail:
|
||||
userLogin.EmailCode = Program.GetUserInput(BotName, Program.EUserInputType.SteamGuard);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericError("Unhandled situation: " + loginResult, BotName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticatorLinker authenticatorLinker = new AuthenticatorLinker(userLogin.Session);
|
||||
|
||||
AuthenticatorLinker.LinkResult linkResult;
|
||||
while ((linkResult = authenticatorLinker.AddAuthenticator()) != AuthenticatorLinker.LinkResult.AwaitingFinalization) {
|
||||
switch (linkResult) {
|
||||
case AuthenticatorLinker.LinkResult.MustProvidePhoneNumber:
|
||||
authenticatorLinker.PhoneNumber = Program.GetUserInput(BotName, Program.EUserInputType.PhoneNumber);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericError("Unhandled situation: " + linkResult, BotName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SteamGuardAccount = authenticatorLinker.LinkedAccount;
|
||||
|
||||
try {
|
||||
File.WriteAllText(MobileAuthenticatorFile, JsonConvert.SerializeObject(SteamGuardAccount));
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticatorLinker.FinalizeResult finalizeResult = authenticatorLinker.FinalizeAddAuthenticator(Program.GetUserInput(BotName, Program.EUserInputType.SMS));
|
||||
if (finalizeResult != AuthenticatorLinker.FinalizeResult.Success) {
|
||||
Logging.LogGenericError("Unhandled situation: " + finalizeResult, BotName);
|
||||
DelinkMobileAuthenticator();
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Successfully linked ASF as new mobile authenticator for this account!", BotName);
|
||||
Program.GetUserInput(BotName, Program.EUserInputType.RevocationCode, SteamGuardAccount.RevocationCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DelinkMobileAuthenticator() {
|
||||
if (SteamGuardAccount == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = SteamGuardAccount.DeactivateAuthenticator();
|
||||
SteamGuardAccount = null;
|
||||
|
||||
try {
|
||||
File.Delete(MobileAuthenticatorFile);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ReadConfig() {
|
||||
if (!File.Exists(ConfigFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
using (XmlReader reader = XmlReader.Create(ConfigFile)) {
|
||||
while (reader.Read()) {
|
||||
if (reader.NodeType != XmlNodeType.Element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string key = reader.Name;
|
||||
if (string.IsNullOrEmpty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string value = reader.GetAttribute("value");
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case "Enabled":
|
||||
Enabled = bool.Parse(value);
|
||||
break;
|
||||
case "SteamLogin":
|
||||
SteamLogin = value;
|
||||
break;
|
||||
case "SteamPassword":
|
||||
SteamPassword = value;
|
||||
break;
|
||||
case "SteamNickname":
|
||||
SteamNickname = value;
|
||||
break;
|
||||
case "SteamApiKey":
|
||||
SteamApiKey = value;
|
||||
break;
|
||||
case "SteamTradeToken":
|
||||
SteamTradeToken = value;
|
||||
break;
|
||||
case "SteamParentalPIN":
|
||||
SteamParentalPIN = value;
|
||||
break;
|
||||
case "SteamMasterID":
|
||||
SteamMasterID = ulong.Parse(value);
|
||||
break;
|
||||
case "SteamMasterClanID":
|
||||
SteamMasterClanID = ulong.Parse(value);
|
||||
break;
|
||||
case "StartOnLaunch":
|
||||
StartOnLaunch = bool.Parse(value);
|
||||
break;
|
||||
case "UseAsfAsMobileAuthenticator":
|
||||
UseAsfAsMobileAuthenticator = bool.Parse(value);
|
||||
break;
|
||||
case "CardDropsRestricted":
|
||||
CardDropsRestricted = bool.Parse(value);
|
||||
break;
|
||||
case "FarmOffline":
|
||||
FarmOffline = bool.Parse(value);
|
||||
break;
|
||||
case "HandleOfflineMessages":
|
||||
HandleOfflineMessages = bool.Parse(value);
|
||||
break;
|
||||
case "ForwardKeysToOtherBots":
|
||||
ForwardKeysToOtherBots = bool.Parse(value);
|
||||
break;
|
||||
case "DistributeKeys":
|
||||
DistributeKeys = bool.Parse(value);
|
||||
break;
|
||||
case "ShutdownOnFarmingFinished":
|
||||
ShutdownOnFarmingFinished = bool.Parse(value);
|
||||
break;
|
||||
case "SendOnFarmingFinished":
|
||||
SendOnFarmingFinished = bool.Parse(value);
|
||||
break;
|
||||
case "SendTradePeriod":
|
||||
SendTradePeriod = byte.Parse(value);
|
||||
break;
|
||||
case "Blacklist":
|
||||
Blacklist.Clear();
|
||||
foreach (string appID in value.Split(',')) {
|
||||
Blacklist.Add(uint.Parse(appID));
|
||||
}
|
||||
break;
|
||||
case "Statistics":
|
||||
Statistics = bool.Parse(value);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericWarning("Unrecognized config value: " + key + "=" + value, BotName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
Logging.LogGenericError("Your config for this bot instance is invalid, it won't run!", BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task Restart() {
|
||||
Stop();
|
||||
await Utilities.SleepAsync(500).ConfigureAwait(false);
|
||||
@@ -460,26 +286,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCallbacks() {
|
||||
TimeSpan timeSpan = TimeSpan.FromMilliseconds(CallbackSleep);
|
||||
while (KeepRunning) {
|
||||
CallbackManager.RunWaitCallbacks(timeSpan);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendMessage(ulong steamID, string message) {
|
||||
if (steamID == 0 || string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: I really need something better
|
||||
if (steamID < 110300000000000000) {
|
||||
SteamFriends.SendChatMessage(steamID, EChatEntryType.ChatMsg, message);
|
||||
} else {
|
||||
SteamFriends.SendChatRoomMessage(steamID, EChatEntryType.ChatMsg, message);
|
||||
}
|
||||
}
|
||||
|
||||
internal string ResponseStatus() {
|
||||
if (CardsFarmer.CurrentGamesFarming.Count > 0) {
|
||||
return "Bot " + BotName + " is currently farming appIDs: " + string.Join(", ", CardsFarmer.CurrentGamesFarming) + " and has a total of " + CardsFarmer.GamesToFarm.Count + " games left to farm.";
|
||||
@@ -966,6 +772,13 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCallbacks() {
|
||||
TimeSpan timeSpan = TimeSpan.FromMilliseconds(CallbackSleep);
|
||||
while (KeepRunning) {
|
||||
CallbackManager.RunWaitCallbacks(timeSpan);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleMessage(ulong steamID, string message) {
|
||||
if (steamID == 0 || string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
@@ -974,6 +787,90 @@ namespace ArchiSteamFarm {
|
||||
SendMessage(steamID, await HandleMessage(message).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
private void SendMessage(ulong steamID, string message) {
|
||||
if (steamID == 0 || string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: I really need something better
|
||||
if (steamID < 110300000000000000) {
|
||||
SteamFriends.SendChatMessage(steamID, EChatEntryType.ChatMsg, message);
|
||||
} else {
|
||||
SteamFriends.SendChatRoomMessage(steamID, EChatEntryType.ChatMsg, message);
|
||||
}
|
||||
}
|
||||
|
||||
private bool LinkMobileAuthenticator() {
|
||||
if (SteamGuardAccount != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Linking new ASF MobileAuthenticator...", BotName);
|
||||
UserLogin userLogin = new UserLogin(SteamLogin, SteamPassword);
|
||||
LoginResult loginResult;
|
||||
while ((loginResult = userLogin.DoLogin()) != LoginResult.LoginOkay) {
|
||||
switch (loginResult) {
|
||||
case LoginResult.NeedEmail:
|
||||
userLogin.EmailCode = Program.GetUserInput(BotName, Program.EUserInputType.SteamGuard);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericError("Unhandled situation: " + loginResult, BotName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuthenticatorLinker authenticatorLinker = new AuthenticatorLinker(userLogin.Session);
|
||||
|
||||
AuthenticatorLinker.LinkResult linkResult;
|
||||
while ((linkResult = authenticatorLinker.AddAuthenticator()) != AuthenticatorLinker.LinkResult.AwaitingFinalization) {
|
||||
switch (linkResult) {
|
||||
case AuthenticatorLinker.LinkResult.MustProvidePhoneNumber:
|
||||
authenticatorLinker.PhoneNumber = Program.GetUserInput(BotName, Program.EUserInputType.PhoneNumber);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericError("Unhandled situation: " + linkResult, BotName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SteamGuardAccount = authenticatorLinker.LinkedAccount;
|
||||
|
||||
try {
|
||||
File.WriteAllText(MobileAuthenticatorFile, JsonConvert.SerializeObject(SteamGuardAccount));
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticatorLinker.FinalizeResult finalizeResult = authenticatorLinker.FinalizeAddAuthenticator(Program.GetUserInput(BotName, Program.EUserInputType.SMS));
|
||||
if (finalizeResult != AuthenticatorLinker.FinalizeResult.Success) {
|
||||
Logging.LogGenericError("Unhandled situation: " + finalizeResult, BotName);
|
||||
DelinkMobileAuthenticator();
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Successfully linked ASF as new mobile authenticator for this account!", BotName);
|
||||
Program.GetUserInput(BotName, Program.EUserInputType.RevocationCode, SteamGuardAccount.RevocationCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool DelinkMobileAuthenticator() {
|
||||
if (SteamGuardAccount == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = SteamGuardAccount.DeactivateAuthenticator();
|
||||
SteamGuardAccount = null;
|
||||
|
||||
try {
|
||||
File.Delete(MobileAuthenticatorFile);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void OnConnected(SteamClient.ConnectedCallback callback) {
|
||||
if (callback == null) {
|
||||
return;
|
||||
@@ -1252,7 +1149,7 @@ namespace ArchiSteamFarm {
|
||||
SteamParentalPIN = Program.GetUserInput(BotName, Program.EUserInputType.SteamParentalPIN);
|
||||
}
|
||||
|
||||
if (!await ArchiWebHandler.Init(SteamClient, callback.WebAPIUserNonce, callback.VanityURL, SteamParentalPIN).ConfigureAwait(false)) {
|
||||
if (!await ArchiWebHandler.Init(SteamClient, callback.WebAPIUserNonce, SteamParentalPIN).ConfigureAwait(false)) {
|
||||
await Restart().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
@@ -1376,5 +1273,109 @@ namespace ArchiSteamFarm {
|
||||
await CardsFarmer.RestartFarming().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ReadConfig() {
|
||||
if (!File.Exists(ConfigFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
using (XmlReader reader = XmlReader.Create(ConfigFile)) {
|
||||
while (reader.Read()) {
|
||||
if (reader.NodeType != XmlNodeType.Element) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string key = reader.Name;
|
||||
if (string.IsNullOrEmpty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string value = reader.GetAttribute("value");
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case "Enabled":
|
||||
Enabled = bool.Parse(value);
|
||||
break;
|
||||
case "SteamLogin":
|
||||
SteamLogin = value;
|
||||
break;
|
||||
case "SteamPassword":
|
||||
SteamPassword = value;
|
||||
break;
|
||||
case "SteamNickname":
|
||||
SteamNickname = value;
|
||||
break;
|
||||
case "SteamApiKey":
|
||||
SteamApiKey = value;
|
||||
break;
|
||||
case "SteamTradeToken":
|
||||
SteamTradeToken = value;
|
||||
break;
|
||||
case "SteamParentalPIN":
|
||||
SteamParentalPIN = value;
|
||||
break;
|
||||
case "SteamMasterID":
|
||||
SteamMasterID = ulong.Parse(value);
|
||||
break;
|
||||
case "SteamMasterClanID":
|
||||
SteamMasterClanID = ulong.Parse(value);
|
||||
break;
|
||||
case "StartOnLaunch":
|
||||
StartOnLaunch = bool.Parse(value);
|
||||
break;
|
||||
case "UseAsfAsMobileAuthenticator":
|
||||
UseAsfAsMobileAuthenticator = bool.Parse(value);
|
||||
break;
|
||||
case "CardDropsRestricted":
|
||||
CardDropsRestricted = bool.Parse(value);
|
||||
break;
|
||||
case "FarmOffline":
|
||||
FarmOffline = bool.Parse(value);
|
||||
break;
|
||||
case "HandleOfflineMessages":
|
||||
HandleOfflineMessages = bool.Parse(value);
|
||||
break;
|
||||
case "ForwardKeysToOtherBots":
|
||||
ForwardKeysToOtherBots = bool.Parse(value);
|
||||
break;
|
||||
case "DistributeKeys":
|
||||
DistributeKeys = bool.Parse(value);
|
||||
break;
|
||||
case "ShutdownOnFarmingFinished":
|
||||
ShutdownOnFarmingFinished = bool.Parse(value);
|
||||
break;
|
||||
case "SendOnFarmingFinished":
|
||||
SendOnFarmingFinished = bool.Parse(value);
|
||||
break;
|
||||
case "SendTradePeriod":
|
||||
SendTradePeriod = byte.Parse(value);
|
||||
break;
|
||||
case "Blacklist":
|
||||
Blacklist.Clear();
|
||||
foreach (string appID in value.Split(',')) {
|
||||
Blacklist.Add(uint.Parse(appID));
|
||||
}
|
||||
break;
|
||||
case "Statistics":
|
||||
Statistics = bool.Parse(value);
|
||||
break;
|
||||
default:
|
||||
Logging.LogGenericWarning("Unrecognized config value: " + key + "=" + value, BotName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
Logging.LogGenericError("Your config for this bot instance is invalid, it won't run!", BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,13 @@
|
||||
|
||||
using SteamKit2;
|
||||
using SteamKit2.Internal;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class CMsgClientClanInviteAction : ISteamSerializableMessage, ISteamSerializable {
|
||||
internal ulong GroupID = 0;
|
||||
internal bool AcceptInvite = true;
|
||||
internal ulong GroupID { get; set; } = 0;
|
||||
internal bool AcceptInvite { get; set; } = true;
|
||||
|
||||
EMsg ISteamSerializableMessage.GetEMsg() {
|
||||
return EMsg.ClientAcknowledgeClanInvite;
|
||||
@@ -44,8 +45,8 @@ namespace ArchiSteamFarm {
|
||||
BinaryWriter binaryWriter = new BinaryWriter(stream);
|
||||
binaryWriter.Write(GroupID);
|
||||
binaryWriter.Write(AcceptInvite);
|
||||
} catch {
|
||||
throw new IOException();
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +59,8 @@ namespace ArchiSteamFarm {
|
||||
BinaryReader binaryReader = new BinaryReader(stream);
|
||||
GroupID = binaryReader.ReadUInt64();
|
||||
AcceptInvite = binaryReader.ReadBoolean();
|
||||
} catch {
|
||||
throw new IOException();
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,15 +36,15 @@ namespace ArchiSteamFarm {
|
||||
private const byte StatusCheckSleep = 5; // In minutes, how long to wait before checking the appID again
|
||||
private const ushort MaxFarmingTime = 600; // In minutes, how long ASF is allowed to farm one game in solo mode
|
||||
|
||||
internal readonly ConcurrentDictionary<uint, float> GamesToFarm = new ConcurrentDictionary<uint, float>();
|
||||
internal readonly List<uint> CurrentGamesFarming = new List<uint>();
|
||||
|
||||
private readonly ManualResetEvent FarmResetEvent = new ManualResetEvent(false);
|
||||
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly Timer Timer;
|
||||
|
||||
internal readonly ConcurrentDictionary<uint, float> GamesToFarm = new ConcurrentDictionary<uint, float>();
|
||||
internal readonly List<uint> CurrentGamesFarming = new List<uint>();
|
||||
|
||||
private bool ManualMode = false;
|
||||
private bool NowFarming = false;
|
||||
|
||||
@@ -118,6 +118,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
CurrentGamesFarming.TrimExcess();
|
||||
foreach (uint appID in appIDs.Keys) {
|
||||
CurrentGamesFarming.Add(appID);
|
||||
}
|
||||
@@ -138,6 +139,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
CurrentGamesFarming.TrimExcess();
|
||||
CurrentGamesFarming.Add(appID);
|
||||
|
||||
Logging.LogGenericInfo("Now farming: " + appID, Bot.BotName);
|
||||
@@ -184,6 +186,7 @@ namespace ArchiSteamFarm {
|
||||
if (await FarmSolo(appID).ConfigureAwait(false)) {
|
||||
Logging.LogGenericInfo("Done farming: " + appID, Bot.BotName);
|
||||
gamesToFarmSolo.Remove(appID);
|
||||
gamesToFarmSolo.TrimExcess();
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
@@ -212,6 +215,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
CurrentGamesFarming.TrimExcess();
|
||||
NowFarming = false;
|
||||
Logging.LogGenericInfo("Farming finished!", Bot.BotName);
|
||||
await Bot.OnFarmingFinished().ConfigureAwait(false);
|
||||
@@ -269,16 +273,16 @@ namespace ArchiSteamFarm {
|
||||
// Find APPIDs we need to farm
|
||||
Logging.LogGenericInfo("Checking other pages...", Bot.BotName);
|
||||
|
||||
List<Task> checkPagesTasks = new List<Task>();
|
||||
List<Task> tasks = new List<Task>(maxPages - 1);
|
||||
for (byte page = 1; page <= maxPages; page++) {
|
||||
if (page == 1) {
|
||||
CheckPage(htmlDocument); // Because we fetched page number 1 already
|
||||
} else {
|
||||
byte currentPage = page; // We need a copy of variable being passed when in for loops
|
||||
checkPagesTasks.Add(Task.Run(async () => await CheckPage(currentPage).ConfigureAwait(false)));
|
||||
tasks.Add(Task.Run(async () => await CheckPage(currentPage).ConfigureAwait(false)));
|
||||
}
|
||||
}
|
||||
await Task.WhenAll(checkPagesTasks).ConfigureAwait(false);
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
if (GamesToFarm.Count == 0) {
|
||||
return true;
|
||||
@@ -286,12 +290,12 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// If we have restricted card drops, actually do check hours of all games that are left to farm
|
||||
if (Bot.CardDropsRestricted) {
|
||||
List<Task> checkHoursTasks = new List<Task>();
|
||||
tasks = new List<Task>(GamesToFarm.Keys.Count);
|
||||
Logging.LogGenericInfo("Checking hours...", Bot.BotName);
|
||||
foreach (uint appID in GamesToFarm.Keys) {
|
||||
checkHoursTasks.Add(Task.Run(async () => await CheckHours(appID).ConfigureAwait(false)));
|
||||
tasks.Add(Task.Run(async () => await CheckHours(appID).ConfigureAwait(false)));
|
||||
}
|
||||
await Task.WhenAll(checkHoursTasks).ConfigureAwait(false);
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -34,7 +34,79 @@ namespace ArchiSteamFarm {
|
||||
internal static bool LogToFile { get; set; } = false;
|
||||
|
||||
internal static void Init() {
|
||||
File.Delete(Program.LogFile);
|
||||
lock (FileLock) {
|
||||
try {
|
||||
File.Delete(Program.LogFile);
|
||||
} catch (Exception e) {
|
||||
bool logToFile = LogToFile;
|
||||
LogToFile = false;
|
||||
LogGenericException(e);
|
||||
LogToFile = logToFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LogGenericWTF(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[!!] WTF: " + previousMethodName + "() <" + botName + "> " + message + ", WTF?");
|
||||
}
|
||||
|
||||
internal static void LogGenericError(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[!!] ERROR: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogGenericException(Exception exception, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (exception == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message);
|
||||
Log("[!] StackTrace: " + exception.StackTrace);
|
||||
|
||||
Exception innerException = exception.InnerException;
|
||||
if (innerException != null) {
|
||||
LogGenericException(innerException, botName, previousMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LogGenericWarning(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[!] WARNING: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogGenericInfo(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[*] INFO: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogNullError(string nullObjectName, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(nullObjectName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LogGenericError(nullObjectName + " is null!", botName, previousMethodName);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void LogGenericDebug(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log("[#] DEBUG: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
private static void Log(string message) {
|
||||
@@ -51,44 +123,16 @@ namespace ArchiSteamFarm {
|
||||
|
||||
if (LogToFile) {
|
||||
lock (FileLock) {
|
||||
File.AppendAllText(Program.LogFile, loggedMessage);
|
||||
try {
|
||||
File.AppendAllText(Program.LogFile, loggedMessage);
|
||||
} catch (Exception e) {
|
||||
bool logToFile = LogToFile;
|
||||
LogToFile = false;
|
||||
LogGenericException(e);
|
||||
LogToFile = logToFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LogGenericWTF(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[!!] WTF: " + previousMethodName + "() <" + botName + "> " + message + ", WTF?");
|
||||
}
|
||||
|
||||
internal static void LogGenericError(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[!!] ERROR: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogGenericException(Exception exception, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message);
|
||||
Log("[!] StackTrace: " + exception.StackTrace);
|
||||
|
||||
Exception innerException = exception.InnerException;
|
||||
if (innerException != null) {
|
||||
LogGenericException(innerException, botName, previousMethodName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LogGenericWarning(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[!] WARNING: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogGenericInfo(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[*] INFO: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
|
||||
internal static void LogNullError(string nullObjectName, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
LogGenericError(nullObjectName + " is null!", botName, previousMethodName);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void LogGenericDebug(string message, string botName = "Main", [CallerMemberName] string previousMethodName = "") {
|
||||
Log("[#] DEBUG: " + previousMethodName + "() <" + botName + "> " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ namespace ArchiSteamFarm {
|
||||
internal sealed class SteamItem {
|
||||
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string appid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string contextid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string assetid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
@@ -43,22 +43,13 @@ namespace ArchiSteamFarm {
|
||||
set { assetid = value; }
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
internal string currencyid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string classid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string instanceid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string amount { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal bool missing { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal int pos { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,8 @@ using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal class SteamItemList {
|
||||
[JsonProperty]
|
||||
internal List<SteamItem> assets { get; set; } = new List<SteamItem>();
|
||||
|
||||
[JsonProperty]
|
||||
internal List<string> currency { get; set; } = new List<string>();
|
||||
|
||||
[JsonProperty]
|
||||
internal bool ready { get; set; } = false;
|
||||
internal sealed class SteamItemList {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal List<SteamItem> assets { get; } = new List<SteamItem>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ using System.Collections.Generic;
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class SteamTradeOffer {
|
||||
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer
|
||||
internal enum ETradeOfferState {
|
||||
internal enum ETradeOfferState : byte {
|
||||
Unknown,
|
||||
Invalid,
|
||||
Active,
|
||||
@@ -44,50 +44,20 @@ namespace ArchiSteamFarm {
|
||||
OnHold
|
||||
}
|
||||
|
||||
internal enum ETradeOfferConfirmationMethod {
|
||||
Invalid,
|
||||
Email,
|
||||
MobileApp
|
||||
}
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal string tradeofferid { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal int accountid_other { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal string message { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal int expiration_time { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal ETradeOfferState trade_offer_state { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal List<SteamItem> items_to_give { get; set; } = new List<SteamItem>();
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal List<SteamItem> items_to_give { get; } = new List<SteamItem>();
|
||||
|
||||
[JsonProperty]
|
||||
internal List<SteamItem> items_to_receive { get; set; } = new List<SteamItem>();
|
||||
|
||||
[JsonProperty]
|
||||
internal bool is_our_offer { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal int time_created { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal int time_updated { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal bool from_real_time_trade { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal int escrow_end_date { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal ETradeOfferConfirmationMethod confirmation_method { get; set; }
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal List<SteamItem> items_to_receive { get; } = new List<SteamItem>();
|
||||
|
||||
// Extra
|
||||
private ulong _OtherSteamID64 = 0;
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal class SteamTradeOfferRequest {
|
||||
[JsonProperty]
|
||||
internal bool newversion { get; set; } = true;
|
||||
internal sealed class SteamTradeOfferRequest {
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal bool newversion { get; } = true;
|
||||
|
||||
[JsonProperty]
|
||||
internal int version { get; set; } = 2;
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal int version { get; } = 2;
|
||||
|
||||
[JsonProperty]
|
||||
internal SteamItemList me { get; set; } = new SteamItemList();
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal SteamItemList me { get; } = new SteamItemList();
|
||||
|
||||
[JsonProperty]
|
||||
internal SteamItemList them { get; set; } = new SteamItemList();
|
||||
[JsonProperty(Required = Required.Always)]
|
||||
internal SteamItemList them { get; } = new SteamItemList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,13 +72,5 @@ namespace ArchiSteamFarm {
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
internal static string UrlDecode(string message) {
|
||||
if (string.IsNullOrEmpty(message)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return WebUtility.UrlDecode(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,27 +30,20 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class WebBrowser {
|
||||
[Flags]
|
||||
internal enum RequestOptions : byte {
|
||||
None = 0,
|
||||
FakeUserAgent = 1 << 0,
|
||||
XMLHttpRequest = 1 << 1
|
||||
}
|
||||
|
||||
private const string FakeUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36";
|
||||
|
||||
internal const byte HttpTimeout = 180; // In seconds, how long we can wait for server's response
|
||||
internal const byte MaxConnections = 20; // Defines maximum number of connections. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
|
||||
internal const byte MaxConnections = 10; // Defines maximum number of connections per ServicePoint. Be careful, as it also defines maximum number of sockets in CLOSE_WAIT state
|
||||
internal const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
|
||||
internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility)
|
||||
|
||||
private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version;
|
||||
private static readonly HttpClientHandler HttpClientHandler = new HttpClientHandler { UseCookies = false };
|
||||
private static readonly HttpClient HttpClient = new HttpClient(HttpClientHandler) { Timeout = TimeSpan.FromSeconds(HttpTimeout) };
|
||||
private static readonly HttpClient HttpClient = new HttpClient(new HttpClientHandler {
|
||||
UseCookies = false
|
||||
}) {
|
||||
Timeout = TimeSpan.FromSeconds(HttpTimeout)
|
||||
};
|
||||
|
||||
internal static void Init() {
|
||||
// Most web services expect that UserAgent is set, so we declare it globally
|
||||
@@ -65,9 +58,86 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// Don't use Expect100Continue, we're sure about our POSTs, save some TCP packets
|
||||
ServicePointManager.Expect100Continue = false;
|
||||
|
||||
// Reuse ports if possible
|
||||
// TODO: Mono doesn't support that feature yet
|
||||
//ServicePointManager.ReusePort = true;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
internal static async Task<HttpResponseMessage> UrlGet(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Get, null, cookies, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlPost(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Post, data, cookies, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToContent(string request, Dictionary<string, string> cookies, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpContent httpContent = httpResponse.Content;
|
||||
if (httpContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await httpContent.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlGetToHtmlDocument(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
content = WebUtility.HtmlDecode(content);
|
||||
HtmlDocument htmlDocument = new HtmlDocument();
|
||||
htmlDocument.LoadHtml(content);
|
||||
|
||||
return htmlDocument;
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlGetToJObject(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject jObject;
|
||||
|
||||
try {
|
||||
jObject = JObject.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jObject;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request) || httpMethod == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -95,14 +165,6 @@ namespace ArchiSteamFarm {
|
||||
requestMessage.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
|
||||
if (requestOptions.HasFlag(RequestOptions.FakeUserAgent)) {
|
||||
requestMessage.Headers.UserAgent.ParseAdd(FakeUserAgent);
|
||||
}
|
||||
|
||||
if (requestOptions.HasFlag(RequestOptions.XMLHttpRequest)) {
|
||||
requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
|
||||
}
|
||||
|
||||
try {
|
||||
responseMessage = await HttpClient.SendAsync(requestMessage).ConfigureAwait(false);
|
||||
} catch { // Request failed, we don't need to know the exact reason, swallow exception
|
||||
@@ -116,211 +178,5 @@ namespace ArchiSteamFarm {
|
||||
|
||||
return responseMessage;
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlGet(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Get, null, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlPost(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Post, data, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> HttpResponseToHtmlDocument(HttpResponseMessage httpResponse) {
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpContent httpContent = httpResponse.Content;
|
||||
if (httpContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await httpContent.ReadAsStringAsync().ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
content = WebUtility.HtmlDecode(content);
|
||||
HtmlDocument htmlDocument = new HtmlDocument();
|
||||
htmlDocument.LoadHtml(content);
|
||||
|
||||
return htmlDocument;
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToContent(string request, Dictionary<string, string> cookies, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpContent httpContent = httpResponse.Content;
|
||||
if (httpContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await httpContent.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlPostToContent(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlPost(request, data, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpContent httpContent = httpResponse.Content;
|
||||
if (httpContent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await httpContent.ReadAsStringAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlPostToJObject(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlPostToContent(request, data, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject jObject;
|
||||
|
||||
try {
|
||||
jObject = JObject.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jObject;
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlGetToHtmlDocument(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await HttpResponseToHtmlDocument(httpResponse).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlPostToHtmlDocument(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlPost(request, data, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await HttpResponseToHtmlDocument(httpResponse).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToTitle(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlDocument htmlDocument = await UrlGetToHtmlDocument(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (htmlDocument == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//head/title");
|
||||
if (htmlNode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return htmlNode.InnerText;
|
||||
}
|
||||
|
||||
internal static async Task<JArray> UrlGetToJArray(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JArray jArray;
|
||||
|
||||
try {
|
||||
jArray = JArray.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jArray;
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlGetToJObject(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JObject jObject;
|
||||
|
||||
try {
|
||||
jObject = JObject.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jObject;
|
||||
}
|
||||
|
||||
internal static async Task<XmlDocument> UrlGetToXML(string request, Dictionary<string, string> cookies = null, string referer = null, RequestOptions requestOptions = RequestOptions.None) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer, requestOptions).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
|
||||
try {
|
||||
xmlDocument.LoadXml(content);
|
||||
} catch (XmlException e) {
|
||||
Logging.LogGenericException(e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user