private IEnumerator DownloadSDK(SdkInfo info) { var path = Path.Combine(downloadDir, info.Filename); activity = string.Format("Downloading {0}...", info.Filename); Debug.Log(activity); // Start the async download job. downloader = new UnityWebRequest(info.Url) { downloadHandler = new DownloadHandlerFile(path), timeout = 60, // seconds }; downloader.SendWebRequest(); // Pause until download done/cancelled/fails, keeping progress bar up to date. while (!downloader.isDone) { yield return(null); var progress = Mathf.FloorToInt(downloader.downloadProgress * 100); if (EditorUtility.DisplayCancelableProgressBar("MoPub SDK Manager", activity, progress)) { downloader.Abort(); } } EditorUtility.ClearProgressBar(); if (string.IsNullOrEmpty(downloader.error)) { AssetDatabase.ImportPackage(path, true); // OK, got the file, so let the user import it if they want. } else { var error = downloader.error; if (downloader.isNetworkError) { if (error.EndsWith("destination host")) { error += ": " + info.Url; } } else if (downloader.isHttpError) { switch (downloader.responseCode) { case 404: var file = Path.GetFileName(new Uri(info.Url).LocalPath); error = string.Format("File {0} not found on server.", file); break; default: error = downloader.responseCode + "\n" + error; break; } } Debug.LogError(error); } // Reset async state so the GUI is operational again. downloader.Dispose(); downloader = null; coroutine = null; }
private IEnumerator GetSDKVersions() { // Wait one frame so that we don't try to show the progress bar in the middle of OnGUI(). yield return(null); activity = "Downloading SDK version manifest..."; UnityWebRequest www = new UnityWebRequest(staging ? stagingURL : manifestURL) { downloadHandler = new DownloadHandlerBuffer(), timeout = 10, // seconds }; yield return(www.SendWebRequest()); if (!string.IsNullOrEmpty(www.error)) { Debug.LogError(www.error); EditorUtility.DisplayDialog( "SDK Manager Service", "The services we need are not accessible. Please consider integrating manually.\n\n" + "For instructions, see " + helpLink, "OK"); } var json = www.downloadHandler.text; if (string.IsNullOrEmpty(json)) { json = "{}"; Debug.LogError("Unable to retrieve SDK version manifest. Showing installed SDKs only."); } www.Dispose(); // Got the file. Now extract info on latest SDKs available. mopubSdkInfo = new SdkInfo(); sdkInfo.Clear(); var dict = MJ.Json.Deserialize(json) as Dictionary <string, object>; if (dict != null) { object obj; if (dict.TryGetValue("mopubBaseConfig", out obj)) { mopubSdkInfo.FromJson("Unity SDK", obj as Dictionary <string, object>); mopubSdkInfo.CurrentVersion = MoPub.MoPubSdkVersion; } if (dict.TryGetValue("releaseInfo", out obj)) { foreach (var item in obj as Dictionary <string, object> ) { var info = new SdkInfo(); if (info.FromJson(item.Key, item.Value as Dictionary <string, object>)) { sdkInfo[info.Key] = info; } } } } // Figure out what versions of SDKs are currently installed. var baseType = typeof(PackageConfig); var configs = from t in Assembly.GetExecutingAssembly().GetTypes() where t.IsSubclassOf(baseType) && !t.IsAbstract select Activator.CreateInstance(t) as PackageConfig; foreach (var config in configs) { SdkInfo info; sdkInfo.TryGetValue(config.Name, out info); if (info.FromConfig(config)) { sdkInfo[info.Key] = info; } } // Clear up the async-job state. coroutine = null; Repaint(); }
private void SdkRow(SdkInfo info, Func <bool, bool> customButton = null) { var lat = info.LatestVersion; var cur = info.CurrentVersion; var isInst = !string.IsNullOrEmpty(cur); var canInst = !string.IsNullOrEmpty(lat) && (!isInst || MoPubUtils.CompareVersions(cur, lat) < 0); // Is any async job in progress? var stillWorking = coroutine != null || downloader != null; var tooltip = string.Empty; if (info.NetworkVersions != null) { string version; if (info.NetworkVersions.TryGetValue(PackageConfig.Platform.ANDROID, out version)) { tooltip += "\n Android SDK: " + version; } if (info.NetworkVersions.TryGetValue(PackageConfig.Platform.IOS, out version)) { tooltip += "\n iOS SDK: " + version; } } tooltip += "\n Installed: " + (cur ?? "n/a"); tooltip = info.Name + "\n Package: " + (lat ?? "n/a") + tooltip; GUILayout.Space(4); using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false))) { GUILayout.Space(10); EditorGUILayout.LabelField(new GUIContent { text = info.Name, tooltip = tooltip }); GUILayout.Button(new GUIContent { text = lat ?? "--", tooltip = tooltip }, canInst ? EditorStyles.boldLabel : EditorStyles.label); GUILayout.Space(3); if (customButton == null || !customButton(canInst)) { GUI.enabled = !stillWorking && (canInst || testing); if (GUILayout.Button(new GUIContent { text = isInst ? "Upgrade" : "Install", tooltip = tooltip }, fieldWidth)) { this.StartCoroutine(DownloadSDK(info)); } GUI.enabled = true; } if (!string.IsNullOrEmpty(info.Instructions) && (info.Instructions != helpLink || testing)) { if (GUILayout.Button("?", GUILayout.ExpandWidth(false))) { Application.OpenURL(info.Instructions); } } else { // Need to fill space so that the Install/Upgrade buttons all line up nicely. GUILayout.Button(" ", EditorStyles.label, GUILayout.Width(17)); } GUILayout.Space(5); } GUILayout.Space(4); }
/// <summary> /// Maps (converts) the provided <see cref="bet_cancel"/> instance to the <see cref="IBetCancel{T}"/> instance /// </summary> /// <param name="message">A <see cref="bet_cancel"/> 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="IBetCancel{T}"/> instance constructed from information in the provided <see cref="bet_cancel"/></returns> public IBetCancel <T> MapBetCancel <T>(bet_cancel message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); var culturesList = cultures as List <CultureInfo> ?? cultures.ToList(); return(new BetCancel <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, message.start_timeSpecified ? (long?)message.start_time : null, message.end_timeSpecified ? (long?)message.end_time : null, string.IsNullOrEmpty(message.superceded_by) ? null : URN.Parse(message.superceded_by), message.market.Select(m => GetMarketCancel(GetEventForNameProvider <T>(URN.Parse(message.event_id), message.SportId, culturesList), m, message.ProducerId, message.SportId, culturesList)), rawMessage)); }
private void Compare(PlayerProfileCI playerCI, playerExtended player, CultureInfo culture) { Assert.IsNotNull(playerCI); Assert.IsNotNull(player); Assert.AreEqual(player.id, playerCI.Id.ToString()); Assert.AreEqual(_competitorId, playerCI.CompetitorId); if (player.type == null) { Assert.IsNull(playerCI.Type); } else { Assert.AreEqual(player.type, playerCI.Type); } if (player.country_code == null) { Assert.IsNull(playerCI.CountryCode); } else { Assert.AreEqual(player.country_code, playerCI.CountryCode); } if (player.date_of_birth == null) { Assert.IsNull(playerCI.DateOfBirth); } else { Assert.AreEqual(player.date_of_birth, playerCI.DateOfBirth.Value.ToString("yyyy-MM-dd")); } if (player.full_name == null) { Assert.IsNull(playerCI.FullName); } else { Assert.AreEqual(player.full_name, playerCI.FullName); } if (player.gender == null) { Assert.IsNull(playerCI.Gender); } else { Assert.AreEqual(player.gender, playerCI.Gender); } if (!player.heightSpecified) { Assert.IsNull(playerCI.Height); } else { Assert.IsTrue(player.height > 0); Assert.AreEqual(player.height, playerCI.Height); } if (!player.weightSpecified) { Assert.IsNull(playerCI.Weight); } else { Assert.IsTrue(player.weight > 0); Assert.AreEqual(player.weight, playerCI.Weight); } if (player.type == null) { Assert.IsNull(playerCI.Type); } else { Assert.AreEqual(player.type, playerCI.Type); } //if (!player.jersey_numberSpecified) //{ // Assert.IsNull(playerCI.); //} //else //{ // Assert.IsTrue(player.height > 0); // Assert.AreEqual(player.height, playerCI.Height); //} if (player.name == null) { Assert.IsNull(playerCI.GetName(culture)); } else { Assert.AreEqual(player.name, playerCI.GetName(culture)); } if (player.nationality == null) { Assert.IsNull(playerCI.GetNationality(culture)); } else { Assert.AreEqual(player.nationality, playerCI.GetNationality(culture)); } if (player.nickname == null) { Assert.IsNull(playerCI.Nickname); } else { Assert.AreEqual(player.nickname, playerCI.Nickname); } if (player.name == null) { Assert.IsNull(playerCI.Abbreviation); } else { Assert.AreEqual(SdkInfo.GetAbbreviationFromName(player.name), playerCI.Abbreviation); } }
/// <summary> /// Maps (converts) the provided <see cref="alive"/> instance to the <see cref="IAlive"/> instance /// </summary> /// <param name="message">A <see cref="alive"/> instance to be mapped (converted)</param> /// <returns>A <see cref="IAlive"/> instance constructed from information in the provided <see cref="alive"/></returns> public IAlive MapAlive(alive message) { Guard.Argument(message, nameof(message)).NotNull(); return(new Alive(new MessageTimestamp(message.GeneratedAt, message.SentAt, message.ReceivedAt, SdkInfo.ToEpochTime(DateTime.Now)), _producerManager.Get(message.product), message.subscribed != 0)); }
/// <summary> /// Maps (converts) the provided <see cref="fixture_change" /> instance to the <see cref="IFixtureChange{T}" /> instance /// </summary> /// <param name="message">A <see cref="fixture_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="IFixtureChange{T}" /> instance constructed from information in the provided <see cref="fixture_change" /></returns> public IFixtureChange <T> MapFixtureChange <T>(fixture_change message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); return(new FixtureChange <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, cultures), message.request_idSpecified ? (long?)message.request_id : null, MessageMapperHelper.GetEnumValue(message.change_typeSpecified, message.change_type, FixtureChangeType.OTHER), message.next_live_timeSpecified ? (long?)message.next_live_time : null, message.start_time, rawMessage)); }
/// <summary> /// Maps (converts) the provided <see cref="cashout" /> instance to the <see cref="ICashOutProbabilities{T}" /> instance /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message">A <see cref="cashout" /> 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="ICashOutProbabilities{T}" /> instance constructed from information in the provided <see cref="cashout" /></returns> public ICashOutProbabilities <T> MapCashOutProbabilities <T>(cashout message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); var culturesList = cultures as List <CultureInfo> ?? cultures.ToList(); var eventId = URN.Parse(message.event_id); var sportId = URN.Parse("sr:sport:1"); return(new CashOutProbabilities <T>(new MessageTimestamp(message.GeneratedAt, message.SentAt, message.ReceivedAt, SdkInfo.ToEpochTime(DateTime.Now)), _producerManager.Get(message.product), GetEventForMessage <T>(eventId, sportId, culturesList), 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, message.odds?.market?.Select(m => GetMarketWithProbabilities(GetEventForNameProvider <T>(eventId, sportId, culturesList), m, message.product, sportId, culturesList)).ToList(), _namedValuesProvider, rawMessage)); }
/// <summary> /// Handles the message received event /// </summary> /// <param name="sender">The <see cref="object"/> representation of the event sender</param> /// <param name="eventArgs">A <see cref="BasicDeliverEventArgs"/> containing event information</param> private void consumer_OnReceived(object sender, BasicDeliverEventArgs eventArgs) { if (eventArgs.Body == null || !eventArgs.Body.Any()) { ExecutionLog.WarnFormat("A message with {0} body received. Aborting message processing", eventArgs.Body == null ? "null" : "empty"); return; } var receivedAt = SdkInfo.ToEpochTime(DateTime.Now); // NOT used for GetRawMessage() var sessionName = _interest == null ? "system" : _interest.Name; string messageBody = null; FeedMessage feedMessage; IProducer producer; string messageName; try { using (var t = Metric.Context("FEED") .Timer("Message deserialization time", Unit.Items, SamplingType.Default, TimeUnit.Minutes) .NewContext(eventArgs.RoutingKey)) { messageBody = Encoding.UTF8.GetString(eventArgs.Body); feedMessage = _deserializer.Deserialize(new MemoryStream(eventArgs.Body)); producer = _producerManager.Get(feedMessage.ProducerId); messageName = feedMessage.GetType().Name; if (!string.IsNullOrEmpty(feedMessage.EventId) && URN.TryParse(feedMessage.EventId, out URN eventUrn)) { feedMessage.EventURN = eventUrn; } if (_keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out var sportId)) { feedMessage.SportId = sportId; } if (t.Elapsed.TotalMilliseconds > 300) { var marketCounts = 0; var outcomeCounts = 0; if (feedMessage is odds_change oddsChange) { marketCounts = oddsChange.odds?.market?.Length ?? 0; outcomeCounts = oddsChange.odds?.market?.Where(w => w.outcome != null).SelectMany(list => list.outcome).Count() ?? 0; } if (feedMessage is bet_settlement betSettlement) { marketCounts = betSettlement.outcomes?.Length ?? 0; outcomeCounts = betSettlement.outcomes?.Where(w => w.Items != null).SelectMany(list => list.Items).Count() ?? 0; } ExecutionLog.Debug( $"Deserialization of {feedMessage.GetType().Name} for {feedMessage.EventId} ({feedMessage.GeneratedAt}) and sport {sportId} took {t.Elapsed.TotalMilliseconds}ms. Markets={marketCounts}, Outcomes={outcomeCounts}"); } } if (producer.IsAvailable && !producer.IsDisabled) { FeedLog.Info($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {messageBody}"); } else { if (FeedLog.IsDebugEnabled) { FeedLog.Debug($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {producer.Id}"); } } if (eventArgs.BasicProperties?.Headers != null) { feedMessage.SentAt = eventArgs.BasicProperties.Headers.ContainsKey("timestamp_in_ms") ? long.Parse(eventArgs.BasicProperties.Headers["timestamp_in_ms"].ToString()) : feedMessage.GeneratedAt; } feedMessage.ReceivedAt = receivedAt; Metric.Context("FEED").Meter("Message received", Unit.Items).Mark(messageName); } catch (DeserializationException ex) { ExecutionLog.Error($"Failed to parse message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); Metric.Context("FEED").Meter("Message deserialization exception", Unit.Items).Mark(); RaiseDeserializationFailed(eventArgs.Body); return; } catch (Exception ex) { ExecutionLog.Error($"Error consuming feed message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); Metric.Context("FEED").Meter("Exception consuming feed message", Unit.Items).Mark(eventArgs.RoutingKey); RaiseDeserializationFailed(eventArgs.Body); return; } // send RawFeedMessage if needed try { if (producer.IsAvailable && !producer.IsDisabled) { //ExecutionLog.LogDebug($"Raw msg [{_interest}]: {feedMessage.GetType().Name} for event {feedMessage.EventId}."); var args = new RawFeedMessageEventArgs(eventArgs.RoutingKey, feedMessage, sessionName); RawFeedMessageReceived?.Invoke(this, args); } } catch (Exception e) { ExecutionLog.Error($"Error dispatching raw message for {feedMessage.EventId}", e); } // continue normal processing if (!_producerManager.Exists(feedMessage.ProducerId)) { ExecutionLog.Warn($"A message for producer which is not defined was received. Producer={feedMessage.ProducerId}"); return; } if (!_useReplay && (!producer.IsAvailable || producer.IsDisabled)) { ExecutionLog.Debug($"A message for producer which is disabled was received. Producer={producer}, MessageType={messageName}"); return; } ExecutionLog.Info($"Message received. Message=[{feedMessage}]."); if (feedMessage.IsEventRelated) { if (!string.IsNullOrEmpty(eventArgs.RoutingKey) && _keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out var sportId)) { feedMessage.SportId = sportId; } else { ExecutionLog.Warn($"Failed to parse the SportId from the routing key. RoutingKey={eventArgs.RoutingKey}, message=[{feedMessage}]. SportId will not be set."); } } RaiseMessageReceived(feedMessage, eventArgs.Body); }
private IEnumerable <IMarketMappingData> GetMarketMapping(IMarketDescription marketDescription) { if (marketDescription == null) { return(new List <IMarketMappingData>()); } if (marketDescription.Mappings == null || !marketDescription.Mappings.Any()) { ExecutionLog.LogDebug($"An error occurred getting mapped marketId for marketId={_marketId} (no mappings exist)."); return(new List <IMarketMappingData>()); } var mappings = marketDescription.Mappings.Where(m => m.CanMap(_producer, _sportId, _specifiers)).ToList(); if (!mappings.Any()) { ExecutionLog.LogDebug($"Market with id:{_marketId}, producer:{_producer}, sportId:{_sportId} has no mappings."); return(mappings); } if (mappings.Count > 1) { foreach (var mapping in mappings) { if (mapping.MarketId.Equals(marketDescription.Id.ToString())) { return(new[] { mapping }); } } ExecutionLog.LogWarning($"Market with id:{_marketId}, producer:{_producer.Id}, sportId:{_sportId.Id} has too many mappings [{mappings.Count}]."); CacheLog.LogWarning($"MarketId:{_marketId}, producer:{_producer.Id}, sportId:{_sportId.Id}, specifiers={SdkInfo.SpecifiersKeysToString(marketDescription.Specifiers)} has too many mappings [{mappings.Count}]."); var i = 0; foreach (var mapping in mappings) { CacheLog.LogDebug($"MarketId:{_marketId}, producer:{_producer.Id}, sportId:{_sportId.Id} mapping[{i}]: {mapping}."); i++; } } return(mappings); }
/// <inheritdoc /> public override string ToString() { return($"After={After}/{SdkInfo.FromEpochTime(After)}, NodeId={NodeId}, Timestamp={Timestamp}/{SdkInfo.FromEpochTime(Timestamp)}, RequestId={RequestId}, Response={ResponseCode}-{ResponseMessage}"); }
private async Task <(string path, SdkInfo)> GetSDKForBinary(OpenJDKRelease release, OpenJDKBinary binary) { if ( release.release_name == null || release.release_link == null || binary.os == null || binary.architecture == null || binary.binary_name == null || binary.binary_link == null || binary.checksum_link == null || binary.version_data == null || binary.version_data.openjdk_version == null || binary.version_data.semver == null ) { throw new ArgumentException("Property is null"); } Console.WriteLine($"Creating SDK for binary {binary.binary_name}"); var shaFileContent = await HttpUtil.FetchString(binary.checksum_link); var sha256 = HashUtil.ParseSha256(shaFileContent) ?? throw new Exception($"Invalid SHA256 from {binary.checksum_link}."); var os = SdkHelper.ParseOperatingSystem(binary.os); var arch = SdkHelper.ParseArch(binary.architecture); var zipDirName = binary.version == "10" ? release.release_name.Replace(binary.version_data.openjdk_version, binary.version_data.semver) : release.release_name; var sdkInfo = new SdkInfo( implements: new[] { "jdk" }, version: binary.version_data.semver, platforms: new[] { new PlatformInfo(os, arch) }, setupSteps: new SdkSetupStep[] { new SdkSetupStep.Download(binary.binary_link, binary.binary_name, new SdkHash(SdkHashType.Sha256, sha256)), new SdkSetupStep.Extract(binary.binary_name, "."), new SdkSetupStep.Delete(binary.binary_name), }, pathDirs: new[] { zipDirName + "/bin" }, env: new Dictionary <string, EnvValue> { { "JAVA_HOME", new EnvValue.Concat( new EnvValue[] { new EnvValue.BuiltInValue(EnvValue.BuiltInValue.SdkDirectory), new EnvValue.OfString("/" + zipDirName), } ) }, } ); var noExtFile = Path.GetFileNameWithoutExtension(binary.binary_name); if (noExtFile.EndsWith(".tar")) { noExtFile = Path.GetFileNameWithoutExtension(noExtFile); } return($"jdk/jdk{binary.version}/{noExtFile}.json", sdkInfo); }
private void ChannelOnModelShutdown(object sender, ShutdownEventArgs shutdownEventArgs) { var reason = _channel.CloseReason == null ? string.Empty : SdkInfo.ClearSensitiveData(_channel.CloseReason.ToString(), _accessToken); ExecutionLog.Info($"The channel with channelNumber {_channel.ChannelNumber} is shutdown. Reason={reason}"); }
private void ConsumerOnShutdown(object sender, ShutdownEventArgs shutdownEventArgs) { var reason = _consumer.ShutdownReason == null ? string.Empty : SdkInfo.ClearSensitiveData(_consumer.ShutdownReason.ToString(), _accessToken); ExecutionLog.Info($"The consumer {_consumer.ConsumerTag} is shutdown. Reason={reason}"); }
/// <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)); }
/// <summary> /// Merges the information from the provided <see cref="CompetitorProfileDTO"/> into the current instance /// </summary> /// <param name="competitorProfile">A <see cref="CompetitorProfileDTO"/> containing information about the competitor</param> /// <param name="culture">A <see cref="CultureInfo"/> specifying the language of the passed <code>dto</code></param> internal void Merge(CompetitorProfileDTO competitorProfile, CultureInfo culture) { Guard.Argument(competitorProfile, nameof(competitorProfile)).NotNull(); Guard.Argument(competitorProfile.Competitor, nameof(competitorProfile.Competitor)).NotNull(); _isVirtual = competitorProfile.Competitor.IsVirtual; Names[culture] = competitorProfile.Competitor.Name; _countryNames[culture] = competitorProfile.Competitor.CountryName; _abbreviations[culture] = string.IsNullOrEmpty(competitorProfile.Competitor.Abbreviation) ? SdkInfo.GetAbbreviationFromName(competitorProfile.Competitor.Name) : competitorProfile.Competitor.Abbreviation; _referenceId = UpdateReferenceIds(competitorProfile.Competitor.Id, competitorProfile.Competitor.ReferenceIds); if (!string.IsNullOrEmpty(competitorProfile.Competitor.CountryCode)) { _countryCode = competitorProfile.Competitor.CountryCode; } if (!string.IsNullOrEmpty(competitorProfile.Competitor.State)) { _state = competitorProfile.Competitor.State; } if (!competitorProfile.Players.IsNullOrEmpty()) { _associatedPlayerIds = competitorProfile.Players.Select(s => s.Id).ToList(); } if (!competitorProfile.Jerseys.IsNullOrEmpty()) { _jerseys = competitorProfile.Jerseys.Select(s => new JerseyCI(s)).ToList(); } if (competitorProfile.Manager != null) { if (_manager == null) { _manager = new ManagerCI(competitorProfile.Manager, culture); } else { _manager.Merge(competitorProfile.Manager, culture); } } if (competitorProfile.Venue != null) { if (_venue == null) { _venue = new VenueCI(competitorProfile.Venue, culture); } else { _venue.Merge(competitorProfile.Venue, culture); } } if (!string.IsNullOrEmpty(competitorProfile.Competitor.Gender)) { _gender = competitorProfile.Competitor.Gender; } if (!string.IsNullOrEmpty(competitorProfile.Competitor.AgeGroup)) { _ageGroup = competitorProfile.Competitor.AgeGroup; } if (competitorProfile.RaceDriverProfile != null) { _raceDriverProfile = new RaceDriverProfileCI(competitorProfile.RaceDriverProfile); } if (competitorProfile.Competitor.SportId != null) { _sportId = competitorProfile.Competitor.SportId; } if (competitorProfile.Competitor.CategoryId != null) { _categoryId = competitorProfile.Competitor.CategoryId; } if (!string.IsNullOrEmpty(competitorProfile.Competitor.ShortName)) { _shortName = competitorProfile.Competitor.ShortName; } _lastTimeCompetitorProfileFetched = DateTime.Now; _cultureCompetitorProfileFetched.Add(culture); _fetchedCultures.Add(culture); }
private PlatformSdk(List <string> realUrls, SdkInfo sdk) { this.realUrls = realUrls; this.sdk = sdk; }
/// <summary> /// Handles the message received event /// </summary> /// <param name="sender">The <see cref="object"/> representation of the event sender</param> /// <param name="eventArgs">A <see cref="BasicDeliverEventArgs"/> containing event information</param> private void consumer_OnReceived(object sender, BasicDeliverEventArgs eventArgs) { if (eventArgs.Body == null || !eventArgs.Body.Any()) { ExecutionLog.WarnFormat("A message with {0} body received. Aborting message processing", eventArgs.Body == null ? "null" : "empty"); return; } var receivedAt = SdkInfo.ToEpochTime(DateTime.Now); // NOT used for GetRawMessage() var sessionName = _interest == null ? "system" : _interest.Name; string messageBody = null; FeedMessage feedMessage; IProducer producer; string messageName; try { messageBody = Encoding.UTF8.GetString(eventArgs.Body); feedMessage = _deserializer.Deserialize(new MemoryStream(eventArgs.Body)); producer = _producerManager.Get(feedMessage.ProducerId); messageName = feedMessage.GetType().Name; if (producer.IsAvailable && !producer.IsDisabled) { FeedLog.Info($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {messageBody}"); } else { if (FeedLog.IsDebugEnabled) { FeedLog.Debug($"<~> {sessionName} <~> {eventArgs.RoutingKey} <~> {producer.Id}"); } } if (eventArgs.BasicProperties?.Headers != null) { feedMessage.SentAt = eventArgs.BasicProperties.Headers.ContainsKey("timestamp_in_ms") ? long.Parse(eventArgs.BasicProperties.Headers["timestamp_in_ms"].ToString()) : feedMessage.GeneratedAt; } feedMessage.ReceivedAt = receivedAt; Metric.Context("RABBIT").Meter("RabbitMqMessageReceiver", Unit.Items).Mark(messageName); } catch (DeserializationException ex) { ExecutionLog.Error($"Failed to parse message. RoutingKey={eventArgs.RoutingKey} Message: {messageBody}", ex); Metric.Context("RABBIT").Meter("RabbitMqMessageReceiver->DeserializationException", Unit.Calls).Mark(); RaiseDeserializationFailed(eventArgs.Body); return; } // send RawFeedMessage if needed try { if (producer.IsAvailable && !producer.IsDisabled) { //ExecutionLog.LogDebug($"Raw msg [{_interest}]: {feedMessage.GetType().Name} for event {feedMessage.EventId}."); var args = new RawFeedMessageEventArgs(eventArgs.RoutingKey, feedMessage, sessionName); RawFeedMessageReceived?.Invoke(this, args); } } catch (Exception e) { ExecutionLog.Error($"Error dispatching raw message for {feedMessage.EventId}", e); } // continue normal processing if (!_producerManager.Exists(feedMessage.ProducerId)) { ExecutionLog.Warn($"A message for producer which is not defined was received. Producer={feedMessage.ProducerId}"); return; } if (!_useReplay && (!producer.IsAvailable || producer.IsDisabled)) { ExecutionLog.Debug($"A message for producer which is disabled was received. Producer={producer}, MessageType={messageName}"); return; } ExecutionLog.Info($"Message received. Message=[{feedMessage}]."); if (feedMessage.IsEventRelated) { URN sportId; if (!string.IsNullOrEmpty(eventArgs.RoutingKey) && _keyParser.TryGetSportId(eventArgs.RoutingKey, messageName, out sportId)) { feedMessage.SportId = sportId; } else { ExecutionLog.Warn($"Failed to parse the SportId from the routing key. RoutingKey={eventArgs.RoutingKey}, message=[{feedMessage}]. SportId will not be set."); } } RaiseMessageReceived(feedMessage, eventArgs.Body); }
/// <summary> /// Maps (converts) the provided <see cref="snapshot_complete"/> instance to the <see cref="ISnapshotCompleted"/> instance /// </summary> /// <param name="message">A <see cref="snapshot_complete"/> instance to be mapped (converted)</param> /// <returns>A <see cref="ISnapshotCompleted"/> instance constructed from information in the provided <see cref="snapshot_complete"/></returns> public ISnapshotCompleted MapSnapShotCompleted(snapshot_complete message) { Guard.Argument(message, nameof(message)).NotNull(); return(new SnapshotCompleted(new MessageTimestamp(message.GeneratedAt, message.SentAt, message.ReceivedAt, SdkInfo.ToEpochTime(DateTime.Now)), _producerManager.Get(message.product), message.request_id)); }
/// <summary> /// Processes a message received on the system's session /// </summary> /// <remarks> /// This method does: /// - starts recovery operations if needed /// - interrupt running recoveries on non-subscribed alive(s) and alive violation(s) /// - set LastTimestampBeforeDisconnect property on the producer. /// This method does not: /// - determine if the user is behind (or not) with message processing - this is done in CheckStatus(..) method /// - attempt to determine whether the recovery has timed-out - this is done in CheckStatus(..) method /// </remarks> /// <param name="message">A <see cref="FeedMessage"/> received on the system session</param> public void ProcessSystemMessage(FeedMessage message) { Guard.Argument(message, nameof(message)).NotNull(); var alive = message as alive; if (alive?.ProducerId != Producer.Id) { return; } var newStatus = Status; if (Status == ProducerRecoveryStatus.FatalError || _producer.IgnoreRecovery) { return; } lock (_syncLock) { try { // store the timestamp of most recent system alive before it is overridden by // _timestampTracker.ProcessSystemAlive(alive); in case the current alive // is not subscribed and ongoing recovery operation must be interrupted var previousAliveTimestamp = _timestampTracker.SystemAliveTimestamp; _timestampTracker.ProcessSystemAlive(alive); _producer.SetTimeOfLastAlive(TimeProviderAccessor.Current.Now); // if current status is NotStarted or Error just start the recovery if (Status == ProducerRecoveryStatus.NotStarted || Status == ProducerRecoveryStatus.Error) { try { if (_recoveryOperation.Start()) { ExecutionLog.Info($"Producer={_producer.Id}: Recovery operation started. Current status={Enum.GetName(typeof(ProducerRecoveryStatus), Status)}, After={SdkInfo.ToEpochTime(_producer.LastTimestampBeforeDisconnect)}."); newStatus = ProducerRecoveryStatus.Started; } else { ExecutionLog.Warn($"Producer={_producer.Id}: An error occurred while starting recovery operation with after={SdkInfo.ToEpochTime(_producer.LastTimestampBeforeDisconnect)}. Retry will be made at next system alive."); } } catch (RecoveryInitiationException ex) { ExecutionLog.Fatal($"Producer id={Producer.Id} failed to execute recovery because 'after' is to much in the past. After={ex.After}. Stopping the feed."); newStatus = ProducerRecoveryStatus.FatalError; } } else { Debug.Assert(Status == ProducerRecoveryStatus.Started || Status == ProducerRecoveryStatus.Completed || Status == ProducerRecoveryStatus.Delayed); // we are no longer in sync with the feed if (alive.subscribed == 0) { if (_recoveryOperation.IsRunning) { Debug.Assert(Status == ProducerRecoveryStatus.Started); var timestamp = SdkInfo.FromEpochTime(previousAliveTimestamp); ExecutionLog.Info($"Producer={_producer.Id}: Recovery operation interrupted. Current status={Enum.GetName(typeof(ProducerRecoveryStatus), Status)}, Timestamp={timestamp}."); _recoveryOperation.Interrupt(timestamp); } else { Debug.Assert(Status == ProducerRecoveryStatus.Completed || Status == ProducerRecoveryStatus.Delayed); try { if (_recoveryOperation.Start()) { ExecutionLog.Info($"Producer={_producer.Id}: Recovery operation started due to un-subscribed alive. Current status={Enum.GetName(typeof(ProducerRecoveryStatus), Status)}, After={SdkInfo.ToEpochTime(_producer.LastTimestampBeforeDisconnect)}."); newStatus = ProducerRecoveryStatus.Started; } else { ExecutionLog.Warn($"Producer={_producer.Id}: An error occurred while starting recovery operation with after={SdkInfo.ToEpochTime(_producer.LastTimestampBeforeDisconnect)}. Retry will be made at next system alive."); newStatus = ProducerRecoveryStatus.Error; } } catch (RecoveryInitiationException ex) { ExecutionLog.Fatal($"Producer id={Producer.Id} failed to execute recovery because 'after' is to much in the past. After={ex.After}. Stopping the feed."); newStatus = ProducerRecoveryStatus.FatalError; } } } } } catch (Exception ex) { ExecutionLog.Error($"An unexpected exception occurred while processing system message. Producer={_producer.Id}, message={message}. Exception:", ex); } if (newStatus != Status) { SetStatusAndRaiseEvent(null, newStatus); } } }
/// <summary> /// Maps (converts) the provided <see cref="bet_stop" /> instance to the <see cref="IBetStop{T}" /> instance /// </summary> /// <typeparam name="T"></typeparam> /// <param name="message">A <see cref="bet_stop" /> 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="IBetStop{T}" /> instance constructed from information in the provided <see cref="bet_stop" /></returns> public IBetStop <T> MapBetStop <T>(bet_stop message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); return(new BetStop <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, cultures), message.request_idSpecified ? (long?)message.request_id : null, MessageMapperHelper.GetEnumValue(message.market_statusSpecified, message.market_status, MarketStatus.SUSPENDED), message.groups?.Split('|'), rawMessage)); }
/// <summary> /// Checks the status of the current recovery manager /// </summary> /// <remarks> /// The method must: /// - Check whether current recovery is running and has expired /// - Whether there is an alive violation /// - Whether the user is behind with processing /// The method should not: /// - Update the processing delay - this is done on a message from a user's session /// - Start the recovery - this is done on alive from the system session /// - Complete non timed-out recovery - this is done on the snapshot_complete from user's session /// </remarks> public void CheckStatus() { //if the producer is disabled in SDK or not available for current user - nothing to do if (!Producer.IsAvailable || Producer.IsDisabled) { return; } // recovery must not be done (replay server) if (_producer.IgnoreRecovery) { return; } // multiple class fields can be accessed from multiple threads(messages from user session(s), system session, here, ...) lock (_syncLock) { var newStatus = Status; try { // check whether the user is falling behind with processing if (Status == ProducerRecoveryStatus.Completed && _timestampTracker.IsBehind) { newStatus = ProducerRecoveryStatus.Delayed; } // check whether the user was behind with processing but is no longer if (Status == ProducerRecoveryStatus.Delayed && !_timestampTracker.IsBehind) { newStatus = ProducerRecoveryStatus.Completed; } // Check whether there is an alive violation during normal processing if ((Status == ProducerRecoveryStatus.Completed || Status == ProducerRecoveryStatus.Delayed) && _timestampTracker.IsAliveViolated) { ExecutionLog.Warn($"Producer id={Producer.Id}: alive violation detected. Recovery will be done on next system alive."); newStatus = ProducerRecoveryStatus.Error; } // Check whether there is an alive violation during recovery if (Status == ProducerRecoveryStatus.Started && _timestampTracker.IsAliveViolated) { Debug.Assert(_recoveryOperation.IsRunning); ExecutionLog.Warn($"Producer id={Producer.Id}: alive violation detected during recovery. Additional recovery from {_timestampTracker.SystemAliveTimestamp} will be done once the current is completed."); _recoveryOperation.Interrupt(SdkInfo.FromEpochTime(_timestampTracker.SystemAliveTimestamp)); } // Check whether the recovery is running and has timed-out if (Status == ProducerRecoveryStatus.Started && _recoveryOperation.HasTimedOut()) { Debug.Assert(_recoveryOperation.IsRunning); _recoveryOperation.CompleteTimedOut(); ExecutionLog.Warn($"Producer id={Producer.Id}: recovery timeout. New recovery from {_timestampTracker.SystemAliveTimestamp} will be done."); newStatus = ProducerRecoveryStatus.Error; } ExecutionLog.Info($"Status check: Producer={_producer}({Enum.GetName(typeof(ProducerRecoveryStatus), Status)}), Timing Info={_timestampTracker}"); } catch (Exception ex) { ExecutionLog.Error($"An unexpected exception occurred while checking status. Producer={_producer.Id}. Status={Status}, IsRunning={_recoveryOperation.IsRunning}", ex); } if (newStatus != Status) { SetStatusAndRaiseEvent(null, newStatus); } } }
/// <summary> /// Maps (converts) the provided <see cref="bet_settlement"/> instance to the <see cref="IBetSettlement{T}"/> instance /// </summary> /// <param name="message">A <see cref="bet_settlement"/> 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="IBetSettlement{T}"/> instance constructed from information in the provided <see cref="bet_settlement"/></returns> public IBetSettlement <T> MapBetSettlement <T>(bet_settlement message, IEnumerable <CultureInfo> cultures, byte[] rawMessage) where T : ISportEvent { Guard.Argument(message, nameof(message)).NotNull(); var culturesList = cultures as List <CultureInfo> ?? cultures.ToList(); return(new BetSettlement <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, message.outcomes.Select(m => GetMarketWithResults(GetEventForNameProvider <T>(URN.Parse(message.event_id), message.SportId, culturesList), m, message.ProducerId, message.SportId, culturesList)), message.certainty, rawMessage)); }
private void CreateAndAttachEvents() { ExecutionLog.LogInformation("Opening the channel ..."); _channel = _channelFactory.CreateChannel(); ExecutionLog.LogInformation($"Channel opened with channelNumber: {_channel.ChannelNumber}. MaxAllowedTimeBetweenMessages={_maxTimeBetweenMessages.TotalSeconds}s."); var declareResult = _channel.QueueDeclare(); foreach (var routingKey in _routingKeys) { ExecutionLog.LogInformation($"Binding queue={declareResult.QueueName} with routingKey={routingKey}"); _channel.QueueBind(declareResult.QueueName, "unifiedfeed", routingKey); } var interestName = _interest == null ? "system" : _interest.Name; _consumer = new EventingBasicConsumer(_channel); _consumer.ConsumerTag = $"UfSdk-NetStd|{SdkInfo.GetVersion()}|{interestName}|{_channel.ChannelNumber}|{DateTime.Now:yyyyMMdd-HHmmss}|{SdkInfo.GetGuid(8)}"; _consumer.Received += ConsumerOnDataReceived; _consumer.Shutdown += ConsumerOnShutdown; _channel.BasicConsume(declareResult.QueueName, true, _consumer.ConsumerTag, _consumer); _channel.ModelShutdown += ChannelOnModelShutdown; ExecutionLog.LogInformation("BasicConsume for channel={}, queue={} and consumer tag {} executed.", _channel.ChannelNumber, declareResult.QueueName, _consumer.ConsumerTag); _lastMessageReceived = DateTime.MinValue; _channelStarted = DateTime.Now; }