public DeviceTwinName GetValidNames(string whitelist, DevicePropertyServiceModel existingData, string eventData)
        {
            ParseWhitelist(whitelist, out var fullNameWhitelist, out var prefixWhitelist);

            var validNames = new DeviceTwinName
            {
                Tags = fullNameWhitelist.Tags,
                ReportedProperties = fullNameWhitelist.ReportedProperties,
            };

            if (existingData != null && (existingData.Tags.Count > 0 || existingData.Reported.Count > 0))
            {
                validNames.Tags.UnionWith(existingData.Tags);

                validNames.ReportedProperties.UnionWith(existingData.Reported);
            }

            if (prefixWhitelist.Tags.Any() || prefixWhitelist.ReportedProperties.Any())
            {
                DeviceTwinName allNames = new DeviceTwinName();
                try
                {
                    // Get list of tags and reported properties from the twin change event data received by Event hub
                    allNames = this.GetDeviceTwinNames(eventData);
                }
                catch (Exception e)
                {
                    throw new Exception("Unable to fetch IoT devices", e);
                }

                if (allNames != null)
                {
                    validNames.Tags.UnionWith(allNames.Tags.
                                              Where(s => prefixWhitelist.Tags.Any(s.StartsWith)));

                    validNames.ReportedProperties.UnionWith(
                        allNames.ReportedProperties.Where(
                            s => prefixWhitelist.ReportedProperties.Any(s.StartsWith)));
                }
            }

            return(validNames);
        }
        private static void ParseWhitelist(
            string whitelist,
            out DeviceTwinName fullNameWhitelist,
            out DeviceTwinName prefixWhitelist)
        {
            var whitelistItems = whitelist.Split(',').Select(s => s.Trim());

            var tags = whitelistItems
                       .Where(s => s.StartsWith(WhitelistTagPrefix, StringComparison.OrdinalIgnoreCase))
                       .Select(s => s.Substring(WhitelistTagPrefix.Length));

            var reported = whitelistItems
                           .Where(s => s.StartsWith(WhitelistReportedPrefix, StringComparison.OrdinalIgnoreCase))
                           .Select(s => s.Substring(WhitelistReportedPrefix.Length));

            var fixedTags = tags.Where(s => !s.EndsWith("*"));

            var fixedReported = reported.Where(s => !s.EndsWith("*"));

            var regexTags = tags.Where(s => s.EndsWith("*")).Select(s => s.Substring(0, s.Length - 1));

            var regexReported = reported.
                                Where(s => s.EndsWith("*")).
                                Select(s => s.Substring(0, s.Length - 1));

            fullNameWhitelist = new DeviceTwinName
            {
                Tags = new HashSet <string>(fixedTags),
                ReportedProperties = new HashSet <string>(fixedReported),
            };
            prefixWhitelist = new DeviceTwinName
            {
                Tags = new HashSet <string>(regexTags),
                ReportedProperties = new HashSet <string>(regexReported),
            };
        }
Exemplo n.º 3
0
        public async Task <bool> UpdateDevicePropertiesAsync(string eventData, string tenant)
        {
            bool updateStatus = false;
            DevicePropertyServiceModel existingDevProperties = null;
            ValueServiceModel          deviceCacheValue      = null;
            CosmosOperations           docClient             = null;

            try
            {
                this.cosmosDbcoll           = $"{CollectionKey}-{tenant}";
                this.cosmosDb               = Environment.GetEnvironmentVariable("DevicePropertiesCacheDatabaseId", EnvironmentVariableTarget.Process);
                this.whitelist              = Environment.GetEnvironmentVariable("WhiteList", EnvironmentVariableTarget.Process);
                this.cosmosDbRus            = Convert.ToInt32(Environment.GetEnvironmentVariable("CosmosDBRus", EnvironmentVariableTarget.Process));
                this.cosmosConnectionString = Environment.GetEnvironmentVariable("CosmosDbConnectionString", EnvironmentVariableTarget.Process);

                docClient = await CosmosOperations.GetClientAsync();

                updateStatus = await docClient.CreateCollectionIfNotExistsAsync(this.cosmosDb, this.cosmosDbcoll, this.cosmosDbRus, CosmosOperation.DeviceCache);

                // CosmosHelper cosmosHelper = new CosmosHelper(cosmosConnectionString, cosmosDbcoll, cosmosDb, tenant, cosmosDbRus, CosmosOperation.devicecache);
                try
                {
                    deviceCacheValue = await docClient.GetDocumentAsync(this.GenerateCollectionLink(this.cosmosDb, this.cosmosDbcoll), CollectionId, Key);

                    existingDevProperties = JsonConvert.DeserializeObject <DevicePropertyServiceModel>(deviceCacheValue.Data);
                }
                catch (ResourceNotFoundException)
                {
                    // Do nothing
                }
                catch (Exception exception)
                {
                    throw new ApplicationException("Get Device Properties failed", exception);
                }

                DeviceTwinNameOperations devTwinOps     = new DeviceTwinNameOperations();
                DeviceTwinName           deviceTwinName = devTwinOps.GetValidNames(this.whitelist, existingDevProperties, eventData);

                if (deviceTwinName != null)
                {
                    DevicePropertyServiceModel devicePropertyModel = new DevicePropertyServiceModel
                    {
                        Tags     = deviceTwinName.Tags,
                        Reported = deviceTwinName.ReportedProperties,
                    };

                    ValueServiceModel valueSvcModel = new ValueServiceModel(new KeyValueDocument(CollectionId, Key, JsonConvert.SerializeObject(devicePropertyModel)));

                    if (devicePropertyModel != null && existingDevProperties == null)
                    {
                        // Create the document
                        if (deviceCacheValue == null)
                        {
                            await docClient.SaveDocumentAsync(CollectionId, Key, valueSvcModel, this.GenerateCollectionLink(this.cosmosDb, this.cosmosDbcoll));

                            updateStatus = true;
                        }
                    }
                    else
                    {
                        // update only if the Tags or the reported properties are different from ones stored in cosmos
                        if (existingDevProperties != null && (!existingDevProperties.Tags.SetEquals(devicePropertyModel.Tags) || !existingDevProperties.Reported.SetEquals(devicePropertyModel.Reported)))
                        {
                            await docClient.SaveDocumentAsync(CollectionId, Key, valueSvcModel, this.GenerateCollectionLink(this.cosmosDb, this.cosmosDbcoll));

                            updateStatus = true;
                        }
                    }
                }
                else
                {
                    updateStatus = true;
                }
            }
            catch (Exception exception)
            {
                throw new ApplicationException($"Update Device Properties failed {exception}, tenant: {tenant}");
            }

            return(updateStatus);
        }