Code review

This commit is contained in:
JustArchi
2016-04-24 23:32:23 +02:00
parent e17c3ecf2a
commit eb6e93a172
2 changed files with 132 additions and 139 deletions

View File

@@ -35,11 +35,10 @@ using System.Threading;
namespace ArchiSteamFarm {
internal sealed class ArchiWebHandler {
private const string SteamCommunity = "steamcommunity.com";
private const string SteamCommunityHost = "steamcommunity.com";
private const byte MinSessionTTL = 15; // Assume session is valid for at least that amount of seconds
private static string SteamCommunityURL = "https://" + SteamCommunity;
private static string SteamCommunityURL = "https://" + SteamCommunityHost;
private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000;
private readonly Bot Bot;
@@ -50,7 +49,7 @@ namespace ArchiSteamFarm {
internal static void Init() {
Timeout = Program.GlobalConfig.HttpTimeout * 1000;
SteamCommunityURL = (Program.GlobalConfig.ForceHttp ? "http://" : "https://") + SteamCommunity;
SteamCommunityURL = (Program.GlobalConfig.ForceHttp ? "http://" : "https://") + SteamCommunityHost;
}
private static uint GetAppIDFromMarketHashName(string hashName) {
@@ -110,6 +109,39 @@ namespace ArchiSteamFarm {
WebBrowser = new WebBrowser(bot.BotName);
}
internal async Task<bool> AcceptGift(ulong gid) {
if (gid == 0) {
return false;
}
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
return false;
}
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
if (string.IsNullOrEmpty(sessionID)) {
Logging.LogNullError("sessionID");
return false;
}
string request = SteamCommunityURL + "/gifts/" + gid + "/acceptunpack";
Dictionary<string, string> data = new Dictionary<string, string>(1) {
{ "sessionid", sessionID }
};
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
}
if (!result) {
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
return false;
}
return true;
}
internal bool Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) {
if (steamClient == null || steamClient.SteamID == null || string.IsNullOrEmpty(webAPIUserNonce)) {
return false;
@@ -162,13 +194,13 @@ namespace ArchiSteamFarm {
Logging.LogGenericInfo("Success!", Bot.BotName);
WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunity));
WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunityHost));
string steamLogin = authResult["token"].Value;
WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunity));
WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunityHost));
string steamLoginSecure = authResult["tokensecure"].Value;
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunity));
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunityHost));
if (!UnlockParentalAccount(parentalPin).Result) {
return false;
@@ -178,48 +210,38 @@ namespace ArchiSteamFarm {
return true;
}
internal async Task<bool?> IsLoggedIn() {
string request = SteamCommunityURL + "/my/profile";
HtmlDocument htmlDocument = null;
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(request).ConfigureAwait(false);
internal async Task<bool> JoinGroup(ulong groupID) {
if (groupID == 0) {
return false;
}
if (htmlDocument == null) {
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
return false;
}
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
if (string.IsNullOrEmpty(sessionID)) {
Logging.LogNullError("sessionID");
return false;
}
string request = SteamCommunityURL + "/gid/" + groupID;
Dictionary<string, string> data = new Dictionary<string, string>(2) {
{ "sessionID", sessionID },
{ "action", "join" }
};
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
}
if (!result) {
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
return null;
return false;
}
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='account_pulldown']");
return htmlNode != null;
}
internal async Task<bool> RefreshSessionIfNeeded() {
if (DateTime.Now.Subtract(LastSessionRefreshCheck).TotalSeconds < MinSessionTTL) {
return true;
}
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
if (DateTime.Now.Subtract(LastSessionRefreshCheck).TotalSeconds < MinSessionTTL) {
SessionSemaphore.Release();
return true;
}
bool result;
bool? isLoggedIn = await IsLoggedIn().ConfigureAwait(false);
if (isLoggedIn.GetValueOrDefault(true)) {
result = true;
LastSessionRefreshCheck = DateTime.Now;
} else {
Logging.LogGenericInfo("Refreshing our session!", Bot.BotName);
result = await Bot.RefreshSession().ConfigureAwait(false);
}
SessionSemaphore.Release();
return result;
return true;
}
internal async Task<Dictionary<uint, string>> GetOwnedGames() {
@@ -295,7 +317,7 @@ namespace ArchiSteamFarm {
return null;
}
Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>> descriptionMap = new Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>>();
Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>> descriptions = new Dictionary<Tuple<ulong, ulong>, Tuple<uint, Steam.Item.EType>>();
foreach (KeyValue description in response["descriptions"].Children) {
ulong classID = description["classid"].AsUnsignedLong();
if (classID == 0) {
@@ -305,7 +327,7 @@ namespace ArchiSteamFarm {
ulong instanceID = description["instanceid"].AsUnsignedLong();
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(classID, instanceID);
if (descriptionMap.ContainsKey(key)) {
if (descriptions.ContainsKey(key)) {
continue;
}
@@ -322,7 +344,7 @@ namespace ArchiSteamFarm {
type = GetItemType(descriptionType);
}
descriptionMap[key] = new Tuple<uint, Steam.Item.EType>(appID, type);
descriptions[key] = new Tuple<uint, Steam.Item.EType>(appID, type);
}
HashSet<Steam.TradeOffer> result = new HashSet<Steam.TradeOffer>();
@@ -347,7 +369,7 @@ namespace ArchiSteamFarm {
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(steamItem.ClassID, steamItem.InstanceID);
Tuple<uint, Steam.Item.EType> description;
if (descriptionMap.TryGetValue(key, out description)) {
if (descriptions.TryGetValue(key, out description)) {
steamItem.RealAppID = description.Item1;
steamItem.Type = description.Item2;
}
@@ -368,7 +390,7 @@ namespace ArchiSteamFarm {
Tuple<ulong, ulong> key = new Tuple<ulong, ulong>(steamItem.ClassID, steamItem.InstanceID);
Tuple<uint, Steam.Item.EType> description;
if (descriptionMap.TryGetValue(key, out description)) {
if (descriptions.TryGetValue(key, out description)) {
steamItem.RealAppID = description.Item1;
steamItem.Type = description.Item2;
}
@@ -382,41 +404,6 @@ namespace ArchiSteamFarm {
return result;
}
internal async Task<bool> JoinClan(ulong clanID) {
if (clanID == 0) {
return false;
}
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
return false;
}
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
if (string.IsNullOrEmpty(sessionID)) {
Logging.LogNullError("sessionID");
return false;
}
string request = SteamCommunityURL + "/gid/" + clanID;
Dictionary<string, string> data = new Dictionary<string, string>(2) {
{ "sessionID", sessionID },
{ "action", "join" }
};
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
}
if (!result) {
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;
@@ -432,9 +419,7 @@ namespace ArchiSteamFarm {
return false;
}
string referer = SteamCommunityURL + "/tradeoffer/" + tradeID;
string request = referer + "/accept";
string request = SteamCommunityURL + "/tradeoffer/" + tradeID + "/accept";
Dictionary<string, string> data = new Dictionary<string, string>(3) {
{ "sessionid", sessionID },
{ "serverid", "1" },
@@ -443,7 +428,7 @@ namespace ArchiSteamFarm {
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false);
result = await WebBrowser.UrlPost(request, data, SteamCommunityURL).ConfigureAwait(false);
}
if (!result) {
@@ -608,9 +593,7 @@ namespace ArchiSteamFarm {
itemID++;
}
string referer = SteamCommunityURL + "/tradeoffer/new";
string request = referer + "/send";
string request = SteamCommunityURL + "/tradeoffer/new/send";
foreach (Steam.TradeOfferRequest trade in trades) {
Dictionary<string, string> data = new Dictionary<string, string>(6) {
{ "sessionid", sessionID },
@@ -623,7 +606,7 @@ namespace ArchiSteamFarm {
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false);
result = await WebBrowser.UrlPost(request, data, SteamCommunityURL).ConfigureAwait(false);
}
if (!result) {
@@ -703,37 +686,48 @@ namespace ArchiSteamFarm {
return true;
}
internal async Task<bool> AcceptGift(ulong gid) {
if (gid == 0) {
return false;
private async Task<bool?> IsLoggedIn() {
string request = SteamCommunityURL + "/my/profile";
HtmlDocument htmlDocument = null;
for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) {
htmlDocument = await WebBrowser.UrlGetToHtmlDocument(request).ConfigureAwait(false);
}
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
return false;
}
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
if (string.IsNullOrEmpty(sessionID)) {
Logging.LogNullError("sessionID");
return false;
}
string request = SteamCommunityURL + "/gifts/" + gid + "/acceptunpack";
Dictionary<string, string> data = new Dictionary<string, string>(1) {
{ "sessionid", sessionID }
};
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false);
}
if (!result) {
if (htmlDocument == null) {
Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
return false;
return null;
}
return true;
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//span[@id='account_pulldown']");
return htmlNode != null;
}
private async Task<bool> RefreshSessionIfNeeded() {
if (DateTime.Now.Subtract(LastSessionRefreshCheck).TotalSeconds < MinSessionTTL) {
return true;
}
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
if (DateTime.Now.Subtract(LastSessionRefreshCheck).TotalSeconds < MinSessionTTL) {
SessionSemaphore.Release();
return true;
}
bool result;
bool? isLoggedIn = await IsLoggedIn().ConfigureAwait(false);
if (isLoggedIn.GetValueOrDefault(true)) {
result = true;
LastSessionRefreshCheck = DateTime.Now;
} else {
Logging.LogGenericInfo("Refreshing our session!", Bot.BotName);
result = await Bot.RefreshSession().ConfigureAwait(false);
}
SessionSemaphore.Release();
return result;
}
private async Task<bool> UnlockParentalAccount(string parentalPin) {
@@ -742,16 +736,15 @@ namespace ArchiSteamFarm {
}
Logging.LogGenericInfo("Unlocking parental account...", Bot.BotName);
string request = SteamCommunityURL + "/parental/ajaxunlock";
Dictionary<string, string> data = new Dictionary<string, string>(1) {
{ "pin", parentalPin }
};
string referer = SteamCommunityURL;
string request = referer + "/parental/ajaxunlock";
bool result = false;
for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) {
result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false);
result = await WebBrowser.UrlPost(request, data, SteamCommunityURL).ConfigureAwait(false);
}
if (!result) {

View File

@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
internal static readonly Dictionary<string, Bot> Bots = new Dictionary<string, Bot>();
private static readonly uint LoginID = MsgClientLogon.ObfuscationMask; // This must be the same for all ASF bots and all ASF processes
private static readonly SemaphoreSlim SteamSemaphore = new SemaphoreSlim(1);
private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1);
internal readonly string BotName;
internal readonly ArchiHandler ArchiHandler;
@@ -70,7 +70,7 @@ namespace ArchiSteamFarm {
internal static async Task RefreshCMs(uint cellID) {
bool initialized = false;
for (byte i = 0; i < 3 && !initialized; i++) {
for (byte i = 0; i < WebBrowser.MaxRetries && !initialized; i++) {
try {
Logging.LogGenericInfo("Refreshing list of CMs...");
await SteamDirectory.Initialize(cellID).ConfigureAwait(false);
@@ -84,7 +84,7 @@ namespace ArchiSteamFarm {
if (initialized) {
Logging.LogGenericInfo("Success!");
} else {
Logging.LogGenericWarning("Failed to initialize list of CMs after 3 tries, ASF will use built-in SK2 list, it may take a while to connect");
Logging.LogGenericWarning("Failed to initialize list of CMs after " + WebBrowser.MaxRetries + " tries, ASF will use built-in SK2 list, it may take a while to connect");
}
}
@@ -106,11 +106,11 @@ namespace ArchiSteamFarm {
return Regex.IsMatch(key, @"[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-?(?:(?:[0-9A-Z]{4,5}-?)?(?:[0-9A-Z]{4,5}))?");
}
private static async Task LimitSteamRequestsAsync() {
await SteamSemaphore.WaitAsync().ConfigureAwait(false);
private static async Task LimitLoginRequestsAsync() {
await LoginSemaphore.WaitAsync().ConfigureAwait(false);
Task.Run(async () => {
await Utilities.SleepAsync(Program.GlobalConfig.LoginLimiterDelay * 1000).ConfigureAwait(false);
SteamSemaphore.Release();
LoginSemaphore.Release();
}).Forget();
}
@@ -133,12 +133,6 @@ namespace ArchiSteamFarm {
return;
}
BotDatabase = BotDatabase.Load(botPath + ".db");
if (BotDatabase == null) {
Logging.LogGenericError("Bot database could not be loaded, refusing to start this bot instance!", botName);
return;
}
bool alreadyExists;
lock (Bots) {
alreadyExists = Bots.ContainsKey(botName);
@@ -153,6 +147,12 @@ namespace ArchiSteamFarm {
SentryFile = botPath + ".bin";
BotDatabase = BotDatabase.Load(botPath + ".db");
if (BotDatabase == null) {
Logging.LogGenericError("Bot database could not be loaded, refusing to start this bot instance!", botName);
return;
}
if (BotDatabase.SteamGuardAccount == null) {
// Support and convert SDA files
string maFilePath = botPath + ".maFile";
@@ -166,8 +166,8 @@ namespace ArchiSteamFarm {
if (Program.GlobalConfig.Debug && !Debugging.NetHookAlreadyInitialized && Directory.Exists(Program.DebugDirectory)) {
try {
SteamClient.DebugNetworkListener = new NetHookNetworkListener(Program.DebugDirectory);
Debugging.NetHookAlreadyInitialized = true;
SteamClient.DebugNetworkListener = new NetHookNetworkListener(Program.DebugDirectory);
} catch (Exception e) {
Logging.LogGenericException(e, botName);
}
@@ -421,7 +421,7 @@ namespace ArchiSteamFarm {
// 2FA tokens are expiring soon, don't use limiter when user is providing one
if (TwoFactorCode == null || BotDatabase.SteamGuardAccount != null) {
await LimitSteamRequestsAsync().ConfigureAwait(false);
await LimitLoginRequestsAsync().ConfigureAwait(false);
}
Logging.LogGenericInfo("Starting...", BotName);
@@ -1435,7 +1435,7 @@ namespace ArchiSteamFarm {
// 2FA tokens are expiring soon, don't use limiter when user is providing one
if (TwoFactorCode == null || BotDatabase.SteamGuardAccount != null) {
await LimitSteamRequestsAsync().ConfigureAwait(false);
await LimitLoginRequestsAsync().ConfigureAwait(false);
}
SteamClient.Connect();
@@ -1651,14 +1651,14 @@ namespace ArchiSteamFarm {
if (BotConfig.SteamMasterClanID != 0) {
Task.Run(async () => {
await ArchiWebHandler.JoinClan(BotConfig.SteamMasterClanID).ConfigureAwait(false);
await ArchiWebHandler.JoinGroup(BotConfig.SteamMasterClanID).ConfigureAwait(false);
JoinMasterChat();
}).Forget();
}
if (Program.GlobalConfig.Statistics) {
Task.Run(async () => {
await ArchiWebHandler.JoinClan(ArchiSCFarmGroup).ConfigureAwait(false);
await ArchiWebHandler.JoinGroup(ArchiSCFarmGroup).ConfigureAwait(false);
SteamFriends.JoinChat(ArchiSCFarmGroup);
}).Forget();
}