private void OnTimer(object sender, ElapsedEventArgs e) { if (!Steam.Instance.IsLoggedOn) { lock (FreeLicenseTimer) { FreeLicenseTimer.Start(); } return; } var list = FreeLicensesToRequest.Take(REQUEST_RATE_LIMIT).ToList(); var now = DateUtils.DateTimeToUnixTime(DateTime.UtcNow) - 60; Dictionary <uint, ulong> startTimes; using (var db = Database.Get()) { startTimes = db.Query( "SELECT `SubID`, `Value` FROM `SubsInfo` WHERE `Key` = @Key AND `SubID` IN @Ids", new { Key = KeyNameCache.GetSubKeyID("extended_starttime"), Ids = list.Select(x => x.Key) } ).ToDictionary(x => (uint)x.SubID, x => Convert.ToUInt64((string)x.Value)); } foreach (var(subId, _) in list) { if (startTimes.TryGetValue(subId, out var startTime) && startTime > now) { // If start time has not been reached yet, don't remove this app from the list and keep trying to activate it continue; } FreeLicensesToRequest.TryRemove(subId, out _); } TaskManager.Run(Save); var appids = list.Select(x => x.Value).Distinct(); AppsRequestedInHour = appids.Count(); Log.WriteDebug(nameof(FreeLicense), $"Requesting {AppsRequestedInHour} free apps as the rate limit timer ran: {string.Join(", ", appids)}"); JobManager.AddJob(() => Steam.Instance.Apps.RequestFreeLicense(appids)); if (FreeLicensesToRequest.Count > 0) { lock (FreeLicenseTimer) { FreeLicenseTimer.Start(); } } }
public PICSChanges(CallbackManager manager) { if (Settings.IsFullRun) { var timer = new Timer { Interval = TimeSpan.FromSeconds(10).TotalMilliseconds }; timer.Elapsed += (sender, args) => FullUpdateProcessor.IsBusy(); timer.Start(); return; } manager.Subscribe <SteamApps.PICSChangesCallback>(OnPICSChanges); using (var db = Database.Get()) { BillingTypeKey = KeyNameCache.GetSubKeyID("root_billingtype"); if (LocalConfig.Current.ChangeNumber == 0) { PreviousChangeNumber = db.ExecuteScalar <uint>("SELECT `ChangeID` FROM `Changelists` ORDER BY `ChangeID` DESC LIMIT 1"); LocalConfig.Current.ChangeNumber = PreviousChangeNumber; } else { PreviousChangeNumber = LocalConfig.Current.ChangeNumber; } Log.WriteInfo(nameof(PICSChanges), $"Previous changelist was {PreviousChangeNumber}"); } if (PreviousChangeNumber == 0) { Log.WriteWarn(nameof(PICSChanges), "Looks like there are no changelists in the database."); Log.WriteWarn(nameof(PICSChanges), $"If you want to fill up your database first, restart with \"FullRun\" setting set to {(int)FullRunState.Enumerate}."); } }
private async Task ProcessKey(string keyName, string displayName, string value, bool isJSON = false) { if (keyName.Length > 90) { Log.WriteError(nameof(SubProcessor), $"Key {keyName} for SubID {SubID} is too long, not inserting info."); return; } // All keys in PICS are supposed to be lower case. // But currently some keys in packages are not lowercased, // this lowercases everything to make sure nothing breaks in future keyName = keyName.ToLowerInvariant().Trim(); if (!CurrentData.ContainsKey(keyName)) { CurrentData[keyName] = new PICSInfo { Processed = true, }; var key = KeyNameCache.GetSubKeyID(keyName); if (key == 0) { var type = isJSON ? 86 : 0; // 86 is a hardcoded const for the website key = await KeyNameCache.CreateSubKey(keyName, displayName, type); if (key == 0) { // We can't insert anything because key wasn't created Log.WriteError(nameof(SubProcessor), $"Failed to create key {keyName} for SubID {SubID}, not inserting info."); return; } IRC.Instance.SendOps($"New package keyname: {Colors.BLUE}{keyName} {Colors.LIGHTGRAY}(ID: {key}) ({displayName}) - {SteamDB.GetPackageUrl(SubID, "history")}"); } await DbConnection.ExecuteAsync("INSERT INTO `SubsInfo` (`SubID`, `Key`, `Value`) VALUES (@SubID, @Key, @Value)", new { SubID, Key = key, Value = value }); await MakeHistory("created_key", key, string.Empty, value); return; } var data = CurrentData[keyName]; if (data.Processed) { Log.WriteWarn(nameof(SubProcessor), $"Duplicate key {keyName} in SubID {SubID}"); return; } data.Processed = true; CurrentData[keyName] = data; if (data.Value == value) { return; } await DbConnection.ExecuteAsync("UPDATE `SubsInfo` SET `Value` = @Value WHERE `SubID` = @SubID AND `Key` = @Key", new { SubID, data.Key, Value = value }); await MakeHistory("modified_key", data.Key, data.Value, value); }
public static async Task HandleMetadataInfo(SteamApps.PICSProductInfoCallback callback) { var apps = new List <uint>(); var subs = new List <uint>(); await using var db = await Database.GetConnectionAsync(); if (callback.Apps.Any()) { Log.WriteDebug(nameof(FullUpdateProcessor), $"Received metadata only product info for {callback.Apps.Count} apps ({callback.Apps.First().Key}...{callback.Apps.Last().Key}), job: {callback.JobID}"); var currentChangeNumbers = (await db.QueryAsync <(uint, uint)>( "SELECT `AppID`, `Value` FROM `AppsInfo` WHERE `Key` = @ChangeNumberKey AND `AppID` IN @Apps", new { ChangeNumberKey = KeyNameCache.GetAppKeyID("root_changenumber"), Apps = callback.Apps.Keys } )).ToDictionary(x => x.Item1, x => x.Item2); foreach (var app in callback.Apps.Values) { currentChangeNumbers.TryGetValue(app.ID, out var currentChangeNumber); if (currentChangeNumber == app.ChangeNumber) { continue; } Log.WriteInfo(nameof(FullUpdateProcessor), $"App {app.ID} - Change: {currentChangeNumber} -> {app.ChangeNumber}"); apps.Add(app.ID); if (!Settings.IsFullRun) { await db.ExecuteAsync("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeNumber) ON DUPLICATE KEY UPDATE `Date` = `Date`", new { app.ChangeNumber }); await db.ExecuteAsync("INSERT INTO `ChangelistsApps` (`ChangeID`, `AppID`) VALUES (@ChangeNumber, @AppID) ON DUPLICATE KEY UPDATE `AppID` = `AppID`", new { AppID = app.ID, app.ChangeNumber }); } } } if (callback.Packages.Any()) { Log.WriteDebug(nameof(FullUpdateProcessor), $"Received metadata only product info for {callback.Packages.Count} packages ({callback.Packages.First().Key}...{callback.Packages.Last().Key}), job: {callback.JobID}"); var currentChangeNumbers = (await db.QueryAsync <(uint, uint)>( "SELECT `SubID`, `Value` FROM `SubsInfo` WHERE `Key` = @ChangeNumberKey AND `SubID` IN @Subs", new { ChangeNumberKey = KeyNameCache.GetSubKeyID("root_changenumber"), Subs = callback.Packages.Keys } )).ToDictionary(x => x.Item1, x => x.Item2); foreach (var sub in callback.Packages.Values) { currentChangeNumbers.TryGetValue(sub.ID, out var currentChangeNumber); if (currentChangeNumber == sub.ChangeNumber) { continue; } Log.WriteInfo(nameof(FullUpdateProcessor), $"Package {sub.ID} - Change: {currentChangeNumber} -> {sub.ChangeNumber}"); subs.Add(sub.ID); if (!Settings.IsFullRun) { await db.ExecuteAsync("INSERT INTO `Changelists` (`ChangeID`) VALUES (@ChangeNumber) ON DUPLICATE KEY UPDATE `Date` = `Date`", new { sub.ChangeNumber }); await db.ExecuteAsync("INSERT INTO `ChangelistsSubs` (`ChangeID`, `SubID`) VALUES (@ChangeNumber, @SubID) ON DUPLICATE KEY UPDATE `SubID` = `SubID`", new { SubID = sub.ID, sub.ChangeNumber }); } } } if (apps.Any() || subs.Any()) { JobManager.AddJob( () => Steam.Instance.Apps.PICSGetAccessTokens(apps, subs), new PICSTokens.RequestedTokens { Apps = apps, Packages = subs, }); } }