public TheThingMatcher(TheMessageAddress thingAddress, Dictionary <string, object> propertiesToMatch) { var thingReference = new TheThingReference { EngineName = thingAddress.EngineName, ThingMID = thingAddress.ThingMID, PropertiesToMatch = propertiesToMatch }; Initialize(thingReference); }
virtual internal TheThing.TheThingSubscription GetSubscriptionInfo(bool?bGeneralize) { TheThingReference thingReference; var tThing = GetThing(); if (tThing != null) { thingReference = new TheThingReference(tThing); if (bGeneralize == true) { thingReference.ThingMID = null; } } else { thingReference = new TheThingReference() { ThingMID = (bGeneralize == false && TheCommonUtils.CGuid(this.ThingMID) != Guid.Empty) ? (Guid?)TheCommonUtils.CGuid(this.ThingMID) : null, EngineName = this.EngineName, DeviceType = this.DeviceType, FriendlyName = this.FriendlyName, PropertiesToMatch = TheSenderThing.CStringToDict(this.PropertiesToMatch), }; } var sub = new TheThing.TheThingSubscription { SubscriptionId = this.cdeMID, AddThingIdentity = this.AddThingIdentity, SamplingWindow = this.ChangeBufferTimeBucketSize, ContinueMatching = this.ContinueMatching, CooldownPeriod = this.ChangeBufferLatency, ThingReference = thingReference, EventFormat = this.EventFormat, ForceAllProperties = this.ForceAllProperties, ForceConfigProperties = this.ForceConfigProperties, IgnoreExistingHistory = this.IgnoreExistingHistory, IgnorePartialFailure = this.IgnorePartialFailure, KeepDurableHistory = this.KeepDurableHistory, MaxHistoryCount = this.MaxHistoryCount, MaxHistoryTime = this.MaxHistoryTime, PartitionKey = this.PartitionKey, PreserveOrder = this.PreserveOrder, PropertiesExcluded = TheCommonUtils.CStringToList(this.PropertiesExcluded, ','), PropertiesIncluded = TheCommonUtils.CStringToList(this.PropertiesIncluded, ','), SendInitialValues = this.SendInitialValues, SendUnchangedValue = this.SendUnchangedValue, StaticProperties = TheSenderThing.CStringToDict(this.StaticProperties), TargetName = this.TargetName, TargetType = this.TargetType, TargetUnit = this.TargetUnit, TokenExpirationInHours = this.TokenExpirationInHours, }; return(sub); }
private void Initialize(TheThingReference thingReference) { _thingReference = thingReference; if (thingReference.PropertiesToMatch != null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(thingReference.PropertiesToMatch); } if (!string.IsNullOrEmpty(thingReference.EngineName)) { if (_thingReference.PropertiesToMatch == null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(); } _thingReference.PropertiesToMatch[nameof(thingReference.EngineName)] = thingReference.EngineName; } if (!string.IsNullOrEmpty(thingReference.DeviceType)) { if (_thingReference.PropertiesToMatch == null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(); } _thingReference.PropertiesToMatch[nameof(thingReference.DeviceType)] = thingReference.DeviceType; } if (!string.IsNullOrEmpty(thingReference.FriendlyName)) { if (_thingReference.PropertiesToMatch == null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(); } _thingReference.PropertiesToMatch[nameof(thingReference.FriendlyName)] = thingReference.FriendlyName; } if (!string.IsNullOrEmpty(thingReference.ID)) { if (_thingReference.PropertiesToMatch == null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(); } _thingReference.PropertiesToMatch[nameof(thingReference.ID)] = thingReference.ID; } if (!string.IsNullOrEmpty(thingReference.Address)) { if (_thingReference.PropertiesToMatch == null) { _thingReference.PropertiesToMatch = new Dictionary <string, object>(); } _thingReference.PropertiesToMatch[nameof(thingReference.Address)] = thingReference.Address; } }
public TheThingMatcher(TheThingReference thingReference) { Initialize(thingReference); }
//internal static Task<ApplyConfigFilesResult> ApplyPipelineConfigJsonAsync(string pipelineConfigJson, IEnumerable<string> answerFilesJson, string configFileNameForLog, string[] answerFileNamesForLog) //{ // var pipeLineTasks = ApplyPipelineConfigJsonInternal(pipelineConfigJson, answerFilesJson, configFileNameForLog, answerFileNamesForLog); // if (pipeLineTasks == null) // { // return TheCommonUtils.TaskFromResult(new ApplyConfigFilesResult // { // Success = false, // }); // } // return TheCommonUtils.TaskWhenAll(pipeLineTasks.Select(t => (Task)t)) // .ContinueWith(t => // { // bool bSuccess = true; // int failedFileCount = 0; // foreach (var task in pipeLineTasks) // { // if (task.IsFaulted) // { // failedFileCount++; // bSuccess = false; // } // } // return new ApplyConfigFilesResult { Success = bSuccess, NumberOfFiles = 1, NumberOfFailedFiles = failedFileCount }; // }); //} static List <Task <List <TheThing> > > ApplyPipelineConfigJsonInternal(ThePipelineConfiguration pipelineConfig, IEnumerable <ThePipelineConfiguration> answerConfigs, string configFileNameForLog, string[] answerFileNamesForLog) { List <Task <List <TheThing> > > pipeLineTasks = new List <Task <List <TheThing> > >(); try { if (configFileNameForLog == null) { configFileNameForLog = pipelineConfig?.FriendlyName ?? "Not specified"; } if (pipelineConfig != null && pipelineConfig.ThingConfigurations != null) { var pipelines = new List <ThePipelineConfiguration>(); if (!pipelineConfig.ThingConfigurations.Any(tc => tc.ThingSpecializationParameters == null)) // If all thing instances have specializations, add the pipeline as a config { pipelines.Add(pipelineConfig); } try { if (!answerConfigs?.Any() == true && !pipelines.Contains(pipelineConfig)) { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Found no answer file for generalized config. Attempting to install the generalized config.", eMsgLevel.l2_Warning, $"File: {configFileNameForLog}. Config {pipelineConfig}")); pipelines.Add(pipelineConfig); } int answerFileIndex = 0; foreach (var answerConfig in answerConfigs) { var answerFileNameForLog = answerFileIndex < answerFileNamesForLog?.Length ? answerFileNamesForLog[answerFileIndex] : answerConfig.FriendlyName ?? $"Answer Config {answerFileIndex}"; answerFileIndex++; try { var pipelineInstance = TheCommonUtils.DeserializeJSONStringToObject <ThePipelineConfiguration>(TheCommonUtils.SerializeObjectToJSONString(pipelineConfig)); // TODO implement Clone to avoid reparsing int thingConfigIndex = 0; foreach (var answerThingConfig in answerConfig.ThingConfigurations) { // verify that the rest matches (or doesn't exist) if (thingConfigIndex < pipelineInstance.ThingConfigurations.Count) { if (answerThingConfig.ThingSpecializationParameters != null) { pipelineInstance.ThingConfigurations[thingConfigIndex].ThingSpecializationParameters = answerThingConfig.ThingSpecializationParameters; } else { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing answer file: no specialization parameters", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. Answer File: {answerFileNameForLog}. Config {pipelineInstance.ThingConfigurations[thingConfigIndex]}")); } if (answerThingConfig.ThingSubscriptions != null) { var generalizedSubscriptions = pipelineInstance.ThingConfigurations[thingConfigIndex].ThingSubscriptions; int subIndex = 0; var newSubscriptions = new List <TheThingSubscription>(); foreach (var answerSub in answerThingConfig.ThingSubscriptions) { if (answerSub != null) { if (answerSub.ExtensionData.ContainsKey("Add")) { // Add a new subscription: remember for now, add later to not confused the subIndex logic newSubscriptions.Add(answerSub); } else if (answerSub.ExtensionData.ContainsKey("Remove")) { // remove this subscription generalizedSubscriptions[subIndex] = null; // Just set to null here, so the subIndex logic doesn't get confused. Will remove the null's later. subIndex++; } else { // Update this subscription var generalizedSub = generalizedSubscriptions[subIndex]; TheThingSubscription.SpecializeThingSubscription(answerSub, generalizedSub); subIndex++; } } } generalizedSubscriptions.AddRange(newSubscriptions); generalizedSubscriptions.RemoveAll(sub => sub == null); } if (answerThingConfig.SensorSubscriptions != null) { var generalizedSubscriptions = pipelineInstance.ThingConfigurations[thingConfigIndex].SensorSubscriptions; int subIndex = 0; var newSubscriptions = new List <TheSensorSubscription>(); foreach (var answerSub in answerThingConfig.SensorSubscriptions) { if (answerSub != null) { if (answerSub.ExtensionData.ContainsKey("Add")) { // Add a new subscription: remember for now, add later to not confused the index newSubscriptions.Add(answerSub); } else if (answerSub.ExtensionData.ContainsKey("Remove")) { // remove this subscription generalizedSubscriptions[subIndex] = null; // Just set to null here, so the index doesn't get confused. Will remove the null's later. subIndex++; } else { // Update this subscription var generalizedSub = generalizedSubscriptions[subIndex]; TheSensorSubscription.SpecializeSensorSubscription(answerSub, generalizedSub); subIndex++; } } } generalizedSubscriptions.AddRange(newSubscriptions); generalizedSubscriptions.RemoveAll(sub => sub == null); } } else { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing answer file: too many specialization parameters. Ignoring.", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. Answer File: {answerFileNameForLog}. Config# {thingConfigIndex}")); } thingConfigIndex++; } if (answerConfig.ThingConfigurations.Count < pipelineInstance.ThingConfigurations.Count) { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing answer file: not enough specialization parameters.", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. Answer File: {answerFileNameForLog}. Params {answerConfig.ThingConfigurations.Count} Expected: {pipelineInstance.ThingConfigurations.Count}")); } pipelines.Add(pipelineInstance); } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing answer file", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. Answer File: {answerFileNameForLog}. {e.Message}")); } } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing answer files", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. {e.Message}")); } // TODO use the application host thing or specify the host thing in the pipeline config/answer file? var owner = TheThingRegistry.GetBaseEngineAsThing(eEngineName.ThingService); if (!owner.IsInit()) { TheBaseAssets.MySYSLOG.WriteToLog(7720, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, $"ApplyConfig Files: error getting Thing engine", eMsgLevel.l1_Error, $"{pipelineConfig}")); } foreach (var pipeline in pipelines) { var thingReferenceMap = new Dictionary <string, string>(); foreach (var thingConfig in pipeline.ThingConfigurations) { var specializedThingIdentity = thingConfig.GetSpecializedThingIdentity(thingReferenceMap); // First synchronously apply the configuration properties, so the plug-in does not start up with the old values var tThing = new TheThingReference(specializedThingIdentity).GetMatchingThings().FirstOrDefault(); if (tThing != null) { if (!tThing.ApplyConfigurationPropertiesInternal(thingConfig, thingReferenceMap)) { TheBaseAssets.MySYSLOG.WriteToLog(7719, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, $"Error applying config properties", eMsgLevel.l3_ImportantMessage, $"{thingConfig}")); } } } var thingsTask = CreateThingPipelineFromConfigurationAsync(owner, pipeline); pipeLineTasks.Add(thingsTask); } } else { throw new Exception($"Error parsing config file {configFileNameForLog}"); } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(7721, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(eEngineName.ThingService, "Error processing config file", eMsgLevel.l1_Error, $"File: {configFileNameForLog}. {e.Message}")); pipeLineTasks = null; } return(pipeLineTasks); }