mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +00:00
Invalidate cache upon pics changes
PICS restart indicates that we don't know what changes exactly we've missed. If package doesn't emit any change number (and it doesn't have to), we might miss the update that happened in the meantime without being aware of that happening.
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Composition;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -258,7 +259,7 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
HashSet<uint> appIDsToRefresh = new();
|
||||
|
||||
foreach (uint packageID in packageIDs) {
|
||||
if (!ASF.GlobalDatabase.PackagesDataReadOnly.TryGetValue(packageID, out (uint ChangeNumber, HashSet<uint>? AppIDs) packageData) || (packageData.AppIDs == null)) {
|
||||
if (!ASF.GlobalDatabase.PackagesDataReadOnly.TryGetValue(packageID, out (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) packageData) || (packageData.AppIDs == null)) {
|
||||
// ASF might not have the package info for us at the moment, we'll retry later
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1219,7 +1219,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal async Task<HashSet<uint>?> GetMarketableAppIDs() => await ArchiWebHandler.GetAppList().ConfigureAwait(false);
|
||||
|
||||
internal async Task<Dictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)>?> GetPackagesData(IReadOnlyCollection<uint> packageIDs) {
|
||||
internal async Task<Dictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)>?> GetPackagesData(IReadOnlyCollection<uint> packageIDs) {
|
||||
if ((packageIDs == null) || (packageIDs.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(packageIDs));
|
||||
}
|
||||
@@ -1239,7 +1239,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
if (packageRequests.Count == 0) {
|
||||
return new Dictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)>(0);
|
||||
return new Dictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)>(0);
|
||||
}
|
||||
|
||||
AsyncJobMultiple<SteamApps.PICSProductInfoCallback>.ResultSet? productInfoResultSet = null;
|
||||
@@ -1256,7 +1256,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)> result = new();
|
||||
Dictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)> result = new();
|
||||
|
||||
foreach (SteamApps.PICSProductInfoCallback.PICSProductInfo productInfo in productInfoResultSet.Results.SelectMany(productInfoResult => productInfoResult.Packages).Where(productInfoPackages => productInfoPackages.Key != 0).Select(productInfoPackages => productInfoPackages.Value)) {
|
||||
if (productInfo.KeyValues == KeyValue.Invalid) {
|
||||
@@ -1265,28 +1265,29 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
(uint ChangeNumber, HashSet<uint>? AppIDs) value = (productInfo.ChangeNumber, null);
|
||||
uint changeNumber = productInfo.ChangeNumber;
|
||||
HashSet<uint>? appIDs = null;
|
||||
|
||||
try {
|
||||
KeyValue appIDs = productInfo.KeyValues["appids"];
|
||||
KeyValue appIDsKv = productInfo.KeyValues["appids"];
|
||||
|
||||
if (appIDs == KeyValue.Invalid) {
|
||||
if (appIDsKv == KeyValue.Invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
value.AppIDs = new HashSet<uint>(appIDs.Children.Count);
|
||||
appIDs = new HashSet<uint>(appIDsKv.Children.Count);
|
||||
|
||||
foreach (string? appIDText in appIDs.Children.Select(app => app.Value)) {
|
||||
foreach (string? appIDText in appIDsKv.Children.Select(app => app.Value)) {
|
||||
if (!uint.TryParse(appIDText, out uint appID) || (appID == 0)) {
|
||||
ArchiLogger.LogNullError(nameof(appID));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
value.AppIDs.Add(appID);
|
||||
appIDs.Add(appID);
|
||||
}
|
||||
} finally {
|
||||
result[productInfo.ID] = value;
|
||||
result[productInfo.ID] = (changeNumber, appIDs?.ToImmutableHashSet());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2620,7 +2621,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// Package is always due to refresh with access token change
|
||||
packagesToRefresh[license.PackageID] = (uint) license.LastChangeNumber;
|
||||
} else if (!ASF.GlobalDatabase.PackagesDataReadOnly.TryGetValue(license.PackageID, out (uint ChangeNumber, HashSet<uint>? AppIDs) packageData) || (packageData.ChangeNumber < license.LastChangeNumber)) {
|
||||
} else if (!ASF.GlobalDatabase.PackagesDataReadOnly.TryGetValue(license.PackageID, out (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) packageData) || (packageData.ChangeNumber < license.LastChangeNumber)) {
|
||||
packagesToRefresh[license.PackageID] = (uint) license.LastChangeNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -41,7 +42,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public IReadOnlyDictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)> PackagesDataReadOnly => PackagesData;
|
||||
public IReadOnlyDictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)> PackagesDataReadOnly => PackagesData;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly InMemoryServerListProvider ServerListProvider = new();
|
||||
@@ -50,7 +51,7 @@ namespace ArchiSteamFarm {
|
||||
private readonly ConcurrentDictionary<uint, ulong> PackagesAccessTokens = new();
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
private readonly ConcurrentDictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)> PackagesData = new();
|
||||
private readonly ConcurrentDictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)> PackagesData = new();
|
||||
|
||||
private readonly SemaphoreSlim PackagesRefreshSemaphore = new(1, 1);
|
||||
|
||||
@@ -151,7 +152,7 @@ namespace ArchiSteamFarm {
|
||||
HashSet<uint> result = new();
|
||||
|
||||
foreach (uint packageID in packageIDs.Where(packageID => packageID != 0)) {
|
||||
if (!PackagesData.TryGetValue(packageID, out (uint ChangeNumber, HashSet<uint>? AppIDs) packagesData) || (packagesData.AppIDs?.Contains(appID) != true)) {
|
||||
if (!PackagesData.TryGetValue(packageID, out (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) packagesData) || (packagesData.AppIDs?.Contains(appID) != true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -161,6 +162,24 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void OnPICSChangesRestart() {
|
||||
bool save = false;
|
||||
|
||||
if (!PackagesData.IsEmpty) {
|
||||
PackagesData.Clear();
|
||||
save = true;
|
||||
}
|
||||
|
||||
if (!PackagesAccessTokens.IsEmpty) {
|
||||
PackagesAccessTokens.Clear();
|
||||
save = true;
|
||||
}
|
||||
|
||||
if (save) {
|
||||
Utilities.InBackground(Save);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RefreshPackageAccessTokens(IReadOnlyDictionary<uint, ulong> packageAccessTokens) {
|
||||
if ((packageAccessTokens == null) || (packageAccessTokens.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(packageAccessTokens));
|
||||
@@ -192,13 +211,13 @@ namespace ArchiSteamFarm {
|
||||
await PackagesRefreshSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
HashSet<uint> packageIDs = packages.Where(package => (package.Key != 0) && (!PackagesData.TryGetValue(package.Key, out (uint ChangeNumber, HashSet<uint>? AppIDs) packageData) || (packageData.ChangeNumber < package.Value))).Select(package => package.Key).ToHashSet();
|
||||
HashSet<uint> packageIDs = packages.Where(package => (package.Key != 0) && (!PackagesData.TryGetValue(package.Key, out (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) packageData) || (packageData.ChangeNumber < package.Value))).Select(package => package.Key).ToHashSet();
|
||||
|
||||
if (packageIDs.Count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<uint, (uint ChangeNumber, HashSet<uint>? AppIDs)>? packagesData = await bot.GetPackagesData(packageIDs).ConfigureAwait(false);
|
||||
Dictionary<uint, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs)>? packagesData = await bot.GetPackagesData(packageIDs).ConfigureAwait(false);
|
||||
|
||||
if (packagesData == null) {
|
||||
bot.ArchiLogger.LogGenericWarning(Strings.WarningFailed);
|
||||
@@ -208,8 +227,8 @@ namespace ArchiSteamFarm {
|
||||
|
||||
bool save = false;
|
||||
|
||||
foreach ((uint packageID, (uint ChangeNumber, HashSet<uint>? AppIDs) packageData) in packagesData) {
|
||||
if (PackagesData.TryGetValue(packageID, out (uint ChangeNumber, HashSet<uint>? AppIDs) previousData) && (packageData.ChangeNumber < previousData.ChangeNumber)) {
|
||||
foreach ((uint packageID, (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) packageData) in packagesData) {
|
||||
if (PackagesData.TryGetValue(packageID, out (uint ChangeNumber, ImmutableHashSet<uint>? AppIDs) previousData) && (packageData.ChangeNumber < previousData.ChangeNumber)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace ArchiSteamFarm {
|
||||
SteamApps.PICSChangesCallback? picsChanges = null;
|
||||
|
||||
for (byte i = 0; (i < WebBrowser.MaxTries) && (picsChanges == null); i++) {
|
||||
refreshBot = Bot.Bots?.Values.FirstOrDefault(bot => bot.IsConnectedAndLoggedOn);
|
||||
refreshBot = Bot.Bots?.Values.Where(bot => bot.IsConnectedAndLoggedOn).OrderByDescending(bot => bot.OwnedPackageIDs.Count).FirstOrDefault();
|
||||
|
||||
if (refreshBot == null) {
|
||||
return;
|
||||
@@ -89,6 +89,14 @@ namespace ArchiSteamFarm {
|
||||
LastChangeNumber = picsChanges.CurrentChangeNumber;
|
||||
|
||||
if (picsChanges.RequiresFullAppUpdate || picsChanges.RequiresFullPackageUpdate || ((picsChanges.AppChanges.Count == 0) && (picsChanges.PackageChanges.Count == 0))) {
|
||||
if (ASF.GlobalDatabase != null) {
|
||||
ASF.GlobalDatabase.OnPICSChangesRestart();
|
||||
|
||||
if (refreshBot.OwnedPackageIDs.Count > 0) {
|
||||
await ASF.GlobalDatabase.RefreshPackages(refreshBot, refreshBot.OwnedPackageIDs.Keys.ToDictionary(packageID => packageID, _ => uint.MinValue)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
await PluginsCore.OnPICSChangesRestart(picsChanges.CurrentChangeNumber).ConfigureAwait(false);
|
||||
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user