/// <summary> /// Maps (converts) the provided <see cref="odds_change"/> instance to the <see cref="IOddsChange{T}"/> instance /// </summary> /// <param name="message">A <see cref="odds_change"/> instance to be mapped (converted)</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}" /> specifying the languages to which the mapped message will be translated</param> /// <param name="rawMessage">The raw message</param> /// <returns>A <see cref="IOddsChange{T}"/> instance constructed from information in the provided <see cref="odds_change"/></returns> public IOddsChange <T> MapOddsChange <T>(odds_change message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); var culturesList = cultures as List <CultureInfo> ?? cultures.ToList(); var markets = message.odds?.market?.Select(m => GetMarketWithOdds(GetEventForNameProvider <T>(message.EventURN, message.SportId, culturesList), m, message.ProducerId, message.SportId, culturesList)).ToList(); return(new OddsChange <T>(new MessageTimestamp(message.GeneratedAt, message.SentAt, message.ReceivedAt, SdkInfo.ToEpochTime(DateTime.Now)), _producerManager.Get(message.product), GetEventForMessage <T>(URN.Parse(message.event_id), message.SportId, culturesList), message.request_idSpecified ? (long?)message.request_id : null, MessageMapperHelper.GetEnumValue(message.odds_change_reasonSpecified, message.odds_change_reason, OddsChangeReason.NORMAL), message.odds != null && message.odds.betstop_reasonSpecified ? (int?)message.odds.betstop_reason : null, message.odds != null && message.odds.betting_statusSpecified ? (int?)message.odds.betting_status : null, markets, message.odds_generation_properties, _namedValuesProvider, rawMessage)); }
public IOddsChange <T> MapOddsChange <T>(odds_change message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Contract.Requires(message != null); Contract.Ensures(Contract.Result <IOddsChange <T> >() != null); return(Contract.Result <IOddsChange <T> >()); }
/// <summary> /// Initializes a new instance of the <see cref="OddsChangeEventArgs{T}"/> class /// </summary> /// <param name="messageMapper">A <see cref="IFeedMessageMapper"/> used to map feed message to the one dispatched to the user</param> /// <param name="feedMessage">A <see cref="odds_change"/> message received from the feed</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying the default languages to which the received message is translated</param> /// <param name="rawMessage">A raw message received from the feed</param> internal OddsChangeEventArgs(IFeedMessageMapper messageMapper, odds_change feedMessage, IEnumerable <CultureInfo> cultures, byte[] rawMessage) { Guard.Argument(messageMapper, nameof(messageMapper)).NotNull(); Guard.Argument(feedMessage, nameof(feedMessage)).NotNull(); Guard.Argument(cultures, nameof(cultures)).NotNull().NotEmpty(); _messageMapper = messageMapper; _feedMessage = feedMessage; _defaultCultures = cultures as IReadOnlyCollection <CultureInfo>; _rawMessage = rawMessage; }
public void Init() { InitSportEventCache(); _statusCache = new MemoryCache("eventsStatus"); _processor = new CacheMessageProcessor(_statusCache, new SportEventStatusMapperFactory(), _sportEventCache); var data = FileHelper.OpenFile(DirPath, InputXml); _record = Deserializer.Deserialize <odds_change>(data); _record.SportId = URN.Parse("sr:sport:1000"); }
/// <summary> /// Initializes a new instance of the <see cref="OddsChangeEventArgs{T}"/> class /// </summary> /// <param name="messageMapper">A <see cref="IFeedMessageMapper"/> used to map feed message to the one dispatched to the user</param> /// <param name="feedMessage">A <see cref="odds_change"/> message received from the feed</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying the default languages to which the received message is translated</param> /// <param name="rawMessage">A raw message received from the feed</param> internal OddsChangeEventArgs(IFeedMessageMapper messageMapper, odds_change feedMessage, IEnumerable <CultureInfo> cultures, byte[] rawMessage) { Contract.Requires(messageMapper != null); Contract.Requires(feedMessage != null); Contract.Requires(cultures != null && cultures.Any()); Contract.Ensures(_messageMapper != null); Contract.Ensures(_feedMessage != null); Contract.Ensures(_defaultCultures != null && _defaultCultures.Any()); _messageMapper = messageMapper; _feedMessage = feedMessage; _defaultCultures = cultures as IReadOnlyCollection <CultureInfo>; _rawMessage = rawMessage; }
/// <summary> /// Initializes a new instance of the <see cref="OddsChangeEventArgs{T}"/> class /// </summary> /// <param name="messageMapper">A <see cref="IFeedMessageMapper"/> used to map feed message to the one dispatched to the user</param> /// <param name="feedMessage">A <see cref="odds_change"/> message received from the feed</param> /// <param name="cultures">A <see cref="IEnumerable{CultureInfo}"/> specifying the default languages to which the received message is translated</param> /// <param name="rawMessage">A raw message received from the feed</param> internal OddsChangeEventArgs(IFeedMessageMapper messageMapper, odds_change feedMessage, IEnumerable <CultureInfo> cultures, byte[] rawMessage) { Guard.Argument(messageMapper, nameof(messageMapper)).NotNull(); Guard.Argument(feedMessage, nameof(feedMessage)).NotNull(); if (!cultures.Any()) { throw new ArgumentOutOfRangeException(nameof(cultures)); } _messageMapper = messageMapper; _feedMessage = feedMessage; _defaultCultures = cultures as IReadOnlyCollection <CultureInfo>; _rawMessage = rawMessage; _oddsChange = GetOddsChange(); }
private void TestEntityValues(IOddsChange <ICompetition> entity, odds_change record, AssertHelper assertHelper) { TestEventMessageProperties(assertHelper, entity, record.timestamp, record.product, record.event_id, record.RequestId); assertHelper.AreEqual(() => entity.ChangeReason, MessageMapperHelper.GetEnumValue <OddsChangeReason>(record.odds_change_reason)); if (record.odds.betstop_reasonSpecified) { assertHelper.AreEqual(() => entity.BetStopReason.Id, record.odds.betstop_reason); } else { assertHelper.IsNull(() => entity.BetStopReason); } if (record.odds.betting_statusSpecified) { assertHelper.AreEqual(() => entity.BettingStatus.Id, record.odds.betting_status); } else { assertHelper.IsNull(() => entity.BettingStatus); } if (record.odds?.market == null || record.odds.market.Length == 0) { Assert.IsNull(entity.Markets); } else { foreach (var marketRecord in record.odds.market) { var market = FindMarket(entity.Markets, marketRecord.id, marketRecord.specifiers); Assert.IsNotNull(market, $"Market with id={marketRecord.id} does not exist on mapped message"); TestMarketValues(market, marketRecord); } } }
/// <summary> /// Dispatches the <see cref="odds_change"/> message /// </summary> /// <param name="message">The <see cref="odds_change"/> message to dispatch</param> /// <param name="rawMessage">A raw message received from the feed</param> private void DispatchOddsChange(odds_change message, byte[] rawMessage) { var eventArgs = new OddsChangeEventArgs <T>(MessageMapper, message, DefaultCultures, rawMessage); Dispatch(OnOddsChange, eventArgs, message); }
private void OddsChange(odds_change e, dbEntities cnn, string routeKey) { using (var dbContextTransaction = cnn.Database.BeginTransaction()) { var spParams = string.Empty; var sectionName = string.Empty; try { var eventId = e.event_id.Split(':').Last(); var product = e.product; var generatedAt = e.timestamp; var clockStopped = 0; if (e.odds?.market != null) { sectionName = "odds_change"; var marketIdList = string.Empty; var specifierList = string.Empty; var statusList = string.Empty; var favoriteList = string.Empty; var outcomeIdList = string.Empty; var outcomeStatusList = string.Empty; var outcomeOddList = string.Empty; foreach (var market in e.odds.market) { var marketId = market.id; var specifier = market.specifiers?.Split('=').LastOrDefault()?.Trim(); var marketStatus = market.status; if (market.outcome != null) { foreach (var outcome in market.outcome) { sectionName = "odds_change.market.outcome"; marketIdList += marketId + ","; specifierList += specifier + ","; statusList += marketStatus + ","; favoriteList += market.favourite + ","; outcomeIdList += outcome.id.Split(':').LastOrDefault() + ","; outcomeStatusList += outcome.active + ","; outcomeOddList += outcome.odds.ToString(_nfi) + ","; marketId = 0; if (!string.IsNullOrEmpty(specifier)) { specifier = "*"; } } } else { marketIdList += market.id + ","; specifierList += specifier + ","; statusList += market.status + ","; favoriteList += market.favourite + ","; outcomeIdList += string.Empty + ","; outcomeStatusList += string.Empty + ","; outcomeOddList += string.Empty + ","; } } sectionName = "execute BETDATA_ODDSCHANGE"; spParams = "EXECUTE PROCEDURE BETDATA_ODDSCHANGE_MULTI("; spParams += SourceId + ","; spParams += eventId + ","; spParams += "'" + marketIdList.Substring(0).Trim() + "',"; spParams += "'" + specifierList.Substring(0).Trim() + "',"; spParams += "'" + statusList.Substring(0).Trim() + "',"; spParams += "'" + favoriteList.Substring(0).Trim() + "',"; spParams += "'" + outcomeIdList.Substring(0).Trim() + "',"; spParams += "'" + outcomeStatusList.Substring(0).Trim() + "',"; spParams += "'" + outcomeOddList.Substring(0).Trim() + "',"; spParams += generatedAt + ")"; cnn.Database.ExecuteSqlCommand(spParams.Trim()); } if (e.sport_event_status != null) { sectionName = "odds_change.sport_event_status"; var periodNumberList = string.Empty; var periodHomeScoreList = string.Empty; var periodAwayScoreList = string.Empty; var periodMatchStatusCodeList = string.Empty; if (e.sport_event_status?.period_scores != null) { if (e.sport_event_status.period_scores.Length > 0) { sectionName = "odds_change.sport_event_status.period_scores"; periodNumberList = e.sport_event_status.period_scores .Aggregate(string.Empty, (current, s) => current + "," + s.number).Substring(1) .Trim(); periodHomeScoreList = e.sport_event_status.period_scores .Aggregate(string.Empty, (current, s) => current + "," + s.home_score).Substring(1) .Trim(); periodAwayScoreList = e.sport_event_status.period_scores .Aggregate(string.Empty, (current, s) => current + "," + s.away_score).Substring(1) .Trim(); periodMatchStatusCodeList = e.sport_event_status.period_scores .Aggregate(string.Empty, (current, s) => current + "," + s.match_status_code) .Substring(1).Trim(); periodNumberList += ","; periodHomeScoreList += ","; periodAwayScoreList += ","; periodMatchStatusCodeList += ","; } } if (e.sport_event_status?.clock?.stopped != null) { clockStopped = e.sport_event_status.clock.stopped ? 1 : 0; } sectionName = "execute BET_EVENTDETAILS_UI"; spParams = "EXECUTE PROCEDURE BET_EVENTDETAILS_UI("; spParams += SourceId + ","; spParams += eventId + ","; spParams += product + ","; spParams += "'" + e.sport_event_status?.clock?.match_time + "',"; spParams += "'" + e.sport_event_status?.clock?.stoppage_time + "',"; spParams += "'" + e.sport_event_status?.clock?.stoppage_time_announced + "',"; spParams += "'" + e.sport_event_status?.clock?.remaining_time + "',"; spParams += "'" + e.sport_event_status?.clock?.remaining_time_in_period + "',"; spParams += clockStopped + ","; spParams += (e.sport_event_status?.statistics?.corners.home ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.corners.away ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.red_cards.home ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.red_cards.away ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.yellow_cards.home ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.yellow_cards.away ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.yellow_red_cards.home ?? 0) + ","; spParams += (e.sport_event_status?.statistics?.yellow_red_cards.away ?? 0) + ","; spParams += e.sport_event_status?.status + ","; spParams += e.sport_event_status?.home_score.ToString(_nfi) + ","; spParams += e.sport_event_status?.away_score.ToString(_nfi) + ","; spParams += e.sport_event_status?.match_status + ","; spParams += (e.odds?.betstop_reason ?? 0) + ","; spParams += (e.odds?.betting_status ?? 0) + ","; spParams += "'" + periodNumberList.Substring(0).Trim() + "',"; spParams += "'" + periodHomeScoreList.Substring(0).Trim() + "',"; spParams += "'" + periodAwayScoreList.Substring(0).Trim() + "',"; spParams += "'" + periodMatchStatusCodeList.Substring(0).Trim() + "',"; spParams += generatedAt + ")"; cnn.Database.ExecuteSqlCommand(spParams.Trim()); } dbContextTransaction.Commit(); SerilogHelper.Information($"{routeKey} {UtcHelper.GetDifferenceFromTimestamp(e.timestamp) + "ms"}"); } catch (Exception ex) { dbContextTransaction.Rollback(); SerilogHelper.Exception( $"Unknown exception in {routeKey} SectionName:{sectionName} SQL:{spParams.Trim()}", ex); } } }
/// <summary> /// Validates the provided <see cref="odds_change" /> message /// </summary> /// <param name="message">The <see cref="odds_change" /> message to validate</param> /// <returns>The <see cref="ValidationResult" /> specifying the result of validation</returns> protected ValidationResult ValidateOddsChange(odds_change message) { Contract.Requires(message != null); ValidateMessageProducer(message); if (!ValidateMessage(message)) { return(ValidationResult.FAILURE); } var result = ValidationResult.SUCCESS; if (message.odds_change_reasonSpecified && !MessageMapperHelper.IsEnumMember <OddsChangeReason>(message.odds_change_reason)) { LogWarning(message, "odds_change_reason", message.odds_change_reason); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds == null) { return(result); } if (message.odds.betstop_reasonSpecified && !_namedValuesProvider.BetStopReasons.IsValueDefined(message.odds.betstop_reason)) { LogWarning(message, "betstop_reason", message.odds.betstop_reason); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds.betting_statusSpecified && !_namedValuesProvider.BettingStatuses.IsValueDefined(message.odds.betting_status)) { LogWarning(message, "betting_status", message.odds.betting_status); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds.market == null || !message.odds.market.Any()) { return(result); } for (var marketIndex = 0; marketIndex < message.odds.market.Length; marketIndex++) { var market = message.odds.market[marketIndex]; if (market.statusSpecified && !MessageMapperHelper.IsEnumMember <MarketStatus>(market.status)) { LogFailure(message, $"market[{marketIndex}].market_status", market.status); return(ValidationResult.FAILURE); } //if (market.favouriteSpecified && market.favourite != 1) //{ // LogWarning(message, $"market[{marketIndex}].favourite", market.favourite); // result = ValidationResult.PROBLEMS_DETECTED; //} if (!ValidateSpecifiers(message, market, marketIndex)) { result = ValidationResult.PROBLEMS_DETECTED; } if (!CheckSpecifiersAsync(message.ProducerId, market.id, market.Specifiers).Result) { result = ValidationResult.PROBLEMS_DETECTED; } if (market.outcome == null || !market.outcome.Any()) { continue; } for (var outcomeIndex = 0; outcomeIndex < market.outcome.Length; outcomeIndex++) { var outcome = market.outcome[outcomeIndex]; result = ValidateOddsChangeOutcomes(message, market, outcome, result); } } return(result); }
/// <summary> /// Validates the provided <see cref="odds_change" /> message /// </summary> /// <param name="message">The <see cref="odds_change" /> message to validate</param> /// <returns>The <see cref="ValidationResult" /> specifying the result of validation</returns> protected ValidationResult ValidateOddsChange(odds_change message) { Guard.Argument(message, nameof(message)).NotNull(); ValidateMessageProducer(message); if (!ValidateMessage(message)) { return(ValidationResult.FAILURE); } var result = ValidationResult.SUCCESS; if (message.odds_change_reasonSpecified && !MessageMapperHelper.IsEnumMember <OddsChangeReason>(message.odds_change_reason)) { LogWarning(message, "odds_change_reason", message.odds_change_reason); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds == null) { return(result); } if (message.odds.betstop_reasonSpecified && !_namedValuesProvider.BetStopReasons.IsValueDefined(message.odds.betstop_reason)) { LogWarning(message, "betstop_reason", message.odds.betstop_reason); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds.betting_statusSpecified && !_namedValuesProvider.BettingStatuses.IsValueDefined(message.odds.betting_status)) { LogWarning(message, "betting_status", message.odds.betting_status); result = ValidationResult.PROBLEMS_DETECTED; } if (message.odds.market == null || !message.odds.market.Any()) { return(result); } foreach (var market in message.odds.market) { if (market.statusSpecified && !MessageMapperHelper.IsEnumMember <MarketStatus>(market.status)) { LogFailure(message, $"market {market.id} market_status", market.status); return(ValidationResult.FAILURE); } if (!ValidateSpecifiers(message, market, market.id)) { result = ValidationResult.PROBLEMS_DETECTED; } if (!CheckSpecifiersAsync(message.ProducerId, market.id, market.Specifiers).Result) { result = ValidationResult.PROBLEMS_DETECTED; } if (market.outcome == null || !market.outcome.Any()) { continue; } foreach (var outcome in market.outcome) { result = ValidateOddsChangeOutcomes(message, market, outcome, result); } } return(result); }