Example #1
0
 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;
     }
 }
Example #2
0
            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);
                }
            }
Example #3
0
 public TheSensorSubscription(TheSensorSubscription sensorInfo) : this(sensorInfo, true)
 {
 }
Example #4
0
        //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);
        }