mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-29 12:40:46 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ad58a22d | ||
|
|
790e6baf46 | ||
|
|
c8fb715558 | ||
|
|
2ab5e6013d | ||
|
|
3e0c34e62c | ||
|
|
65b31e5537 | ||
|
|
62a6e38e47 | ||
|
|
0b50a45336 | ||
|
|
8d1d162b02 | ||
|
|
dbe13a1965 | ||
|
|
fc13633f5e | ||
|
|
d0cc10f3c6 | ||
|
|
567931a4cc | ||
|
|
396dc17ab2 |
@@ -32,6 +32,16 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class ArchiHandler : ClientMsgHandler {
|
||||
private readonly Bot Bot;
|
||||
|
||||
internal ArchiHandler(Bot bot) {
|
||||
if (bot == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bot = bot;
|
||||
}
|
||||
|
||||
/*
|
||||
____ _ _ _ _
|
||||
/ ___| __ _ | || || |__ __ _ ___ | | __ ___
|
||||
@@ -261,7 +271,7 @@ namespace ArchiSteamFarm {
|
||||
try {
|
||||
return await new AsyncJob<PurchaseResponseCallback>(Client, request.SourceJobID);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
Logging.LogGenericException(e, Bot.BotName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace ArchiSteamFarm {
|
||||
private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000;
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly Dictionary<string, string> Cookie = new Dictionary<string, string>(4);
|
||||
private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1);
|
||||
private readonly WebBrowser WebBrowser;
|
||||
|
||||
private DateTime LastSessionRefreshCheck = DateTime.MinValue;
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
Bot = bot;
|
||||
|
||||
WebBrowser = new WebBrowser(bot.BotName);
|
||||
}
|
||||
|
||||
internal bool Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) {
|
||||
@@ -114,15 +116,13 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
|
||||
string steamLogin = authResult["token"].AsString();
|
||||
string steamLoginSecure = authResult["tokensecure"].AsString();
|
||||
WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunity));
|
||||
|
||||
Cookie["sessionid"] = sessionID;
|
||||
Cookie["steamLogin"] = steamLogin;
|
||||
Cookie["steamLoginSecure"] = steamLoginSecure;
|
||||
string steamLogin = authResult["token"].Value;
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunity));
|
||||
|
||||
// The below is used for display purposes only
|
||||
Cookie["webTradeEligibility"] = "{\"allowed\":0,\"reason\":0,\"allowed_at_time\":0,\"steamguard_required_days\":0,\"sales_this_year\":0,\"max_sales_per_year\":0,\"forms_requested\":0}";
|
||||
string steamLoginSecure = authResult["tokensecure"].Value;
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunity));
|
||||
|
||||
if (!UnlockParentalAccount(parentalPin).Result) {
|
||||
return false;
|
||||
@@ -135,7 +135,7 @@ namespace ArchiSteamFarm {
|
||||
internal async Task<bool?> IsLoggedIn() {
|
||||
HtmlDocument htmlDocument = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/profile", Cookie).ConfigureAwait(false);
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/profile").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (htmlDocument == null) {
|
||||
@@ -186,7 +186,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
XmlDocument response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlGetToXML(request, Cookie).ConfigureAwait(false);
|
||||
response = await WebBrowser.UrlGetToXML(request).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
@@ -291,8 +291,9 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string sessionID;
|
||||
if (!Cookie.TryGetValue("sessionid", out sessionID)) {
|
||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||
if (string.IsNullOrEmpty(sessionID)) {
|
||||
Logging.LogNullError("sessionID");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -303,12 +304,12 @@ namespace ArchiSteamFarm {
|
||||
{"action", "join"}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie).ConfigureAwait(false);
|
||||
bool result = false;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
|
||||
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (!result) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
@@ -325,8 +326,9 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string sessionID;
|
||||
if (!Cookie.TryGetValue("sessionid", out sessionID)) {
|
||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||
if (string.IsNullOrEmpty(sessionID)) {
|
||||
Logging.LogNullError("sessionID");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -339,12 +341,12 @@ namespace ArchiSteamFarm {
|
||||
{"tradeofferid", tradeID.ToString()}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie, referer).ConfigureAwait(false);
|
||||
bool result = false;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
|
||||
result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (!result) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
@@ -359,7 +361,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
JObject jObject = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) {
|
||||
jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/753/6?trading=1", Cookie).ConfigureAwait(false);
|
||||
jObject = await WebBrowser.UrlGetToJObject(SteamCommunityURL + "/my/inventory/json/753/6?trading=1").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (jObject == null) {
|
||||
@@ -394,8 +396,9 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string sessionID;
|
||||
if (!Cookie.TryGetValue("sessionid", out sessionID)) {
|
||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||
if (string.IsNullOrEmpty(sessionID)) {
|
||||
Logging.LogNullError("sessionID");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -434,12 +437,12 @@ namespace ArchiSteamFarm {
|
||||
{"trade_offer_create_params", string.IsNullOrEmpty(token) ? "" : $"{{\"trade_offer_access_token\":\"{token}\"}}"}
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie, referer).ConfigureAwait(false);
|
||||
bool result = false;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
|
||||
result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (!result) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
@@ -459,7 +462,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
HtmlDocument htmlDocument = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/badges?l=english&p=" + page, Cookie).ConfigureAwait(false);
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/badges?p=" + page).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (htmlDocument == null) {
|
||||
@@ -481,7 +484,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
HtmlDocument htmlDocument = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/gamecards/" + appID + "?l=english", Cookie).ConfigureAwait(false);
|
||||
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(SteamCommunityURL + "/my/gamecards/" + appID).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (htmlDocument == null) {
|
||||
@@ -497,12 +500,12 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlGet(SteamCommunityURL + "/my/inventory", Cookie).ConfigureAwait(false);
|
||||
bool result = false;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
|
||||
result = await WebBrowser.UrlGet(SteamCommunityURL + "/my/inventory").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (!result) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
@@ -519,8 +522,9 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string sessionID;
|
||||
if (!Cookie.TryGetValue("sessionid", out sessionID)) {
|
||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||
if (string.IsNullOrEmpty(sessionID)) {
|
||||
Logging.LogNullError("sessionID");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -529,12 +533,12 @@ namespace ArchiSteamFarm {
|
||||
{ "sessionid", sessionID }
|
||||
};
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie).ConfigureAwait(false);
|
||||
bool result = false;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
|
||||
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
if (!result) {
|
||||
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
@@ -557,7 +561,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) {
|
||||
response = await WebBrowser.UrlPost(request, data, Cookie, referer).ConfigureAwait(false);
|
||||
response = await WebBrowser.UrlPostToResponse(request, data, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
@@ -567,10 +571,13 @@ namespace ArchiSteamFarm {
|
||||
|
||||
IEnumerable<string> setCookieValues;
|
||||
if (!response.Headers.TryGetValues("Set-Cookie", out setCookieValues)) {
|
||||
response.Dispose();
|
||||
Logging.LogNullError("setCookieValues", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
response.Dispose();
|
||||
|
||||
foreach (string setCookieValue in setCookieValues) {
|
||||
if (!setCookieValue.Contains("steamparental=")) {
|
||||
continue;
|
||||
@@ -583,8 +590,8 @@ namespace ArchiSteamFarm {
|
||||
setCookie = setCookie.Substring(0, index);
|
||||
}
|
||||
|
||||
Cookie["steamparental"] = setCookie;
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamparental", setCookie, "/", "." + SteamCommunity));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace ArchiSteamFarm {
|
||||
internal bool KeepRunning { get; private set; }
|
||||
|
||||
private bool InvalidPassword, LoggedInElsewhere;
|
||||
private string AuthCode, TwoFactorAuth;
|
||||
private string AuthCode, TwoFactorCode;
|
||||
|
||||
internal static async Task RefreshCMs(uint cellID) {
|
||||
bool initialized = false;
|
||||
@@ -164,7 +164,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
ArchiHandler = new ArchiHandler();
|
||||
ArchiHandler = new ArchiHandler(this);
|
||||
SteamClient.AddHandler(ArchiHandler);
|
||||
|
||||
CallbackManager = new CallbackManager(SteamClient);
|
||||
@@ -410,7 +410,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// 2FA tokens are expiring soon, use limiter only when we don't have any pending
|
||||
if (TwoFactorAuth == null) {
|
||||
if (TwoFactorCode == null) {
|
||||
await Program.LimitSteamRequestsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -1317,6 +1317,11 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Logging.LogGenericInfo("Logging in...", BotName);
|
||||
|
||||
// If we have ASF 2FA enabled, we can always provide TwoFactorCode, and save a request
|
||||
if (BotDatabase.SteamGuardAccount != null) {
|
||||
TwoFactorCode = BotDatabase.SteamGuardAccount.GenerateSteamGuardCode();
|
||||
}
|
||||
|
||||
// TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed
|
||||
if (Program.GlobalConfig.HackIgnoreMachineID) {
|
||||
Logging.LogGenericWarning("Using workaround for broken GenerateMachineID()!", BotName);
|
||||
@@ -1326,7 +1331,7 @@ namespace ArchiSteamFarm {
|
||||
AuthCode = AuthCode,
|
||||
LoginID = LoginID,
|
||||
LoginKey = BotDatabase.LoginKey,
|
||||
TwoFactorCode = TwoFactorAuth,
|
||||
TwoFactorCode = TwoFactorCode,
|
||||
SentryFileHash = sentryHash,
|
||||
ShouldRememberPassword = true
|
||||
});
|
||||
@@ -1339,7 +1344,7 @@ namespace ArchiSteamFarm {
|
||||
AuthCode = AuthCode,
|
||||
LoginID = LoginID,
|
||||
LoginKey = BotDatabase.LoginKey,
|
||||
TwoFactorCode = TwoFactorAuth,
|
||||
TwoFactorCode = TwoFactorCode,
|
||||
SentryFileHash = sentryHash,
|
||||
ShouldRememberPassword = true
|
||||
});
|
||||
@@ -1386,7 +1391,7 @@ namespace ArchiSteamFarm {
|
||||
Logging.LogGenericInfo("Reconnecting...", BotName);
|
||||
|
||||
// 2FA tokens are expiring soon, use limiter only when we don't have any pending
|
||||
if (TwoFactorAuth == null) {
|
||||
if (TwoFactorCode == null) {
|
||||
await Program.LimitSteamRequestsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -1548,13 +1553,13 @@ namespace ArchiSteamFarm {
|
||||
break;
|
||||
case EResult.AccountLoginDeniedNeedTwoFactor:
|
||||
if (BotDatabase.SteamGuardAccount == null) {
|
||||
TwoFactorAuth = Program.GetUserInput(Program.EUserInputType.TwoFactorAuthentication, BotName);
|
||||
if (string.IsNullOrEmpty(TwoFactorAuth)) {
|
||||
TwoFactorCode = Program.GetUserInput(Program.EUserInputType.TwoFactorAuthentication, BotName);
|
||||
if (string.IsNullOrEmpty(TwoFactorCode)) {
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
TwoFactorAuth = BotDatabase.SteamGuardAccount.GenerateSteamGuardCode();
|
||||
Logging.LogGenericWarning("2FA code was invalid despite of using ASF 2FA. Invalid authenticator or bad timing?", BotName);
|
||||
}
|
||||
break;
|
||||
case EResult.InvalidPassword:
|
||||
@@ -1573,13 +1578,13 @@ namespace ArchiSteamFarm {
|
||||
string maFilePath = Path.Combine(Program.ConfigDirectory, callback.ClientSteamID.ConvertToUInt64() + ".maFile");
|
||||
if (File.Exists(maFilePath)) {
|
||||
ImportAuthenticator(maFilePath);
|
||||
} else if (TwoFactorAuth == null && BotConfig.UseAsfAsMobileAuthenticator) {
|
||||
} else if (TwoFactorCode == null && BotConfig.UseAsfAsMobileAuthenticator) {
|
||||
LinkMobileAuthenticator();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset one-time-only access tokens
|
||||
AuthCode = TwoFactorAuth = null;
|
||||
AuthCode = TwoFactorCode = null;
|
||||
|
||||
ResetGamesPlayed();
|
||||
|
||||
|
||||
@@ -103,56 +103,51 @@ namespace ArchiSteamFarm {
|
||||
|
||||
bool farmedSomething = false;
|
||||
|
||||
// Now the algorithm used for farming depends on whether account is restricted or not
|
||||
if (Bot.BotConfig.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm
|
||||
Logging.LogGenericInfo("Chosen farming algorithm: Complex", Bot.BotName);
|
||||
while (GamesToFarm.Count > 0) {
|
||||
HashSet<uint> gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm);
|
||||
if (gamesToFarmSolo.Count > 0) {
|
||||
while (gamesToFarmSolo.Count > 0) {
|
||||
uint appID = gamesToFarmSolo.First();
|
||||
if (await FarmSolo(appID).ConfigureAwait(false)) {
|
||||
farmedSomething = true;
|
||||
gamesToFarmSolo.Remove(appID);
|
||||
gamesToFarmSolo.TrimExcess();
|
||||
do {
|
||||
// Now the algorithm used for farming depends on whether account is restricted or not
|
||||
if (Bot.BotConfig.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm
|
||||
Logging.LogGenericInfo("Chosen farming algorithm: Complex", Bot.BotName);
|
||||
while (GamesToFarm.Count > 0) {
|
||||
HashSet<uint> gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm);
|
||||
if (gamesToFarmSolo.Count > 0) {
|
||||
while (gamesToFarmSolo.Count > 0) {
|
||||
uint appID = gamesToFarmSolo.First();
|
||||
if (await FarmSolo(appID).ConfigureAwait(false)) {
|
||||
farmedSomething = true;
|
||||
gamesToFarmSolo.Remove(appID);
|
||||
gamesToFarmSolo.TrimExcess();
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (FarmMultiple()) {
|
||||
Logging.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Keys), Bot.BotName);
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (FarmMultiple()) {
|
||||
Logging.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Keys), Bot.BotName);
|
||||
}
|
||||
} else { // If we have unrestricted card drops, we use simple algorithm
|
||||
Logging.LogGenericInfo("Chosen farming algorithm: Simple", Bot.BotName);
|
||||
while (GamesToFarm.Count > 0) {
|
||||
uint appID = GamesToFarm.Keys.FirstOrDefault();
|
||||
if (await FarmSolo(appID).ConfigureAwait(false)) {
|
||||
farmedSomething = true;
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // If we have unrestricted card drops, we use simple algorithm
|
||||
Logging.LogGenericInfo("Chosen farming algorithm: Simple", Bot.BotName);
|
||||
while (GamesToFarm.Count > 0) {
|
||||
uint appID = GamesToFarm.Keys.FirstOrDefault();
|
||||
if (await FarmSolo(appID).ConfigureAwait(false)) {
|
||||
farmedSomething = true;
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (await IsAnythingToFarm().ConfigureAwait(false));
|
||||
|
||||
CurrentGamesFarming.Clear();
|
||||
CurrentGamesFarming.TrimExcess();
|
||||
NowFarming = false;
|
||||
|
||||
// We finished our queue for now, make sure that everything is indeed farmed before proceeding further
|
||||
// Some games could be added in the meantime
|
||||
if (await IsAnythingToFarm().ConfigureAwait(false)) {
|
||||
StartFarming().Forget();
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Farming finished!", Bot.BotName);
|
||||
await Bot.OnFarmingFinished(farmedSomething).ConfigureAwait(false);
|
||||
}
|
||||
@@ -207,10 +202,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
private async Task<bool> IsAnythingToFarm() {
|
||||
if (NowFarming) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Checking badges...", Bot.BotName);
|
||||
|
||||
// Find the number of badge pages
|
||||
|
||||
@@ -82,17 +82,21 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private static Timer AutoUpdatesTimer;
|
||||
private static EMode Mode = EMode.Normal;
|
||||
private static WebBrowser WebBrowser;
|
||||
|
||||
internal static async Task CheckForUpdate() {
|
||||
string oldExeFile = ExecutableFile + ".old";
|
||||
|
||||
// We booted successfully so we can now remove old exe file
|
||||
if (File.Exists(oldExeFile)) {
|
||||
// It's entirely possible that old process is still running, allow at least a second before trying to remove the file
|
||||
await Utilities.SleepAsync(1000).ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
File.Delete(oldExeFile);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
return;
|
||||
Logging.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +174,11 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.Exists(oldExeFile)) {
|
||||
Logging.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually");
|
||||
return;
|
||||
}
|
||||
|
||||
// Auto update logic starts here
|
||||
if (releaseResponse.Assets == null) {
|
||||
Logging.LogGenericWarning("Could not proceed with update because that version doesn't include assets!");
|
||||
@@ -306,7 +315,7 @@ namespace ArchiSteamFarm {
|
||||
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter steam parental PIN: ");
|
||||
break;
|
||||
case EUserInputType.RevocationCode:
|
||||
Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation);
|
||||
Console.WriteLine((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "PLEASE WRITE DOWN YOUR REVOCATION CODE: " + extraInformation);
|
||||
Console.Write("Hit enter once ready...");
|
||||
break;
|
||||
case EUserInputType.TwoFactorAuthentication:
|
||||
@@ -361,6 +370,8 @@ namespace ArchiSteamFarm {
|
||||
ArchiWebHandler.Init();
|
||||
WebBrowser.Init();
|
||||
WCF.Init();
|
||||
|
||||
WebBrowser = new WebBrowser("Main");
|
||||
}
|
||||
|
||||
private static void ParseArgs(string[] args) {
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.0.2.6")]
|
||||
[assembly: AssemblyFileVersion("2.0.2.6")]
|
||||
[assembly: AssemblyVersion("2.0.2.8")]
|
||||
[assembly: AssemblyFileVersion("2.0.2.8")]
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
@@ -35,6 +36,27 @@ namespace ArchiSteamFarm {
|
||||
return Task.WhenAll(sequence.Select(action));
|
||||
}
|
||||
|
||||
internal static string GetCookieValue(this CookieContainer cookieContainer, string URL, string name) {
|
||||
if (string.IsNullOrEmpty(URL) || string.IsNullOrEmpty(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CookieCollection cookies = cookieContainer.GetCookies(new Uri(URL));
|
||||
if (cookies == null || cookies.Count == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (Cookie cookie in cookies) {
|
||||
if (!cookie.Name.Equals(name, StringComparison.Ordinal)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return cookie.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static Task SleepAsync(int miliseconds) {
|
||||
if (miliseconds < 0) {
|
||||
return Task.FromResult(true);
|
||||
|
||||
@@ -23,37 +23,31 @@
|
||||
*/
|
||||
|
||||
using HtmlAgilityPack;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class WebBrowser {
|
||||
internal sealed class WebBrowser {
|
||||
internal const byte MaxRetries = 5; // Defines maximum number of retries, UrlRequest() does not handle retry by itself (it's app responsibility)
|
||||
|
||||
private 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
|
||||
private const byte MaxIdleTime = 15; // In seconds, how long socket is allowed to stay in CLOSE_WAIT state after there are no connections to it
|
||||
|
||||
private static readonly string DefaultUserAgent = "ArchiSteamFarm/" + Program.Version;
|
||||
private static readonly HttpClient HttpClient = new HttpClient(new HttpClientHandler {
|
||||
UseCookies = false
|
||||
}) {
|
||||
Timeout = TimeSpan.FromSeconds(60)
|
||||
};
|
||||
|
||||
internal readonly CookieContainer CookieContainer = new CookieContainer();
|
||||
|
||||
private readonly HttpClient HttpClient;
|
||||
private readonly string Identifier;
|
||||
|
||||
internal static void Init() {
|
||||
HttpClient.Timeout = TimeSpan.FromSeconds(Program.GlobalConfig.HttpTimeout);
|
||||
|
||||
// Most web services expect that UserAgent is set, so we declare it globally
|
||||
// Any request can override that on as-needed basis (see: RequestOptions.FakeUserAgent)
|
||||
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent);
|
||||
|
||||
// Set max connection limit from default of 2 to desired value
|
||||
ServicePointManager.DefaultConnectionLimit = MaxConnections;
|
||||
|
||||
@@ -63,67 +57,114 @@ 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
|
||||
#if !__MonoCS__
|
||||
// Reuse ports if possible (since .NET 4.6+)
|
||||
//ServicePointManager.ReusePort = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlGet(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal WebBrowser(string identifier) {
|
||||
if (string.IsNullOrEmpty(identifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Identifier = identifier;
|
||||
|
||||
HttpClientHandler httpClientHandler = new HttpClientHandler {
|
||||
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
|
||||
CookieContainer = CookieContainer
|
||||
};
|
||||
|
||||
HttpClient = new HttpClient(httpClientHandler) {
|
||||
Timeout = TimeSpan.FromSeconds(Program.GlobalConfig.HttpTimeout)
|
||||
};
|
||||
|
||||
// Most web services expect that UserAgent is set, so we declare it globally
|
||||
HttpClient.DefaultRequestHeaders.UserAgent.ParseAdd(DefaultUserAgent);
|
||||
}
|
||||
|
||||
internal async Task<bool> UrlGet(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpResponseMessage response = await UrlGetToResponse(request, referer).ConfigureAwait(false);
|
||||
if (response == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
response.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task<bool> UrlPost(string request, Dictionary<string, string> data = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpResponseMessage response = await UrlPostToResponse(request, data, referer).ConfigureAwait(false);
|
||||
if (response == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
response.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
internal async Task<HttpResponseMessage> UrlGetToResponse(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Get, null, cookies, referer).ConfigureAwait(false);
|
||||
return await UrlRequest(request, HttpMethod.Get, null, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<HttpResponseMessage> UrlPost(string request, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<HttpResponseMessage> UrlPostToResponse(string request, Dictionary<string, string> data = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await UrlRequest(request, HttpMethod.Post, data, cookies, referer).ConfigureAwait(false);
|
||||
return await UrlRequest(request, HttpMethod.Post, data, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task<string> UrlGetToContent(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<string> UrlGetToContent(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer).ConfigureAwait(false);
|
||||
HttpResponseMessage httpResponse = await UrlGetToResponse(request, referer).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (httpResponse.Content == null) {
|
||||
return null;
|
||||
}
|
||||
string result = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
httpResponse.Dispose();
|
||||
|
||||
return await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<Stream> UrlGetToStream(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<Stream> UrlGetToStream(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HttpResponseMessage httpResponse = await UrlGet(request, cookies, referer).ConfigureAwait(false);
|
||||
HttpResponseMessage httpResponse = await UrlGetToResponse(request, referer).ConfigureAwait(false);
|
||||
if (httpResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (httpResponse.Content == null) {
|
||||
return null;
|
||||
}
|
||||
Stream result = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
httpResponse.Dispose();
|
||||
|
||||
return await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static async Task<HtmlDocument> UrlGetToHtmlDocument(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<HtmlDocument> UrlGetToHtmlDocument(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
string content = await UrlGetToContent(request, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
@@ -135,12 +176,12 @@ namespace ArchiSteamFarm {
|
||||
return htmlDocument;
|
||||
}
|
||||
|
||||
internal static async Task<JObject> UrlGetToJObject(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<JObject> UrlGetToJObject(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
string content = await UrlGetToContent(request, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
@@ -149,20 +190,20 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
jObject = JObject.Parse(content);
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e);
|
||||
} catch (JsonException e) {
|
||||
Logging.LogGenericException(e, Identifier);
|
||||
return null;
|
||||
}
|
||||
|
||||
return jObject;
|
||||
}
|
||||
|
||||
internal static async Task<XmlDocument> UrlGetToXML(string request, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
internal async Task<XmlDocument> UrlGetToXML(string request, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string content = await UrlGetToContent(request, cookies, referer).ConfigureAwait(false);
|
||||
string content = await UrlGetToContent(request, referer).ConfigureAwait(false);
|
||||
if (string.IsNullOrEmpty(content)) {
|
||||
return null;
|
||||
}
|
||||
@@ -172,14 +213,14 @@ namespace ArchiSteamFarm {
|
||||
try {
|
||||
xmlDocument.LoadXml(content);
|
||||
} catch (XmlException e) {
|
||||
Logging.LogGenericException(e);
|
||||
Logging.LogGenericException(e, Identifier);
|
||||
return null;
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, Dictionary<string, string> cookies = null, string referer = null) {
|
||||
private async Task<HttpResponseMessage> UrlRequest(string request, HttpMethod httpMethod, Dictionary<string, string> data = null, string referer = null) {
|
||||
if (string.IsNullOrEmpty(request) || httpMethod == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -194,19 +235,11 @@ namespace ArchiSteamFarm {
|
||||
try {
|
||||
requestMessage.Content = new FormUrlEncodedContent(data);
|
||||
} catch (UriFormatException e) {
|
||||
Logging.LogGenericException(e);
|
||||
Logging.LogGenericException(e, Identifier);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (cookies != null && cookies.Count > 0) {
|
||||
StringBuilder cookieHeader = new StringBuilder();
|
||||
foreach (KeyValuePair<string, string> cookie in cookies) {
|
||||
cookieHeader.Append(cookie.Key + "=" + cookie.Value + ";");
|
||||
}
|
||||
requestMessage.Headers.Add("Cookie", cookieHeader.ToString());
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(referer)) {
|
||||
requestMessage.Headers.Referrer = new Uri(referer);
|
||||
}
|
||||
@@ -218,15 +251,14 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
if (responseMessage == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!responseMessage.IsSuccessStatusCode) {
|
||||
if (responseMessage == null || !responseMessage.IsSuccessStatusCode) {
|
||||
if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) {
|
||||
Logging.LogGenericError("Request: " + request + " failed!");
|
||||
Logging.LogGenericError("Status code: " + responseMessage.StatusCode);
|
||||
Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false));
|
||||
Logging.LogGenericError("Request: " + request + " failed!", Identifier);
|
||||
if (responseMessage != null) {
|
||||
Logging.LogGenericError("Status code: " + responseMessage.StatusCode, Identifier);
|
||||
Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false), Identifier);
|
||||
responseMessage.Dispose();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user