예제 #1
0
        public async Task <MalTrainingData> LoadMalTrainingDataAsync(CancellationToken cancellationToken)
        {
            // Load all anime, users, and entries in parallel, then combine them into training data.
            try
            {
                Dictionary <int, MalAnime>  animes;
                Dictionary <int, mal_user>  dbUsers;
                IList <mal_list_entry_slim> dbEntrySlurp;

                using (CancellationTokenSource faultCanceler = new CancellationTokenSource())
                    using (CancellationTokenSource faultOrUserCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, faultCanceler.Token))
                    {
                        Task <Dictionary <int, MalAnime> > animeTask = AsyncUtils.EnsureExceptionsWrapped(
                            () => SlurpAnimeAsync(faultOrUserCancel.Token));
                        CancellableTask cancellableAnimeTask = new CancellableTask(animeTask, faultCanceler);

                        Task <Dictionary <int, mal_user> > userTask = AsyncUtils.EnsureExceptionsWrapped(
                            () => SlurpUsersAsync(faultOrUserCancel.Token));
                        CancellableTask cancellableUserTask = new CancellableTask(userTask, faultCanceler);

                        Task <IList <mal_list_entry_slim> > entryTask = AsyncUtils.EnsureExceptionsWrapped(
                            () => SlurpEntriesAsync(faultOrUserCancel.Token));
                        CancellableTask cancellableEntryTask = new CancellableTask(entryTask, faultCanceler);

                        await AsyncUtils.WhenAllCancelOnFirstExceptionDontWaitForCancellations(cancellableEntryTask, cancellableAnimeTask, cancellableUserTask).ConfigureAwait(false);

                        animes       = animeTask.Result;
                        dbUsers      = userTask.Result;
                        dbEntrySlurp = entryTask.Result;
                    }

                Logging.Log.Debug("Processing list entries from the database.");
                long entryCount = 0;

                Dictionary <int, List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> > entriesByUser =
                    new Dictionary <int, List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> >();

                foreach (mal_list_entry_slim dbEntry in dbEntrySlurp)
                {
                    entryCount++;
                    mal_user dbUser;
                    if (!dbUsers.TryGetValue(dbEntry.mal_user_id, out dbUser) || !animes.ContainsKey(dbEntry.mal_anime_id))
                    {
                        // Entry for an anime or user that wasn't in the database...there must have been an update going on between the time we got users, anime, and list entries
                        continue;
                    }
                    List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList;
                    if (!entriesByUser.TryGetValue(dbEntry.mal_user_id, out animeList))
                    {
                        animeList = new List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>();
                        entriesByUser[dbEntry.mal_user_id] = animeList;
                    }

                    animeList.Add(new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(
                                      animeId: dbEntry.mal_anime_id,
                                      entry: new MalListEntry(
                                          rating: (byte?)dbEntry.rating,
                                          status: (CompletionStatus)dbEntry.mal_list_entry_status_id,
                                          numEpisodesWatched: dbEntry.num_episodes_watched
                                          )
                                      ));
                }

                Dictionary <int, MalUserListEntries> users = new Dictionary <int, MalUserListEntries>(dbUsers.Count);
                foreach (int userId in entriesByUser.Keys)
                {
                    List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList = entriesByUser[userId];
                    animeList.Capacity = animeList.Count;
                    ReadOnlyMalListEntryDictionary listEntries = new ReadOnlyMalListEntryDictionary(animeList);
                    users[userId] = new MalUserListEntries(listEntries, animes, dbUsers[userId].mal_name, okToRecommendPredicate: null);
                }

                Logging.Log.DebugFormat("Done processing {0} list entries.", entryCount);

                return(new MalTrainingData(users, animes));
            }
            catch (Exception ex) when(!(ex is OperationCanceledException))
            {
                throw new Exception(string.Format("Error loading MAL training data: {0}", ex.Message), ex);
            }
        }