public async Task TestImputation()
        {
            var games = (await StorageHelper.GetAllApps(AppEntity.MeasuredFilter).ConfigureAwait(true)).ToArray();

            await Imputer.ImputeByGenre(games).ConfigureAwait(false);

            AssertValidTtbs(games);
        }
        private static void AssertTtbFixes(int main, int extras, int completionist, bool mainImputed, bool extrasImputed, bool completionistImputed)
        {
            int mainBefore          = main;
            int extrasBefore        = extras;
            int completionistBefore = completionist;

            Imputer.FixInvalidTtbs(ref main, mainImputed, ref extras, extrasImputed, ref completionist, completionistImputed, new TtbRatios(0.7, 0.4, 0.3));
            Assert.IsTrue(completionist >= extras && extras >= main,
                          Invariant($"Invalid TTBs not fixed: M{mainBefore}/E{extrasBefore}/C{completionistBefore} -> M{main}/E{extras}/C{completionist}"));
        }
        private static async Task UpdateMissingGames()
        {
            var tickCount = Environment.TickCount;

            MissingUpdaterEventSource.Log.UpdateMissingGamesStart();

            var allSteamAppsTask = GetAllSteamApps(s_client);
            var allKnownAppsTask = StorageHelper.GetAllApps(null, StorageRetries);

            await Task.WhenAll(allSteamAppsTask, allKnownAppsTask).ConfigureAwait(false);

            var allSteamApps = allSteamAppsTask.Result;
            var allKnownApps = allKnownAppsTask.Result;

            var knownSteamIdsHash = new HashSet <int>(allKnownApps.Select(ae => ae.SteamAppId));
            var missingApps       = allSteamApps.Where(a => !knownSteamIdsHash.Contains(a.appid)).Take(UpdateLimit).ToArray();

            MissingUpdaterEventSource.Log.MissingAppsDetermined(missingApps);

            var updates = new ConcurrentBag <AppEntity>();
            InvalidOperationException ioe = null;

            try
            {
                await SteamStoreHelper
                .GetStoreInformationUpdates(missingApps.Select(a => new BasicStoreInfo(a.appid, a.name, null)).ToArray(), s_client, updates)
                .ConfigureAwait(false);
            }
            catch (Exception e)
            {
                ioe = new InvalidOperationException("Could not retrieve store information for all games", e);
            }

            var measuredUpdates = updates.Where(a => a.Measured).ToArray();

            if (measuredUpdates.Length > 0)
            {
                await HltbScraper.ScrapeHltb(measuredUpdates).ConfigureAwait(false);

                //re-impute for measured updates
                await Imputer.Impute(allKnownApps.Where(a => a.Measured).Concat(measuredUpdates).ToArray()).ConfigureAwait(false);
            }

            //we're inserting new entries, no fear of collisions (even if two jobs overlap the next one will fix it)
            await StorageHelper.Insert(updates, "updating missing games", StorageHelper.SteamToHltbTableName, StorageRetries).ConfigureAwait(false);

            if (ioe != null)
            {
                throw ioe; //fail job
            }

            await SiteUtil.SendSuccessMail("Missing updater", updates.Count + " app(s) added", tickCount).ConfigureAwait(false);

            MissingUpdaterEventSource.Log.UpdateMissingGamesStop();
        }
Beispiel #4
0
        private static async Task UpdateUnknownApps()
        {
            var ticks = Environment.TickCount;

            UnknownUpdaterEventSource.Log.UpdateUnknownAppsStart();

            var allUnknownApps = (await StorageHelper.GetAllApps(AppEntity.UnknownFilter, StorageRetries).ConfigureAwait(false)).Take(UpdateLimit).ToArray();

            var updates = new ConcurrentBag <AppEntity>();
            InvalidOperationException ioe = null;

            try
            {
                await SteamStoreHelper.GetStoreInformationUpdates(
                    allUnknownApps.Select(ae => new BasicStoreInfo(ae.SteamAppId, ae.SteamName, ae.AppType)).ToArray(), Client, updates).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                ioe = new InvalidOperationException("Could not retrieve store information for all apps", e);
            }

            UnknownUpdaterEventSource.Log.UpdateNewlyCategorizedApps(updates);

            var measuredUpdates = updates.Where(a => a.Measured).ToArray();

            if (measuredUpdates.Length > 0)
            {
                await HltbScraper.ScrapeHltb(measuredUpdates).ConfigureAwait(false);

                //re-impute with new scraped values for updated games (Enumberable.Union() guarantees measuredUpdates will be enumerated before allApps!)
                var allMeasuredApps = await StorageHelper.GetAllApps(AppEntity.MeasuredFilter).ConfigureAwait(false);

                await Imputer.Impute(measuredUpdates.Union(allMeasuredApps, new AppEntitySteamIdComparer()).ToArray()).ConfigureAwait(false);
            }

            var unknownAppsMap = allUnknownApps.ToDictionary(ae => ae.SteamAppId);
            await StorageHelper.ExecuteOperations(updates,
                                                  ae => new[] { TableOperation.Delete(unknownAppsMap[ae.SteamAppId]), TableOperation.Insert(ae) },
                                                  StorageHelper.SteamToHltbTableName, "updating previously unknown games", StorageRetries).ConfigureAwait(false);

            if (ioe != null)
            {
                throw ioe; //fail job
            }

            await SiteUtil.SendSuccessMail("Unknown updater",
                                           updates.Count + " previously unknown game(s) updated", ticks).ConfigureAwait(false);

            UnknownUpdaterEventSource.Log.UpdateUnknownAppsStop();
        }
        private static void AssertSanitization(int main, int extras, int completionist, int mainExpected, int extrasExpected, int completionistExpected)
        {
            var game = new AppEntity(1, "test", AppEntity.GameTypeName);

            game.SetMainTtb(main, main == 0);
            game.SetExtrasTtb(extras, extras == 0);
            game.SetCompletionistTtb(completionist, completionist == 0);

            Imputer.Sanitize(new [] { game });

            var ttbs = String.Format(CultureInfo.InvariantCulture, "{0}/{1}/{2}", main, extras, completionist);

            Assert.AreEqual(mainExpected, game.MainTtb, "Invalid Main sanitization for TTBs: " + ttbs);
            Assert.AreEqual(extrasExpected, game.ExtrasTtb, "Invalid Extras sanitization for TTBs: " + ttbs);
            Assert.AreEqual(completionistExpected, game.CompletionistTtb, "Invalid Completionist sanitization for TTBs: " + ttbs);
        }
Beispiel #6
0
        private static async Task MainAsync()
        {
            var tickCount = Environment.TickCount;

            SiteUtil.SetDefaultConnectionLimit();

            var allMeasuredApps = (await StorageHelper.GetAllApps(AppEntity.MeasuredFilter, StorageRetries).ConfigureAwait(false)).Take(ScrapingLimit).ToArray();

            await ScrapeHltb(allMeasuredApps).ConfigureAwait(false);

            await Imputer.Impute(allMeasuredApps).ConfigureAwait(false);

            //we're using Replace since the only other update to an existing game-typed entity would have to be manual which should take precedence
            await StorageHelper.Replace(allMeasuredApps, "updating scraped gametimes", StorageHelper.SteamToHltbTableName, StorageRetries).ConfigureAwait(false);

            await SiteUtil.SendSuccessMail("HLTB scraper", allMeasuredApps.Length + " game(s) scraped", tickCount).ConfigureAwait(false);
        }
Beispiel #7
0
        private static async Task ProcessDistinctSuggestions(
            SuggestionEntity[] distinctSuggestions, IReadOnlyDictionary <int, AppEntity> allMeasuredAppsMap, Dictionary <int, AppEntity> allMeasuredAppsMapForImputation)
        {
            var validSuggestions = new ConcurrentDictionary <int, SuggestionInfo>(
                GetSuggestionsForKnownAndPrepareApps(allMeasuredAppsMap, distinctSuggestions).ToDictionary(si => si.App.SteamAppId));

            var invalidSuggestions = new ConcurrentBag <SuggestionInfo>(
                distinctSuggestions.Where(s => !validSuggestions.ContainsKey(s.SteamAppId))
                .Select(s => new SuggestionInfo(s, new AppEntity(-1, "[Unknown]", "[Unknown]"), -1, "[Unknown]")));

            Console.WriteLine("Scraping HLTB info for suggestions...");
            await HltbScraper.ScrapeHltb(validSuggestions.Values.Where(s => !s.Suggestion.IsRetype).Select(s => s.App).ToArray(),
                                         (a, e) =>
            {
                Console.WriteLine("Can't parse HLTB ID {0} suggested for {1} ({2}): {3}", a.HltbId, a.SteamName, a.SteamAppId, e);
                bool removed = validSuggestions.TryRemove(a.SteamAppId, out var invalidSuggestion);
                Trace.Assert(removed, "Invalid validSuggestions state");
                invalidSuggestions.Add(invalidSuggestion);
            }).ConfigureAwait(false);

            Console.WriteLine("Removing invalid suggestions...");
            await RemoveInvalidSuggestions(invalidSuggestions);

            Console.WriteLine("Processing suggestions...");

            var acceptedHltbSuggestions = await ProcessSuggestionsByUserInput(validSuggestions.Values).ConfigureAwait(false);

            if (acceptedHltbSuggestions.Count > 0)
            {
                foreach (var suggestion in acceptedHltbSuggestions)
                {
                    allMeasuredAppsMapForImputation[suggestion.Suggestion.SteamAppId] = suggestion.App;
                }

                Console.WriteLine("Imputing missing TTBs from genre stats...");
                await Imputer.Impute(allMeasuredAppsMapForImputation.Values.ToArray()).ConfigureAwait(false);

                Console.Write("Updating HLTB suggestions... ");
                foreach (var suggestion in acceptedHltbSuggestions)
                {
                    await StorageHelper.AcceptSuggestion(suggestion.App, suggestion.Suggestion).ConfigureAwait(false);
                }
            }
        }