Compare commits

...

5 Commits

Author SHA1 Message Date
JustArchi
e5ee909b96 Remove debug leftovers 2017-08-01 13:23:19 +02:00
JustArchi
f3f444d0bd Test fix #605 2017-08-01 13:00:54 +02:00
JustArchi
43d18b6d49 Move debug to appropriate place 2017-08-01 12:44:22 +02:00
JustArchi
f24be67c8c Bunch of stuff for #605 2017-08-01 12:41:57 +02:00
JustArchi
6ce4f2941b Bump 2017-07-31 17:51:04 +02:00
11 changed files with 85 additions and 91 deletions

View File

@@ -3,8 +3,8 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<AssemblyVersion>3.0.0.7</AssemblyVersion> <AssemblyVersion>3.0.0.8</AssemblyVersion>
<FileVersion>3.0.0.7</FileVersion> <FileVersion>3.0.0.8</FileVersion>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<ErrorReport>none</ErrorReport> <ErrorReport>none</ErrorReport>
<ApplicationIcon>ASF.ico</ApplicationIcon> <ApplicationIcon>ASF.ico</ApplicationIcon>

View File

@@ -58,15 +58,15 @@ namespace ArchiSteamFarm {
private const string SteamStoreURL = "http://" + SteamStoreHost; private const string SteamStoreURL = "http://" + SteamStoreHost;
private static readonly SemaphoreSlim InventorySemaphore = new SemaphoreSlim(1); private static readonly SemaphoreSlim InventorySemaphore = new SemaphoreSlim(1, 1);
private static int Timeout = GlobalConfig.DefaultConnectionTimeout * 1000; // This must be int type private static int Timeout = GlobalConfig.DefaultConnectionTimeout * 1000; // This must be int type
private readonly SemaphoreSlim ApiKeySemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim ApiKeySemaphore = new SemaphoreSlim(1, 1);
private readonly Bot Bot; private readonly Bot Bot;
private readonly SemaphoreSlim PublicInventorySemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim PublicInventorySemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim TradeTokenSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim TradeTokenSemaphore = new SemaphoreSlim(1, 1);
private readonly WebBrowser WebBrowser; private readonly WebBrowser WebBrowser;
private string CachedApiKey; private string CachedApiKey;

View File

@@ -50,12 +50,11 @@ namespace ArchiSteamFarm {
private const ushort MaxSteamMessageLength = 2048; private const ushort MaxSteamMessageLength = 2048;
private const byte MaxTwoFactorCodeFailures = 3; private const byte MaxTwoFactorCodeFailures = 3;
private const byte MinHeartBeatTTL = GlobalConfig.DefaultConnectionTimeout; // Assume client is responsive for at least that amount of seconds private const byte MinHeartBeatTTL = GlobalConfig.DefaultConnectionTimeout; // Assume client is responsive for at least that amount of seconds
private const byte PICSCooldownInMiliseconds = 200; // We might need to tune this further
internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>(); internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>();
private static readonly SemaphoreSlim GiftsSemaphore = new SemaphoreSlim(1); private static readonly SemaphoreSlim GiftsSemaphore = new SemaphoreSlim(1, 1);
private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1); private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1, 1);
private static readonly SteamConfiguration SteamConfiguration = new SteamConfiguration(); private static readonly SteamConfiguration SteamConfiguration = new SteamConfiguration();
internal readonly ArchiLogger ArchiLogger; internal readonly ArchiLogger ArchiLogger;
@@ -74,16 +73,16 @@ namespace ArchiSteamFarm {
private readonly BotDatabase BotDatabase; private readonly BotDatabase BotDatabase;
private readonly string BotName; private readonly string BotName;
private readonly CallbackManager CallbackManager; private readonly CallbackManager CallbackManager;
private readonly SemaphoreSlim CallbackSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim CallbackSemaphore = new SemaphoreSlim(1, 1);
[JsonProperty] [JsonProperty]
private readonly CardsFarmer CardsFarmer; private readonly CardsFarmer CardsFarmer;
private readonly ConcurrentHashSet<ulong> HandledGifts = new ConcurrentHashSet<ulong>(); private readonly ConcurrentHashSet<ulong> HandledGifts = new ConcurrentHashSet<ulong>();
private readonly Timer HeartBeatTimer; private readonly Timer HeartBeatTimer;
private readonly SemaphoreSlim InitializationSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim InitializationSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim LootingSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim LootingSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim PICSSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim PICSSemaphore = new SemaphoreSlim(1, 1);
private readonly Statistics Statistics; private readonly Statistics Statistics;
private readonly SteamApps SteamApps; private readonly SteamApps SteamApps;
private readonly SteamClient SteamClient; private readonly SteamClient SteamClient;
@@ -361,10 +360,7 @@ namespace ArchiSteamFarm {
ArchiLogger.LogGenericException(e); ArchiLogger.LogGenericException(e);
return (0, DateTime.MinValue); return (0, DateTime.MinValue);
} finally { } finally {
Task.Run(async () => { PICSSemaphore.Release();
await Task.Delay(PICSCooldownInMiliseconds).ConfigureAwait(false);
PICSSemaphore.Release();
}).Forget();
} }
// ReSharper disable once LoopCanBePartlyConvertedToQuery - C# 7.0 out can't be used within LINQ query yet | https://github.com/dotnet/roslyn/issues/15619 // ReSharper disable once LoopCanBePartlyConvertedToQuery - C# 7.0 out can't be used within LINQ query yet | https://github.com/dotnet/roslyn/issues/15619
@@ -471,10 +467,7 @@ namespace ArchiSteamFarm {
ArchiLogger.LogGenericException(e); ArchiLogger.LogGenericException(e);
return null; return null;
} finally { } finally {
Task.Run(async () => { PICSSemaphore.Release();
await Task.Delay(PICSCooldownInMiliseconds).ConfigureAwait(false);
PICSSemaphore.Release();
}).Forget();
} }
Dictionary<uint, HashSet<uint>> result = new Dictionary<uint, HashSet<uint>>(); Dictionary<uint, HashSet<uint>> result = new Dictionary<uint, HashSet<uint>>();
@@ -1141,7 +1134,7 @@ namespace ArchiSteamFarm {
try { try {
if (DateTime.UtcNow.Subtract(ArchiHandler.LastPacketReceived).TotalSeconds > MinHeartBeatTTL) { if (DateTime.UtcNow.Subtract(ArchiHandler.LastPacketReceived).TotalSeconds > MinHeartBeatTTL) {
await SteamApps.PICSGetProductInfo(0, null); await SteamFriends.RequestProfileInfo(SteamClient.SteamID);
} }
HeartBeatFailures = 0; HeartBeatFailures = 0;

View File

@@ -58,9 +58,9 @@ namespace ArchiSteamFarm {
); );
private readonly Bot Bot; private readonly Bot Bot;
private readonly SemaphoreSlim EventSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim EventSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim FarmingSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim FarmingInitializationSemaphore = new SemaphoreSlim(1, 1);
private readonly ManualResetEventSlim FarmResetEvent = new ManualResetEventSlim(false); private readonly SemaphoreSlim FarmingResetSemaphore = new SemaphoreSlim(0, 1);
private readonly Timer IdleFarmingTimer; private readonly Timer IdleFarmingTimer;
[JsonProperty] [JsonProperty]
@@ -87,8 +87,8 @@ namespace ArchiSteamFarm {
public void Dispose() { public void Dispose() {
// Those are objects that are always being created if constructor doesn't throw exception // Those are objects that are always being created if constructor doesn't throw exception
EventSemaphore.Dispose(); EventSemaphore.Dispose();
FarmingSemaphore.Dispose(); FarmingInitializationSemaphore.Dispose();
FarmResetEvent.Dispose(); FarmingResetSemaphore.Dispose();
// Those are objects that might be null and the check should be in-place // Those are objects that might be null and the check should be in-place
IdleFarmingTimer?.Dispose(); IdleFarmingTimer?.Dispose();
@@ -140,7 +140,7 @@ namespace ArchiSteamFarm {
internal async Task OnNewItemsNotification() { internal async Task OnNewItemsNotification() {
if (NowFarming) { if (NowFarming) {
FarmResetEvent.Set(); FarmingResetSemaphore.Release();
return; return;
} }
@@ -188,7 +188,7 @@ namespace ArchiSteamFarm {
return; return;
} }
await FarmingSemaphore.WaitAsync().ConfigureAwait(false); await FarmingInitializationSemaphore.WaitAsync().ConfigureAwait(false);
try { try {
if (NowFarming || Paused || !Bot.IsPlayingPossible) { if (NowFarming || Paused || !Bot.IsPlayingPossible) {
@@ -231,7 +231,7 @@ namespace ArchiSteamFarm {
KeepFarming = NowFarming = true; KeepFarming = NowFarming = true;
Utilities.StartBackgroundFunction(Farm); Utilities.StartBackgroundFunction(Farm);
} finally { } finally {
FarmingSemaphore.Release(); FarmingInitializationSemaphore.Release();
} }
} }
@@ -240,7 +240,7 @@ namespace ArchiSteamFarm {
return; return;
} }
await FarmingSemaphore.WaitAsync().ConfigureAwait(false); await FarmingInitializationSemaphore.WaitAsync().ConfigureAwait(false);
try { try {
if (!NowFarming) { if (!NowFarming) {
@@ -248,7 +248,7 @@ namespace ArchiSteamFarm {
} }
KeepFarming = false; KeepFarming = false;
FarmResetEvent.Set(); FarmingResetSemaphore.Release();
for (byte i = 0; (i < 5) && NowFarming; i++) { for (byte i = 0; (i < 5) && NowFarming; i++) {
await Task.Delay(1000).ConfigureAwait(false); await Task.Delay(1000).ConfigureAwait(false);
@@ -261,7 +261,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(Strings.IdlingStopped); Bot.ArchiLogger.LogGenericInfo(Strings.IdlingStopped);
Bot.OnFarmingStopped(); Bot.OnFarmingStopped();
} finally { } finally {
FarmingSemaphore.Release(); FarmingInitializationSemaphore.Release();
} }
} }
@@ -556,65 +556,68 @@ namespace ArchiSteamFarm {
// If we have restricted card drops, we use complex algorithm // If we have restricted card drops, we use complex algorithm
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Complex")); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Complex"));
while (GamesToFarm.Count > 0) { while (GamesToFarm.Count > 0) {
HashSet<Game> playableGamesToFarmSolo = new HashSet<Game>(); HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm.Where(game => game.HoursPlayed >= HoursToBump));
foreach (Game game in GamesToFarm.Where(game => game.HoursPlayed >= HoursToBump)) {
if (await IsPlayableGame(game).ConfigureAwait(false)) { foreach (Game game in gamesToCheck) {
playableGamesToFarmSolo.Add(game); if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue;
}
if (await FarmSolo(game).ConfigureAwait(false)) {
continue;
}
NowFarming = false;
return;
}
gamesToCheck = new HashSet<Game>(GamesToFarm.OrderByDescending(game => game.HoursPlayed));
HashSet<Game> playableGamesToFarmMultiple = new HashSet<Game>();
foreach (Game game in gamesToCheck) {
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue;
}
playableGamesToFarmMultiple.Add(game);
if (playableGamesToFarmMultiple.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
break;
} }
} }
if (playableGamesToFarmSolo.Count > 0) { if (playableGamesToFarmMultiple.Count == 0) {
while (playableGamesToFarmSolo.Count > 0) { break;
Game playableGame = playableGamesToFarmSolo.First(); }
if (await FarmSolo(playableGame).ConfigureAwait(false)) {
playableGamesToFarmSolo.Remove(playableGame); if (await FarmMultiple(playableGamesToFarmMultiple).ConfigureAwait(false)) {
} else { Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", playableGamesToFarmMultiple.Select(game => game.AppID))));
NowFarming = false;
return;
}
}
} else { } else {
HashSet<Game> playableGamesToFarmMultiple = new HashSet<Game>(); NowFarming = false;
foreach (Game game in GamesToFarm.Where(game => game.HoursPlayed < HoursToBump).OrderByDescending(game => game.HoursPlayed)) { return;
if (await IsPlayableGame(game).ConfigureAwait(false)) {
playableGamesToFarmMultiple.Add(game);
}
if (playableGamesToFarmMultiple.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
break;
}
}
if (FarmMultiple(playableGamesToFarmMultiple)) {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", playableGamesToFarmMultiple.Select(game => game.AppID))));
} else {
NowFarming = false;
return;
}
} }
} }
} else { } else {
// If we have unrestricted card drops, we use simple algorithm // If we have unrestricted card drops, we use simple algorithm
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Simple")); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Simple"));
while (GamesToFarm.Count > 0) { while (GamesToFarm.Count > 0) {
Game playableGame = null; HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm);
foreach (Game game in GamesToFarm) {
foreach (Game game in gamesToCheck) {
if (!await IsPlayableGame(game).ConfigureAwait(false)) { if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue; continue;
} }
playableGame = game; if (await FarmSolo(game).ConfigureAwait(false)) {
break;
}
if (playableGame != null) {
if (await FarmSolo(playableGame).ConfigureAwait(false)) {
continue; continue;
} }
}
NowFarming = false; NowFarming = false;
return; return;
}
} }
} }
} while ((await IsAnythingToFarm().ConfigureAwait(false)).GetValueOrDefault()); } while ((await IsAnythingToFarm().ConfigureAwait(false)).GetValueOrDefault());
@@ -646,8 +649,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName)); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName));
DateTime startFarmingPeriod = DateTime.UtcNow; DateTime startFarmingPeriod = DateTime.UtcNow;
if (FarmResetEvent.Wait(60 * 1000 * Program.GlobalConfig.FarmingDelay)) { if (await FarmingResetSemaphore.WaitAsync(60 * 1000 * Program.GlobalConfig.FarmingDelay).ConfigureAwait(false)) {
FarmResetEvent.Reset();
success = KeepFarming; success = KeepFarming;
} }
@@ -665,7 +667,7 @@ namespace ArchiSteamFarm {
return success; return success;
} }
private bool FarmHours(ConcurrentHashSet<Game> games) { private async Task<bool> FarmHours(ConcurrentHashSet<Game> games) {
if ((games == null) || (games.Count == 0)) { if ((games == null) || (games.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(games)); Bot.ArchiLogger.LogNullError(nameof(games));
return false; return false;
@@ -689,8 +691,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdlingList, string.Join(", ", games.Select(game => game.AppID)))); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdlingList, string.Join(", ", games.Select(game => game.AppID))));
DateTime startFarmingPeriod = DateTime.UtcNow; DateTime startFarmingPeriod = DateTime.UtcNow;
if (FarmResetEvent.Wait(60 * 1000 * Program.GlobalConfig.FarmingDelay)) { if (await FarmingResetSemaphore.WaitAsync(60 * 1000 * Program.GlobalConfig.FarmingDelay).ConfigureAwait(false)) {
FarmResetEvent.Reset();
success = KeepFarming; success = KeepFarming;
} }
@@ -711,7 +712,7 @@ namespace ArchiSteamFarm {
return success; return success;
} }
private bool FarmMultiple(IEnumerable<Game> games) { private async Task<bool> FarmMultiple(IEnumerable<Game> games) {
if (games == null) { if (games == null) {
Bot.ArchiLogger.LogNullError(nameof(games)); Bot.ArchiLogger.LogNullError(nameof(games));
return false; return false;
@@ -721,7 +722,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdlingList, string.Join(", ", CurrentGamesFarming.Select(game => game.AppID)))); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdlingList, string.Join(", ", CurrentGamesFarming.Select(game => game.AppID))));
bool result = FarmHours(CurrentGamesFarming); bool result = await FarmHours(CurrentGamesFarming).ConfigureAwait(false);
CurrentGamesFarming.Clear(); CurrentGamesFarming.Clear();
return result; return result;
} }

View File

@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
public bool IsReadOnly => false; public bool IsReadOnly => false;
private readonly HashSet<T> BackingCollection = new HashSet<T>(); private readonly HashSet<T> BackingCollection = new HashSet<T>();
private readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1); private readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
public bool Add(T item) { public bool Add(T item) {
SemaphoreSlim.Wait(); SemaphoreSlim.Wait();

View File

@@ -102,7 +102,7 @@ namespace ArchiSteamFarm {
internal readonly bool Statistics = true; internal readonly bool Statistics = true;
[JsonProperty(Required = Required.DisallowNull)] [JsonProperty(Required = Required.DisallowNull)]
internal readonly ProtocolTypes SteamProtocols = ProtocolTypes.All; internal readonly ProtocolTypes SteamProtocols = ProtocolTypes.Tcp;
[JsonProperty(Required = Required.DisallowNull)] [JsonProperty(Required = Required.DisallowNull)]
internal readonly EUpdateChannel UpdateChannel = EUpdateChannel.Stable; internal readonly EUpdateChannel UpdateChannel = EUpdateChannel.Stable;

View File

@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
private readonly object FileLock = new object(); private readonly object FileLock = new object();
private readonly SemaphoreSlim PackagesRefreshSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim PackagesRefreshSemaphore = new SemaphoreSlim(1, 1);
internal uint CellID { internal uint CellID {
get => _CellID; get => _CellID;

View File

@@ -42,14 +42,14 @@ namespace ArchiSteamFarm {
private const byte CodeInterval = 30; private const byte CodeInterval = 30;
private static readonly char[] CodeCharacters = { '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y' }; private static readonly char[] CodeCharacters = { '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y' };
private static readonly SemaphoreSlim TimeSemaphore = new SemaphoreSlim(1); private static readonly SemaphoreSlim TimeSemaphore = new SemaphoreSlim(1, 1);
private static int? SteamTimeDifference; private static int? SteamTimeDifference;
// "ERROR" is being used by SteamDesktopAuthenticator // "ERROR" is being used by SteamDesktopAuthenticator
internal bool HasCorrectDeviceID => !string.IsNullOrEmpty(DeviceID) && !DeviceID.Equals("ERROR"); internal bool HasCorrectDeviceID => !string.IsNullOrEmpty(DeviceID) && !DeviceID.Equals("ERROR");
private readonly SemaphoreSlim ConfirmationsSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim ConfirmationsSemaphore = new SemaphoreSlim(1, 1);
#pragma warning disable 649 #pragma warning disable 649
[JsonProperty(PropertyName = "identity_secret", Required = Required.Always)] [JsonProperty(PropertyName = "identity_secret", Required = Required.Always)]

View File

@@ -40,7 +40,7 @@ namespace ArchiSteamFarm {
private const string URL = "https://" + SharedInfo.StatisticsServer; private const string URL = "https://" + SharedInfo.StatisticsServer;
private readonly Bot Bot; private readonly Bot Bot;
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1);
private DateTime LastAnnouncementCheck = DateTime.MinValue; private DateTime LastAnnouncementCheck = DateTime.MinValue;
private DateTime LastHeartBeat = DateTime.MinValue; private DateTime LastHeartBeat = DateTime.MinValue;

View File

@@ -37,7 +37,7 @@ namespace ArchiSteamFarm {
private readonly Bot Bot; private readonly Bot Bot;
private readonly ConcurrentHashSet<ulong> IgnoredTrades = new ConcurrentHashSet<ulong>(); private readonly ConcurrentHashSet<ulong> IgnoredTrades = new ConcurrentHashSet<ulong>();
private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1); private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1, 1);
private bool ParsingScheduled; private bool ParsingScheduled;

View File

@@ -18,6 +18,6 @@
"OptimizationMode": 0, "OptimizationMode": 0,
"Statistics": true, "Statistics": true,
"SteamOwnerID": 0, "SteamOwnerID": 0,
"SteamProtocols": 7, "SteamProtocols": 1,
"UpdateChannel": 1 "UpdateChannel": 1
} }