internal static void SpecializeSensorSubscription(TheSensorSubscription answerSub, TheSensorSubscription generalizedSub) { if (answerSub.SubscriptionId != null) { generalizedSub.SubscriptionId = answerSub.SubscriptionId; } if (answerSub.ExtensionData != null) { foreach (var prop in answerSub.ExtensionData) { generalizedSub.ExtensionData[prop.Key] = prop.Value; } } if (answerSub.SampleRate != null) { generalizedSub.SampleRate = answerSub.SampleRate; } if (answerSub.SensorId != null) { generalizedSub.SensorId = answerSub.SensorId; } if (answerSub.TargetProperty != null) { generalizedSub.TargetProperty = answerSub.TargetProperty; } if (answerSub.TargetThing != null) { generalizedSub.TargetThing = answerSub.TargetThing; } }
public TheSensorSubscription(TheSensorSubscription sensorInfo, bool normalizeExtensionData) { this.SubscriptionId = sensorInfo.SubscriptionId; this.SensorId = sensorInfo.SensorId; this.SampleRate = sensorInfo.SampleRate; this.TargetThing = sensorInfo.TargetThing; this.TargetProperty = sensorInfo.TargetProperty; var extensionData = normalizeExtensionData ? sensorInfo.GetBaseSubscription()?.ExtensionData : sensorInfo.ExtensionData; if (extensionData != null) { this.ExtensionData = new Dictionary <string, object>(extensionData); } }
public TheSensorSubscription(TheSensorSubscription sensorInfo) : this(sensorInfo, true) { }
//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); }