/// <summary> /// Asynchronously gets a <see cref="IEnumerable{T}"/> representing competitors in the sport event associated with the current instance /// </summary> /// <returns>A <see cref="Task{T}"/> representing the retrieval operation</returns> public async Task <IEnumerable <ICompetitor> > GetCompetitorsAsync() { var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id); if (competitionCI == null) { ExecutionLog.Debug($"Missing data. No sportEvent cache item for id={Id}."); return(null); } var items = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await competitionCI.GetCompetitorsIdsAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <URN> > >(competitionCI.GetCompetitorsIdsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("CompetitorsIds")).ConfigureAwait(false); var competitorsIds = items == null ? new List <URN>() : items.ToList(); if (!competitorsIds.Any()) { return(new List <ICompetitor>()); } var tasks = competitorsIds.Select(s => _sportEntityFactory.BuildTeamCompetitorAsync(s, Cultures, competitionCI, ExceptionStrategy)).ToList(); await Task.WhenAll(tasks).ConfigureAwait(false); return(tasks.Select(s => s.Result)); }
/// <summary> /// Asynchronously gets a <see cref="ITeamCompetitor" /> representing away competitor of the match associated with the current instance /// </summary> /// <returns>A <see cref="Task{ITeamCompetitor}"/> representing the retrieval operation</returns> public async Task<ITeamCompetitor> GetAwayCompetitorAsync() { var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return null; } var items = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetCompetitorsIdsAsync(Cultures).ConfigureAwait(false) : await new Func<IEnumerable<CultureInfo>, Task<IEnumerable<URN>>>(matchCI.GetCompetitorsIdsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("CompetitorsIds")).ConfigureAwait(false); if (items == null) { return null; } var competitorUrns = items.ToList(); if (competitorUrns.Count == 2) { return await _sportEntityFactory.BuildTeamCompetitorAsync(competitorUrns[1], Cultures, matchCI, ExceptionStrategy).ConfigureAwait(false); } ExecutionLog.Error($"Received {competitorUrns.Count} competitors for match[Id = {Id}]. Match can have only 2 competitors."); throw new InvalidOperationException($"Invalid number of competitors. Match must have exactly 2 competitors, received {competitorUrns.Count}"); }
/// <summary> /// Asynchronously gets the associated category /// </summary> /// <returns>The associated category</returns> public async Task <ICategorySummary> GetCategoryAsync() { var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id); if (lotteryCI == null) { ExecutionLog.Debug($"Missing data. No lottery cache item for id={Id}."); return(null); } var categoryId = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await lotteryCI.GetCategoryIdAsync().ConfigureAwait(false) : await new Func <Task <URN> >(lotteryCI.GetCategoryIdAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("CategoryId")).ConfigureAwait(false); if (categoryId == null) { ExecutionLog.Debug($"Missing data. No categoryId for lottery cache item with id={Id}."); return(null); } var categoryData = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await _sportDataCache.GetCategoryAsync(categoryId, Cultures).ConfigureAwait(false) : await new Func <URN, IEnumerable <CultureInfo>, Task <CategoryData> >(_sportDataCache.GetCategoryAsync).SafeInvokeAsync(categoryId, Cultures, ExecutionLog, GetFetchErrorMessage("CategoryData")).ConfigureAwait(false); return(categoryData == null ? null : new CategorySummary(categoryData.Id, categoryData.Names, categoryData.CountryCode)); }
/// <summary> /// Invoked when the <code>_timer</code> ticks in order to periodically fetch market descriptions for configured /// languages /// </summary> /// <param name="sender">The <see cref="ITimer" /> raising the event</param> /// <param name="e">A <see cref="EventArgs" /> instance containing the event data</param> private async void OnTimerElapsed(object sender, EventArgs e) { if (_isDisposed) { return; } //when the timer first elapses fetch data only for languages which were not yet fetched. On subsequent timer elapses fetch data for all configured languages var languagesToFetch = _prefetchLanguages .Where(language => !_fetchedLanguages.Contains(language) || _hasTimerElapsedOnce).ToList(); if (!languagesToFetch.Any()) { _hasTimerElapsedOnce = true; return; } try { _fetchedLanguages.Clear(); ExecutionLog.Debug( $"Loading invariant market descriptions for [{string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName))}] (timer)."); await GetMarketInternalAsync(0, languagesToFetch).ConfigureAwait(false); } catch (Exception ex) { if (ex is CommunicationException || ex is DeserializationException || ex is FormatException) { var languagesString = string.Join(",", languagesToFetch.Select(l => l.TwoLetterISOLanguageName)); ExecutionLog.Warn( $"An error occurred while periodically fetching market description of languages {languagesString}", ex); return; } var disposedException = ex as ObjectDisposedException; if (disposedException != null) { ExecutionLog.Warn( $"An error occurred while periodically fetching market descriptions because the object graph is being disposed. Object causing the exception:{disposedException.ObjectName}"); return; } if (ex is TaskCanceledException) { ExecutionLog.Warn( "An error occurred while periodically fetching market descriptions because the object graph is being disposed."); return; } ExecutionLog.Warn("An error occurred while periodically fetching market description.", ex); } _hasTimerElapsedOnce = true; }
public async Task <StageType> GetStageTypeAsync() { var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id); if (stageCI == null) { ExecutionLog.Debug($"Missing data. No stage cache item for id={Id}."); return(StageType.Child); } return(await stageCI.GetTypeAsync().ConfigureAwait(false)); }
/// <summary> /// Adds the sport event status to the internal cache /// </summary> /// <param name="eventId">The eventId of the sport event status to be cached</param> /// <param name="sportEventStatus">The sport event status to be cached</param> /// <param name="statusOnEvent">The sport event status received directly on event level</param> /// <param name="source">The source of the SES</param> // ReSharper disable once UnusedParameter.Local private void AddSportEventStatus(URN eventId, SportEventStatusCI sportEventStatus, string statusOnEvent, string source) { if (_isDisposed) { return; } if (sportEventStatus == null) { return; } Guard.Argument(eventId, nameof(eventId)).NotNull(); if (string.IsNullOrEmpty(source) || source.Equals("OddsChange", StringComparison.InvariantCultureIgnoreCase) || source.Equals("SportEventSummary", StringComparison.InvariantCultureIgnoreCase) || !_sportEventStatusCache.Contains(eventId.ToString())) { lock (_lock) { if (!string.IsNullOrEmpty(source)) { if (OperationManager.IgnoreBetPalTimelineSportEventStatus && source.Contains("Timeline") && _ignoreEventsTimelineCache.Contains(eventId.ToString())) { ExecutionLog.Debug($"Received SES for {eventId} from {source} with EventStatus:{sportEventStatus.Status} (timeline ignored)"); return; } source = $" from {source}"; } ExecutionLog.Debug($"Received SES for {eventId}{source} with EventStatus:{sportEventStatus.Status}"); var cacheItem = _sportEventStatusCache.AddOrGetExisting(eventId.ToString(), sportEventStatus, new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(OperationManager.SportEventStatusCacheTimeout.TotalSeconds) }) as SportEventStatusCI; if (cacheItem != null) { cacheItem.SetFeedStatus(sportEventStatus.FeedStatusDTO); cacheItem.SetSapiStatus(sportEventStatus.SapiStatusDTO); } } } else { ExecutionLog.Debug($"Received SES for {eventId} from {source} with EventStatus:{sportEventStatus.Status} (ignored)"); } }
/// <summary> /// Asynchronously gets a <see cref="BookingStatus"/> enum member providing booking status for the associated @event or a null reference if booking status is not known /// </summary> /// <returns></returns> public async Task<BookingStatus?> GetBookingStatusAsync() { var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id); if (competitionCI == null) { ExecutionLog.Debug($"Missing data. No sportEvent cache item for id={Id}."); return null; } return ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await competitionCI.GetBookingStatusAsync().ConfigureAwait(false) : await new Func<Task<BookingStatus?>>(competitionCI.GetBookingStatusAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("BookingStatus")).ConfigureAwait(false); }
/// <summary> /// Asynchronously gets a <see cref="IFixture"/> instance containing information about the arranged sport event /// </summary> /// <returns>A <see cref="Task{IFixture}"/> representing the retrieval operation</returns> /// <remarks>A Fixture is a sport event that has been arranged for a particular time and place</remarks> public async Task<IFixture> GetFixtureAsync() { var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return null; } return ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetFixtureAsync(Cultures).ConfigureAwait(false) : await new Func<IEnumerable<CultureInfo>, Task<IFixture>>(matchCI.GetFixtureAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("Fixture")).ConfigureAwait(false); }
/// <summary> /// Asynchronously gets the list of associated <see cref="IDraw"/> /// </summary> /// <returns>A <see cref="Task{T}"/> representing an async operation</returns> public async Task <IEnumerable <IDraw> > GetDrawsAsync() { var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id); if (lotteryCI == null) { ExecutionLog.Debug($"Missing data. No lottery cache item for id={Id}."); return(null); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await lotteryCI.GetScheduledDrawsAsync().ConfigureAwait(false) : await new Func <Task <IEnumerable <URN> > >(lotteryCI.GetScheduledDrawsAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("ScheduledDraws")).ConfigureAwait(false); return(item.Select(s => new Draw(s, SportId, SportEventCache, Cultures, ExceptionStrategy))); }
/// <summary> /// Asynchronously gets a <see cref="IRound"/> representing the tournament round to which the sport event associated with the current instance belongs to /// </summary> /// <returns>A <see cref="Task{IRound}"/> representing the retrieval operation</returns> public async Task <IRound> GetTournamentRoundAsync() { var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return(null); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetTournamentRoundAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <RoundCI> >(matchCI.GetTournamentRoundAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("Round")).ConfigureAwait(false); return(item == null ? null : new Round(item, Cultures)); }
/// <summary> /// Asynchronously gets <see cref="T:System.Collections.Generic.IEnumerable`1" /> list of associated <see cref="T:Sportradar.OddsFeed.SDK.Entities.REST.IDrawResult" /> /// </summary> /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing an async operation</returns> /// <exception cref="System.NotImplementedException"></exception> public async Task <IEnumerable <IDrawResult> > GetResultsAsync() { var drawCI = (DrawCI)SportEventCache.GetEventCacheItem(Id); if (drawCI == null) { ExecutionLog.Debug($"Missing data. No draw cache item for id={Id}."); return(null); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await drawCI.GetResultsAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <DrawResultCI> > >(drawCI.GetResultsAsync).SafeInvokeAsync(Cultures, ExecutionLog, "DrawResults").ConfigureAwait(false); return(item?.Select(s => new DrawResult(s))); }
/// <summary> /// Asynchronously gets a liveOdds /// </summary> /// <returns>A liveOdds</returns> public async Task <string> GetLiveOddsAsync() { var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id); if (competitionCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return(null); } var liveOdds = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await competitionCI.GetLiveOddsAsync().ConfigureAwait(false) : await new Func <Task <string> >(competitionCI.GetLiveOddsAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("LiveOdds")).ConfigureAwait(false); return(liveOdds); }
/// <summary> /// Asynchronously gets <see cref="DrawStatus" /> associated with the current instance /// </summary> /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing an async operation</returns> /// <exception cref="System.NotImplementedException"></exception> public async Task <DrawStatus> GetStatusAsync() { var drawCI = (DrawCI)SportEventCache.GetEventCacheItem(Id); if (drawCI == null) { ExecutionLog.Debug($"Missing data. No draw cache item for id={Id}."); return(DrawStatus.Unknown); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await drawCI.GetStatusAsync().ConfigureAwait(false) : await new Func <Task <DrawStatus> >(drawCI.GetStatusAsync).SafeInvokeAsync(ExecutionLog, "DrawStatus").ConfigureAwait(false); return(item); }
/// <summary> /// Asynchronously loads the list of market descriptions from the Sports API /// </summary> /// <returns>Returns true if the action succeeded</returns> public async Task <bool> LoadMarketDescriptionsAsync() { try { ExecutionLog.Debug($"Loading variant market descriptions for [{string.Join(", ", _prefetchLanguages.Select(l => l.TwoLetterISOLanguageName))}] (user request)."); _fetchedLanguages.Clear(); await GetVariantDescriptionInternalAsync("0", _prefetchLanguages).ConfigureAwait(false); } catch (Exception ex) { ExecutionLog.Warn($"An error occurred while fetching market descriptions variant list. The exception:{ex.Message}"); return(false); } return(true); }
/// <summary> /// Asynchronously gets a <see cref="ILongTermEvent"/> representing the tournament to which the sport event associated with the current instance belongs to /// </summary> /// <returns>A <see cref="Task{ILongTermEvent}"/> representing the retrieval operation</returns> public async Task<ILongTermEvent> GetTournamentAsync() { var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return null; } var tournamentId = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetTournamentIdAsync(Cultures).ConfigureAwait(false) : await new Func<IEnumerable<CultureInfo>, Task<URN>>(matchCI.GetTournamentIdAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("ILongTermEvent")).ConfigureAwait(false); return tournamentId == null ? null : _sportEntityFactory.BuildSportEvent<ILongTermEvent>(tournamentId, SportId, Cultures, ExceptionStrategy); }
/// <summary> /// Asynchronously gets a <see cref="ISportEventConditions"/> instance representing live conditions of the sport event associated with the current instance /// </summary> /// <returns>A <see cref="Task{IVenue}"/> representing the retrieval operation</returns> /// <remarks>A Fixture is a sport event that has been arranged for a particular time and place</remarks> public async Task<ISportEventConditions> GetConditionsAsync() { var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id); if (competitionCI == null) { ExecutionLog.Debug($"Missing data. No sportEvent cache item for id={Id}."); return null; } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await competitionCI.GetConditionsAsync(Cultures).ConfigureAwait(false) : await new Func<IEnumerable<CultureInfo>, Task<SportEventConditionsCI>>(competitionCI.GetConditionsAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("EventConditions")).ConfigureAwait(false); return item == null ? null : new SportEventConditions(item, Cultures); }
public async Task <IEnumerable <IStage> > GetStagesAsync() { var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id); if (stageCI == null) { ExecutionLog.Debug($"Missing data. No stage cache item for id={Id}."); return(null); } var cacheItems = ExceptionStrategy == ExceptionHandlingStrategy.CATCH ? await stageCI.GetStagesAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <IEnumerable <StageCI> > >(stageCI.GetStagesAsync) .SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("ChildStages")).ConfigureAwait(false); return(cacheItems?.Select(c => new Stage(c.Id, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, _matchStatusesCache, Cultures, ExceptionStrategy))); }
/// <summary> /// Asynchronously gets <see cref="IDrawInfo"/> associated with the current instance /// </summary> /// <returns>A <see cref="Task{T}"/> representing an async operation</returns> public async Task <IDrawInfo> GetDrawInfoAsync() { var lotteryCI = (LotteryCI)SportEventCache.GetEventCacheItem(Id); if (lotteryCI == null) { ExecutionLog.Debug($"Missing data. No lottery cache item for id={Id}."); return(null); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await lotteryCI.GetDrawInfoAsync().ConfigureAwait(false) : await new Func <Task <DrawInfoCI> >(lotteryCI.GetDrawInfoAsync).SafeInvokeAsync(ExecutionLog, GetFetchErrorMessage("DrawInfo")).ConfigureAwait(false); return(item == null ? null : new DrawInfo(item)); }
/// <summary> /// Asynchronously gets a <see cref="IVenue"/> instance representing a venue where the sport event associated with the /// current instance will take place /// </summary> /// <returns>A <see cref="Task{IVenue}"/> representing the retrieval operation</returns> public async Task <IVenue> GetVenueAsync() { var competitionCI = (CompetitionCI)SportEventCache.GetEventCacheItem(Id); if (competitionCI == null) { ExecutionLog.Debug($"Missing data. No sportEvent cache item for id={Id}."); return(null); } var item = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await competitionCI.GetVenueAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <VenueCI> >(competitionCI.GetVenueAsync).SafeInvokeAsync(Cultures, ExecutionLog, "Venue").ConfigureAwait(false); return(item == null ? null : new Venue(item, Cultures)); }
/// <summary> /// Asynchronously gets the associated delayed info /// </summary> /// <returns>A <see cref="T:System.Threading.Tasks.Task`1" /> representing the retrieval operation</returns> /// <exception cref="NotImplementedException"></exception> public async Task <IDelayedInfo> GetDelayedInfoAsync() { var matchCI = (MatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return(null); } var delayedInfoCI = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetDelayedInfoAsync(Cultures).ConfigureAwait(false) : await new Func <IEnumerable <CultureInfo>, Task <DelayedInfoCI> >(matchCI.GetDelayedInfoAsync).SafeInvokeAsync(Cultures, ExecutionLog, GetFetchErrorMessage("DelayedInfo")).ConfigureAwait(false); return(delayedInfoCI == null ? null : new DelayedInfo(delayedInfoCI)); }
/// <summary> /// Asynchronously gets the associated event timeline for single culture /// </summary> /// <param name="culture">The languages to which the returned instance should be translated</param> /// <remarks>Recommended to be used when only <see cref="IEventTimeline"/> is needed for this <see cref="IMatch"/></remarks> /// <returns>A <see cref="Task{IEventTimeline}"/> representing the retrieval operation</returns> public async Task<IEventTimeline> GetEventTimelineAsync(CultureInfo culture) { var matchCI = (IMatchCI)SportEventCache.GetEventCacheItem(Id); if (matchCI == null) { ExecutionLog.Debug($"Missing data. No match cache item for id={Id}."); return null; } var oneCulture = new List<CultureInfo> {culture ?? Cultures.First()}; var eventTimelineCI = ExceptionStrategy == ExceptionHandlingStrategy.THROW ? await matchCI.GetEventTimelineAsync(oneCulture).ConfigureAwait(false) : await new Func<IEnumerable<CultureInfo>, Task<EventTimelineCI>>(matchCI.GetEventTimelineAsync).SafeInvokeAsync(oneCulture, ExecutionLog, GetFetchErrorMessage("EventTimeline")).ConfigureAwait(false); return eventTimelineCI == null ? null : new EventTimeline(eventTimelineCI); }
public async Task <IStage> GetParentStageAsync() { var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id); if (stageCI == null) { ExecutionLog.Debug($"Missing data. No stage cache item for id={Id}."); return(null); } var parentStageId = await stageCI.GetParentStageAsync(Cultures).ConfigureAwait(false); if (parentStageId != null) { return(new Stage(parentStageId, GetSportAsync().Result.Id, _sportEntityFactory, SportEventCache, _sportDataCache, SportEventStatusCache, MatchStatusCache, Cultures, ExceptionStrategy)); } return(null); }
public async Task <ISportSummary> GetSportAsync() { var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id); if (stageCI == null) { ExecutionLog.Debug($"Missing data. No stage cache item for id={Id}."); return(null); } var sportId = await stageCI.GetSportIdAsync().ConfigureAwait(false); if (sportId == null) { ExecutionLog.Debug($"Missing data. No sportId for stage cache item with id={Id}."); return(null); } var sportCI = await _sportDataCache.GetSportAsync(sportId, Cultures).ConfigureAwait(false); return(sportCI == null ? null : new SportSummary(sportCI.Id, sportCI.Names)); }
/// <summary> /// Adds the sport event status to the internal cache /// </summary> /// <param name="eventId">The eventId of the sport event status to be cached</param> /// <param name="sportEventStatus">The sport event status to be cached</param> /// <param name="source">The source of the SES</param> private void AddSportEventStatus(URN eventId, SportEventStatusCI sportEventStatus, string source) { if (_isDisposed) { return; } lock (_lock) { if (string.IsNullOrEmpty(source) || source.Equals("OddsChange", StringComparison.InvariantCultureIgnoreCase) || source.Equals("SportEventSummary", StringComparison.InvariantCultureIgnoreCase) || !_sportEventStatusCache.Contains(eventId.ToString())) { if (!string.IsNullOrEmpty(source)) { source = $" from {source}"; } ExecutionLog.Debug( $"Received SES for {eventId}{source} with EventStatus:{sportEventStatus.Status}"); var cacheItem = _sportEventStatusCache.AddOrGetExisting(eventId.ToString(), sportEventStatus, new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(_cacheItemExpireTime.TotalSeconds) }) as SportEventStatusCI; if (cacheItem != null) { cacheItem.SetFeedStatus(sportEventStatus.FeedStatusDTO); cacheItem.SetSapiStatus(sportEventStatus.SapiStatusDTO); } } else { ExecutionLog.Debug( $"Received SES for {eventId} from {source} with EventStatus:{sportEventStatus.Status} (ignored)"); } } }
public async Task <ICategorySummary> GetCategoryAsync() { var stageCI = (StageCI)SportEventCache.GetEventCacheItem(Id); if (stageCI == null) { ExecutionLog.Debug($"Missing data. No stage cache item for id={Id}."); return(null); } var categoryId = await stageCI.GetCategoryIdAsync().ConfigureAwait(false); if (categoryId == null) { ExecutionLog.Debug($"Missing data. No categoryId for stage cache item with id={Id}."); return(null); } var categoryCI = await _sportDataCache.GetCategoryAsync(categoryId, Cultures).ConfigureAwait(false); return(categoryCI == null ? null : new CategorySummary(categoryCI.Id, categoryCI.Names, categoryCI.CountryCode)); }
/// <summary> /// Asynchronously gets a <see cref="PlayerProfileCI"/> representing the profile for the specified player /// </summary> /// <param name="playerId">A <see cref="URN"/> specifying the id of the player for which to get the profile</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying languages in which the information should be available</param> /// <returns>A <see cref="Task{PlayerProfileCI}"/> representing the asynchronous operation</returns> /// <exception cref="CacheItemNotFoundException">The requested item was not found in cache and could not be obtained from the API</exception> public async Task <PlayerProfileCI> GetPlayerProfileAsync(URN playerId, IEnumerable <CultureInfo> cultures) { Guard.Argument(playerId, nameof(playerId)).NotNull(); Guard.Argument(cultures, nameof(cultures)).NotNull().NotEmpty(); Metric.Context("CACHE").Meter("ProfileCache->GetPlayerProfileAsync", Unit.Calls); await _semaphorePlayer.WaitAsync().ConfigureAwait(false); PlayerProfileCI cachedItem; try { cachedItem = (PlayerProfileCI)_cache.Get(playerId.ToString()); var wantedCultures = cultures.ToList(); var missingLanguages = LanguageHelper.GetMissingCultures(wantedCultures, cachedItem?.Names.Keys).ToList(); if (!missingLanguages.Any()) { return(cachedItem); } // try to fetch for competitor, to avoid requests by each player if (cachedItem?.CompetitorId != null) { var competitorCI = (CompetitorCI)_cache.Get(cachedItem.CompetitorId.ToString()); if (competitorCI != null && (competitorCI.LastTimeCompetitorProfileFetched < DateTime.Now.AddSeconds(-30) || LanguageHelper.GetMissingCultures(wantedCultures, competitorCI.CultureCompetitorProfileFetched).Any())) { ExecutionLog.Debug($"Fetching competitor profile for competitor {competitorCI.Id} instead of player {cachedItem.Id} for languages=[{string.Join(",", missingLanguages.Select(s => s.TwoLetterISOLanguageName))}]."); try { await _semaphoreCompetitor.WaitAsync().ConfigureAwait(false); var cultureTasks = missingLanguages.ToDictionary(c => c, c => _dataRouterManager.GetCompetitorAsync(competitorCI.Id, c, null)); await Task.WhenAll(cultureTasks.Values).ConfigureAwait(false); } catch (Exception) { // ignored } finally { if (!_isDisposed) { _semaphoreCompetitor.Release(); } } cachedItem = (PlayerProfileCI)_cache.Get(playerId.ToString()); missingLanguages = LanguageHelper.GetMissingCultures(wantedCultures, cachedItem?.Names.Keys).ToList(); if (!missingLanguages.Any()) { return(cachedItem); } } } var cultureTaskDictionary = missingLanguages.ToDictionary(c => c, c => _dataRouterManager.GetPlayerProfileAsync(playerId, c, null)); await Task.WhenAll(cultureTaskDictionary.Values).ConfigureAwait(false); cachedItem = (PlayerProfileCI)_cache.Get(playerId.ToString()); } catch (Exception ex) { if (ex is DeserializationException || ex is MappingException) { throw new CacheItemNotFoundException($"An error occurred while fetching player profile for player {playerId} in cache", playerId.ToString(), ex); } throw; } finally { if (!_isDisposed) { _semaphorePlayer.Release(); } } return(cachedItem); }
private void AddSportEvent(URN id, SportEventSummaryDTO item, CultureInfo culture, ISportEventCI requester, DtoType dtoType) { TournamentInfoDTO tournamentInfoDTO = null; lock (_addLock) { try { var cacheItem = _sportEventCacheItemFactory.Get(Cache.Get(id.ToString())); if (requester != null && !Equals(requester, cacheItem) && id.Equals(requester.Id)) { try { var requesterMerged = false; var fixture = item as FixtureDTO; if (fixture != null) { if (requester.Id.TypeGroup == ResourceTypeGroup.MATCH) { ((MatchCI)requester).MergeFixture(fixture, culture, true); } else if (requester.Id.TypeGroup == ResourceTypeGroup.STAGE) { ((StageCI)requester).MergeFixture(fixture, culture, true); } else { ((TournamentInfoCI)requester).MergeFixture(fixture, culture, true); } requesterMerged = true; } if (!requesterMerged) { var match = item as MatchDTO; if (match != null) { ((MatchCI)requester).Merge(match, culture, true); requesterMerged = true; } } if (!requesterMerged) { var stage = item as StageDTO; if (stage != null) { ((StageCI)requester).Merge(stage, culture, true); requesterMerged = true; } } if (!requesterMerged) { var tour = item as TournamentInfoDTO; if (tour != null) { var stageCI = requester as StageCI; if (stageCI != null) { stageCI.Merge(tour, culture, true); requesterMerged = true; } else { var tourCI = requester as TournamentInfoCI; if (tourCI != null) { tourCI.Merge(tour, culture, true); requesterMerged = true; } } } } if (!requesterMerged) { var draw = item as DrawDTO; if (draw != null) { ((DrawCI)requester).Merge(draw, culture, true); requesterMerged = true; } } if (!requesterMerged) { var lottery = item as LotteryDTO; if (lottery != null) { ((LotteryCI)requester).Merge(lottery, culture, true); requesterMerged = true; } } if (!requesterMerged) { requester.Merge(item, culture, true); } } catch (Exception) { ExecutionLog.Debug($"Merging failed for {id} and item type: {item.GetType().Name} and dto type: {dtoType} for requester: {requester.Id}."); } } if (cacheItem != null) { //ExecutionLog.Debug($"Saving OLD data for {id} and item type: {item.GetType().Name} and dto type: {dtoType}."); var merged = false; //var cacheItem = _sportEventCacheItemFactory.Get(Cache.Get(id.ToString())); var fixture = item as FixtureDTO; if (fixture != null) { if (cacheItem.Id.TypeGroup == ResourceTypeGroup.MATCH) { ((MatchCI)cacheItem).MergeFixture(fixture, culture, true); } else if (cacheItem.Id.TypeGroup == ResourceTypeGroup.STAGE) { ((StageCI)cacheItem).MergeFixture(fixture, culture, true); } else { ((TournamentInfoCI)cacheItem).MergeFixture(fixture, culture, true); } if (fixture.Tournament != null) { tournamentInfoDTO = new TournamentInfoDTO(fixture.Tournament); } merged = true; } if (!merged) { var stage = item as StageDTO; if (stage != null) { ((StageCI)cacheItem).Merge(stage, culture, true); merged = true; if (stage.Tournament != null) { tournamentInfoDTO = new TournamentInfoDTO(stage.Tournament); } } } if (!merged) { var tour = item as TournamentInfoDTO; if (tour != null) { var stageCI = cacheItem as StageCI; if (stageCI != null) { stageCI.Merge(tour, culture, true); merged = true; } else { var tourCI = cacheItem as TournamentInfoCI; if (tourCI != null) { tourCI.Merge(tour, culture, true); merged = true; } } } } if (!merged) { var match = item as MatchDTO; if (match != null) { ((MatchCI)cacheItem).Merge(match, culture, true); merged = true; if (match.Tournament != null) { tournamentInfoDTO = new TournamentInfoDTO(match.Tournament); } } } if (!merged) { var draw = item as DrawDTO; if (draw != null) { ((DrawCI)cacheItem).Merge(draw, culture, true); merged = true; } } if (!merged) { var lottery = item as LotteryDTO; if (lottery != null) { ((LotteryCI)cacheItem).Merge(lottery, culture, true); merged = true; } } if (!merged) { cacheItem.Merge(item, culture, true); } } else { //ExecutionLog.Debug($"Saving NEW data for {id} and item type: {item.GetType().Name} and dto type: {dtoType}."); var ci = _sportEventCacheItemFactory.Build(item, culture); if (dtoType == DtoType.SportEventSummary || dtoType == DtoType.LotteryDraw || dtoType == DtoType.MatchSummary) { ci.LoadedSummaries.Add(culture); } else if (dtoType == DtoType.Fixture) { ci.LoadedFixtures.Add(culture); } AddNewCacheItem(ci); if (!ci.Id.Equals(id)) { var tInfo = item as TournamentInfoDTO; if (tInfo != null) { var newTournamentDto = new TournamentInfoDTO(tInfo, tInfo.Season != null, tInfo.CurrentSeason != null); var ci2 = _sportEventCacheItemFactory.Build(newTournamentDto, culture); AddNewCacheItem(ci2); } else { var ci2 = _sportEventCacheItemFactory.Build(item, culture); ci2.Id = id; AddNewCacheItem(ci2); } } } } catch (Exception ex) { ExecutionLog.Error($"Error adding sport event for id={id}, dto type={item?.GetType().Name} and lang={culture.TwoLetterISOLanguageName}.", ex); } } // if there are events for non-standard tournaments (tournaments not on All tournaments for all sports) // TODO: should we save/merge all, or just adding non-existing??? if (tournamentInfoDTO != null && (SpecialTournaments.Contains(tournamentInfoDTO.Id) || !Cache.Contains(tournamentInfoDTO.Id.ToString()))) { if (SpecialTournaments.Contains(tournamentInfoDTO.Id)) { //ExecutionLog.Debug($"Updating tournament id={tournamentInfoDTO.Id}, introduced by event id={id} and lang=[{culture.TwoLetterISOLanguageName}]."); } else { //ExecutionLog.Debug($"Saving tournament id={tournamentInfoDTO.Id}, introduced by event id={id} and lang=[{culture.TwoLetterISOLanguageName}]."); SpecialTournaments.Add(tournamentInfoDTO.Id); } AddSportEvent(tournamentInfoDTO.Id, tournamentInfoDTO, culture, null, dtoType); } }