private List <DTO.MalListEntry> CreateDtoAnimeList(IDictionary <int, RecEngine.MAL.MalListEntry> animeList) { List <DTO.MalListEntry> dtoAnimeList = new List <DTO.MalListEntry>(); foreach (int animeId in animeList.Keys) { RecEngine.MAL.MalListEntry engineEntry = animeList[animeId]; DTO.MalListEntry dtoEntry = new DTO.MalListEntry(animeId, engineEntry.Rating, engineEntry.Status, engineEntry.NumEpisodesWatched); dtoAnimeList.Add(dtoEntry); } return(dtoAnimeList); }
public async Task <GetMalRecsResponse> GetMalRecsAsync(GetMalRecsRequest request, CancellationToken cancellationToken) { request.AssertArgumentNotNull("request"); request.RecSourceName.AssertArgumentNotNull("request.RecSourceName"); request.AnimeList.AssertArgumentNotNull("request.AnimeList"); request.AnimeList.Entries.AssertArgumentNotNull("request.AnimeList.Entries"); if (request.TargetScore == null && request.TargetFraction == null) { Error error = new Error(ErrorCodes.InvalidArgument, "Payload.TargetScore or Payload.TargetFraction must be set."); throw new RecServiceErrorException(error); } string targetScoreString; if (request.TargetFraction != null) { targetScoreString = request.TargetFraction.Value.ToString("P2"); } else { targetScoreString = request.TargetScore.Value.ToString(); } Logging.Log.InfoFormat("Request for {0} MAL recs using rec source {1}. User has {2} anime list entries. Target score is {3}.", request.NumRecsDesired, request.RecSourceName, request.AnimeList.Entries.Count, targetScoreString); // Acquire read lock on rec sources const int lockTimeoutInSeconds = 3; using (CancellationTokenSource lockTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(lockTimeoutInSeconds))) using (CancellationTokenSource lockCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, lockTimeout.Token)) { bool gotLock = false; try { using (var recSourcesLock = await m_recSourcesLockAsync.EnterReadLockAsync(lockCancel.Token).ConfigureAwait(false)) { gotLock = true; // Get rec source by name if (!m_recSources.ContainsKey(request.RecSourceName)) { Error error = new Error(errorCode: ErrorCodes.NoSuchRecSource, message: string.Format("No rec source called \"{0}\" is loaded.", request.RecSourceName)); throw new RecServiceErrorException(error); } ITrainableJsonRecSource recSource = m_recSources[request.RecSourceName]; // Convert DTO anime list to RecEngine anime list Dictionary <int, AnimeRecs.RecEngine.MAL.MalListEntry> entries = new Dictionary <int, RecEngine.MAL.MalListEntry>(); foreach (AnimeRecs.RecService.DTO.MalListEntry dtoEntry in request.AnimeList.Entries) { AnimeRecs.RecEngine.MAL.MalListEntry recEngineEntry = new RecEngine.MAL.MalListEntry(dtoEntry.Rating, dtoEntry.Status, dtoEntry.NumEpisodesWatched); entries[dtoEntry.MalAnimeId] = recEngineEntry; } MalUserListEntries animeList = new MalUserListEntries(ratings: entries, animes: m_animes, malUsername: null, prerequisites: m_prereqs); Stopwatch timer = Stopwatch.StartNew(); GetMalRecsResponse response = recSource.GetRecommendations(animeList, request, cancellationToken); timer.Stop(); Logging.Log.InfoFormat("Got recommendations from rec source {0}. Took {1}.", request.RecSourceName, timer.Elapsed); return(response); } } catch (OperationCanceledException) { // If we couldn't get a read lock within 3 seconds, a reload/retrain is probably going on if (!gotLock) { Error error = new Error(errorCode: ErrorCodes.Maintenance, message: "The rec service is currently undergoing maintenance and cannot respond to rec requests."); throw new RecServiceErrorException(error); } else { throw; } } } }
public GetMalRecsResponse GetMalRecs(GetMalRecsRequest request) { request.AssertArgumentNotNull("Payload"); request.RecSourceName.AssertArgumentNotNull("Payload.RecSourceName"); request.AnimeList.AssertArgumentNotNull("Payload.AnimeList"); request.AnimeList.Entries.AssertArgumentNotNull("Payload.AnimeList.Entries"); if (request.TargetScore == null && request.TargetFraction == null) { Error error = new Error(ErrorCodes.InvalidArgument, "Payload.TargetScore or Payload.TargetFraction must be set."); throw new RecServiceErrorException(error); } string targetScoreString; if (request.TargetFraction != null) { targetScoreString = request.TargetFraction.Value.ToString("P2"); } else { targetScoreString = request.TargetScore.Value.ToString(); } Logging.Log.InfoFormat("Request for {0} MAL recs using rec source {1}. User has {2} anime list entries. Target score is {3}.", request.NumRecsDesired, request.RecSourceName, request.AnimeList.Entries.Count, targetScoreString); // Acquire read lock on rec sources bool enteredLock; const int lockTimeoutInMs = 3000; using (var trainingDataReadLock = m_trainingDataLock.ScopedReadLock(lockTimeoutInMs, out enteredLock)) { // If we couldn't get a read lock within 3 seconds, a reload/retrain is probably going on if (!enteredLock) { Error error = new Error(errorCode: ErrorCodes.Maintenance, message: "The rec service is currently undergoing maintenance and cannot respond to rec requests."); throw new RecServiceErrorException(error); } using (var recSourcesReadLock = m_recSourcesLock.ScopedReadLock()) { // Get rec source by name if (!m_recSources.ContainsKey(request.RecSourceName)) { Error error = new Error(errorCode: ErrorCodes.NoSuchRecSource, message: string.Format("No rec source called \"{0}\" is loaded.", request.RecSourceName)); throw new RecServiceErrorException(error); } ITrainableJsonRecSource recSource = m_recSources[request.RecSourceName]; // Convert DTO anime list to RecEngine anime list Dictionary<int, AnimeRecs.RecEngine.MAL.MalListEntry> entries = new Dictionary<int, RecEngine.MAL.MalListEntry>(); foreach (AnimeRecs.RecService.DTO.MalListEntry dtoEntry in request.AnimeList.Entries) { AnimeRecs.RecEngine.MAL.MalListEntry recEngineEntry = new RecEngine.MAL.MalListEntry(dtoEntry.Rating, dtoEntry.Status, dtoEntry.NumEpisodesWatched); entries[dtoEntry.MalAnimeId] = recEngineEntry; } MalUserListEntries animeList = new MalUserListEntries(ratings: entries, animes: m_animes, malUsername: null, prerequisites: m_prereqs); Stopwatch timer = Stopwatch.StartNew(); GetMalRecsResponse response = recSource.GetRecommendations(animeList, request); timer.Stop(); Logging.Log.InfoFormat("Got recommendations from rec source {0}. Took {1}.", request.RecSourceName, timer.Elapsed); return response; } } }