Example #1
0
        public TheThingMatcher(TheMessageAddress thingAddress, Dictionary <string, object> propertiesToMatch)
        {
            var thingReference = new TheThingReference {
                EngineName = thingAddress.EngineName, ThingMID = thingAddress.ThingMID, PropertiesToMatch = propertiesToMatch
            };

            Initialize(thingReference);
        }
Example #2
0
        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);
        }
Example #3
0
 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;
     }
 }
Example #4
0
 public TheThingMatcher(TheThingReference thingReference)
 {
     Initialize(thingReference);
 }
Example #5
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);
        }