This commit is contained in:
Łukasz Domeradzki
2024-10-06 15:14:48 +02:00
parent 9b40ab3b52
commit 78cf64e808
4 changed files with 79 additions and 23 deletions

View File

@@ -183,6 +183,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
private readonly ConcurrentHashSet<ulong> SteamFamilySharingIDs = [];
private readonly SteamUser SteamUser;
private readonly Trading Trading;
private readonly SemaphoreSlim UnpackBoosterPacksSemaphore = new(1, 1);
private IEnumerable<(string FilePath, EFileType FileType)> RelatedFiles {
get {
@@ -315,6 +316,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
private SteamSaleEvent? SteamSaleEvent;
private Timer? TradeCheckTimer;
private string? TwoFactorCode;
private bool UnpackBoosterPacksScheduled;
private Bot(string botName, BotConfig botConfig, BotDatabase botDatabase) {
ArgumentException.ThrowIfNullOrEmpty(botName);
@@ -415,6 +417,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
RefreshWebSessionSemaphore.Dispose();
SendCompleteTypesSemaphore.Dispose();
Trading.Dispose();
UnpackBoosterPacksSemaphore.Dispose();
Actions.Dispose();
CardsFarmer.Dispose();
@@ -442,6 +445,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
RefreshWebSessionSemaphore.Dispose();
SendCompleteTypesSemaphore.Dispose();
Trading.Dispose();
UnpackBoosterPacksSemaphore.Dispose();
await Actions.DisposeAsync().ConfigureAwait(false);
await CardsFarmer.DisposeAsync().ConfigureAwait(false);
@@ -3121,7 +3125,21 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
Utilities.InBackground(ArchiWebHandler.MarkInventory);
}
if (BotConfig.CompleteTypesToSend.Count > 0) {
// The following actions should be synchronized, as they modify the state of the inventory
if (BotConfig.FarmingPreferences.HasFlag(BotConfig.EFarmingPreferences.AutoUnpackBoosterPacks)) {
Utilities.InBackground(
async () => {
if (!await UnpackBoosterPacks().ConfigureAwait(false)) {
// Another task is already in progress, so it'll handle the actions below as well
return;
}
if (BotConfig.CompleteTypesToSend.Count > 0) {
await SendCompletedSets().ConfigureAwait(false);
}
}
);
} else if (BotConfig.CompleteTypesToSend.Count > 0) {
Utilities.InBackground(SendCompletedSets);
}
}
@@ -3923,6 +3941,32 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
RefreshTokensTimer = null;
}
private async Task<bool> UnpackBoosterPacks() {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (UnpackBoosterPacksSemaphore) {
if (UnpackBoosterPacksScheduled) {
return false;
}
UnpackBoosterPacksScheduled = true;
}
await UnpackBoosterPacksSemaphore.WaitAsync().ConfigureAwait(false);
try {
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (UnpackBoosterPacksSemaphore) {
UnpackBoosterPacksScheduled = false;
}
await Actions.UnpackBoosterPacks().ConfigureAwait(false);
} finally {
UnpackBoosterPacksSemaphore.Release();
}
return true;
}
private void UpdateTokens(string accessToken, string? refreshToken = null) {
ArgumentException.ThrowIfNullOrEmpty(accessToken);

View File

@@ -476,6 +476,35 @@ public sealed class Actions : IAsyncDisposable, IDisposable {
return (true, Strings.Done);
}
[PublicAPI]
public async Task<bool> UnpackBoosterPacks() {
if (!Bot.IsConnectedAndLoggedOn) {
return false;
}
// It'd make sense here to actually check return code of ArchiWebHandler.UnpackBooster(), but it lies most of the time | https://github.com/JustArchi/ArchiSteamFarm/issues/704
bool result = true;
// It'd also make sense to run all of this in parallel, but it seems that Steam has a lot of problems with inventory-related parallel requests | https://steamcommunity.com/groups/archiasf/discussions/1/3559414588264550284/
try {
await foreach (Asset item in Bot.ArchiHandler.GetMyInventoryAsync().Where(static item => item.Type == EAssetType.BoosterPack).ConfigureAwait(false)) {
if (!await Bot.ArchiWebHandler.UnpackBooster(item.RealAppID, item.AssetID).ConfigureAwait(false)) {
result = false;
}
}
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);
return false;
} catch (Exception e) {
Bot.ArchiLogger.LogGenericException(e);
return false;
}
return result;
}
[PublicAPI]
public static async Task<(bool Success, string? Message, Version? Version)> Update(GlobalConfig.EUpdateChannel? channel = null, bool forced = false) {
if (channel.HasValue && !Enum.IsDefined(channel.Value)) {

View File

@@ -3418,27 +3418,9 @@ public sealed class Commands {
return FormatBotResponse(Strings.BotNotConnected);
}
// It'd make sense here to actually check return code of ArchiWebHandler.UnpackBooster(), but it lies most of the time | https://github.com/JustArchi/ArchiSteamFarm/issues/704
bool completeSuccess = true;
bool result = await Bot.Actions.UnpackBoosterPacks().ConfigureAwait(false);
// It'd also make sense to run all of this in parallel, but it seems that Steam has a lot of problems with inventory-related parallel requests | https://steamcommunity.com/groups/archiasf/discussions/1/3559414588264550284/
try {
await foreach (Asset item in Bot.ArchiHandler.GetMyInventoryAsync().Where(static item => item.Type == EAssetType.BoosterPack).ConfigureAwait(false)) {
if (!await Bot.ArchiWebHandler.UnpackBooster(item.RealAppID, item.AssetID).ConfigureAwait(false)) {
completeSuccess = false;
}
}
} catch (TimeoutException e) {
Bot.ArchiLogger.LogGenericWarningException(e);
completeSuccess = false;
} catch (Exception e) {
Bot.ArchiLogger.LogGenericException(e);
completeSuccess = false;
}
return FormatBotResponse(completeSuccess ? Strings.Success : Strings.Done);
return FormatBotResponse(result ? Strings.Success : Strings.Done);
}
private static async Task<string?> ResponseUnpackBoosters(EAccess access, string botNames, ulong steamID = 0) {

View File

@@ -641,7 +641,7 @@ public sealed class BotConfig {
[Flags]
[PublicAPI]
public enum EFarmingPreferences : byte {
public enum EFarmingPreferences : ushort {
None = 0,
FarmingPausedByDefault = 1,
ShutdownOnFarmingFinished = 2,
@@ -651,7 +651,8 @@ public sealed class BotConfig {
SkipUnplayedGames = 32,
EnableRiskyCardsDiscovery = 64,
AutoSteamSaleEvent = 128,
All = FarmingPausedByDefault | ShutdownOnFarmingFinished | SendOnFarmingFinished | FarmPriorityQueueOnly | SkipRefundableGames | SkipUnplayedGames | EnableRiskyCardsDiscovery | AutoSteamSaleEvent
AutoUnpackBoosterPacks = 256,
All = FarmingPausedByDefault | ShutdownOnFarmingFinished | SendOnFarmingFinished | FarmPriorityQueueOnly | SkipRefundableGames | SkipUnplayedGames | EnableRiskyCardsDiscovery | AutoSteamSaleEvent | AutoUnpackBoosterPacks
}
[Flags]