/// <summary>
            /// Merge properties
            /// </summary>
            /// <param name="target"></param>
            /// <param name="source"></param>
            private Dictionary <string, VariantValue> Merge(
                Dictionary <string, VariantValue> target,
                Dictionary <string, VariantValue> source)
            {
                if (source == null)
                {
                    return(target);
                }

                if (target == null)
                {
                    return(source);
                }

                foreach (var item in source)
                {
                    if (target.ContainsKey(item.Key))
                    {
                        if (VariantValueEx.IsNull(item.Value) || VariantValueEx.IsNull(item.Value))
                        {
                            target.Remove(item.Key);
                        }
                        else
                        {
                            target[item.Key] = item.Value;
                        }
                    }
                    else if (!VariantValueEx.IsNull(item.Value))
                    {
                        target.Add(item.Key, item.Value);
                    }
                }
                return(target);
            }
        public async Task NodeReadStaticArrayByteStringValueVariableTestAsync()
        {
            var browser  = _services();
            var node     = "http://test.org/UA/Data/#i=10314";
            var expected = await _readExpected(_endpoint, node);

            // Act
            var result = await browser.NodeValueReadAsync(_endpoint,
                                                          new ValueReadRequestModel {
                NodeId = node
            });

            // Assert
            Assert.NotNull(result);
            Assert.NotNull(result.Value);
            Assert.NotNull(result.SourceTimestamp);
            Assert.NotNull(result.ServerTimestamp);
            AssertEqualValue(expected, result.Value);

            if (VariantValueEx.IsNull(result.Value))
            {
                return;
            }
            Assert.True(result.Value.IsListOfValues);
            if (result.Value.Count == 0)
            {
                return;
            }
            // TODO: Can be null.  Assert.Equal(VariantValueType.String, (result.Value)[0].Type);
            // TODO:  Assert.Equal(VariantValueType.Bytes, (result.Value)[0].Type);
            Assert.Equal("ByteString", result.DataType);
        }
        public async Task NodeReadStaticArrayByteValueVariableTestAsync()
        {
            var browser  = _services();
            var node     = "http://test.org/UA/Data/#i=10302";
            var expected = await _readExpected(_endpoint, node);

            // Act
            var result = await browser.NodeValueReadAsync(_endpoint,
                                                          new ValueReadRequestModel {
                NodeId = node
            });

            // Assert
            Assert.NotNull(result);
            Assert.NotNull(result.Value);
            Assert.NotNull(result.SourceTimestamp);
            Assert.NotNull(result.ServerTimestamp);
            AssertEqualValue(expected, result.Value);

            if (VariantValueEx.IsNull(result.Value))
            {
                return;
            }

            Assert.True(result.Value.IsString);
            // TODO: Returns a bytestring, not byte array.  Investigate.
            // Assert.Equal(VariantValueType.Bytes, result.Value.Type);
            // Assert.True(result.Value.IsArray);
            // if ((result.Value).Count == 0) return;
            // Assert.Equal(VariantValueType.Integer, (result.Value)[0].Type);
            Assert.Equal("ByteString", result.DataType);
            // TODO: Assert.Equal("Byte", result.DataType);
        }
 /// <summary>
 /// Equality comparison
 /// </summary>
 /// <param name="model"></param>
 /// <param name="that"></param>
 /// <returns></returns>
 public static bool IsSameAs(this CredentialModel model,
                             CredentialModel that)
 {
     if (model == that)
     {
         return(true);
     }
     if (model == null || that == null)
     {
         return(false);
     }
     if ((that.Type ?? CredentialType.None) !=
         (model.Type ?? CredentialType.None))
     {
         return(false);
     }
     if (VariantValueEx.IsNull(that.Value) || VariantValueEx.IsNull(model.Value))
     {
         if (VariantValueEx.IsNull(that.Value) && VariantValueEx.IsNull(model.Value))
         {
             return(true);
         }
         return(false);
     }
     if (!VariantValue.DeepEquals(that.Value, model.Value))
     {
         return(false);
     }
     return(true);
 }
Beispiel #5
0
            /// <inheritdoc/>
            public override void WriteJson(JsonWriter writer, object value,
                                           JsonSerializer serializer)
            {
                switch (value)
                {
                case JsonVariantValue json:
                    json.Token.WriteTo(writer, serializer.Converters.ToArray());
                    break;

                case VariantValue variant:
                    if (VariantValueEx.IsNull(variant))
                    {
                        writer.WriteNull();
                    }
                    else if (variant.IsListOfValues)
                    {
                        writer.WriteStartArray();
                        foreach (var item in variant.Values)
                        {
                            WriteJson(writer, item, serializer);
                        }
                        writer.WriteEndArray();
                    }
                    else if (variant.IsObject)
                    {
                        writer.WriteStartObject();
                        foreach (var key in variant.PropertyNames)
                        {
                            var item = variant[key];
                            if (VariantValueEx.IsNull(item))
                            {
                                if (serializer.NullValueHandling != NullValueHandling.Include ||
                                    serializer.DefaultValueHandling != DefaultValueHandling.Include)
                                {
                                    break;
                                }
                            }
                            writer.WritePropertyName(key);
                            WriteJson(writer, item, serializer);
                        }
                        writer.WriteEndObject();
                    }
                    else if (variant.TryGetValue(out var primitive))
                    {
                        serializer.Serialize(writer, primitive);
                        break;
                    }
                    else
                    {
                        serializer.Serialize(writer, variant.Value);
                        break;
                    }
                    break;

                default:
                    throw new NotSupportedException("Unexpected type passed");
                }
            }
Beispiel #6
0
        /// <summary>
        /// Synchronize controllers with current reported twin state
        /// </summary>
        /// <param name="twin"></param>
        /// <param name="reported"></param>
        /// <returns></returns>
        private async Task ReportControllerStateAsync(Twin twin,
                                                      Dictionary <string, VariantValue> reported)
        {
            var processed = await _settings.GetSettingsStateAsync();

            // If there are changes, update what should be reported back.
            foreach (var property in processed)
            {
                var exists = twin.Properties.Reported.Contains(property.Key);
                if (VariantValueEx.IsNull(property.Value))
                {
                    if (exists)
                    {
                        // If exists as reported, remove
                        reported.AddOrUpdate(property.Key, null);
                        _reported.Remove(property.Key);
                    }
                }
                else
                {
                    if (exists)
                    {
                        // If exists and same as property value, continue
                        var r = (VariantValue)this._serializer.FromObject(
                            twin.Properties.Reported[property.Key]);
                        if (r == property.Value)
                        {
                            continue;
                        }
                    }
                    else if (VariantValueEx.IsNull(property.Value))
                    {
                        continue;
                    }

                    // Otherwise, add to reported properties
                    reported[property.Key] = property.Value;
                    _reported.AddOrUpdate(property.Key, property.Value);
                }
            }
            if (reported.Count > 0)
            {
                _logger.Debug("Reporting controller state...");
                var collection = new TwinCollection();
                foreach (var item in reported)
                {
                    collection[item.Key] = item.Value?.ConvertTo <object>();
                }
                await Client.UpdateReportedPropertiesAsync(collection);

                _logger.Debug("Complete controller state reported (properties: {@settings}).",
                              reported.Keys);
            }
        }
Beispiel #7
0
 /// <inheritdoc/>
 public int Serialize(ref byte[] bytes, int offset, T value,
                      MessagePackSerializerOptions options)
 {
     if (value is MessagePackVariantValue packed)
     {
         return(MsgPack.Serialize(packed._value?.GetType() ?? typeof(object),
                                  ref bytes, offset, packed._value, options));
     }
     else if (value is null)
     {
         return(MsgPackWriter.WriteNil(ref bytes, offset));
     }
     else if (value is VariantValue variant)
     {
         if (VariantValueEx.IsNull(variant))
         {
             return(MsgPackWriter.WriteNil(ref bytes, offset));
         }
         else if (variant.IsListOfValues)
         {
             var written = MsgPackWriter.WriteArrayHeader(
                 ref bytes, offset, variant.Count);
             foreach (var item in variant.Values)
             {
                 written += MsgPack.Serialize(item?.GetType() ?? typeof(object),
                                              ref bytes, offset + written, item, options);
             }
             return(written);
         }
         else if (variant.IsObject)
         {
             // Serialize objects as key value pairs
             var dict = variant.PropertyNames
                        .ToDictionary(k => k, k => variant[k]);
             return(MsgPack.Serialize(dict.GetType(), ref bytes,
                                      offset, dict, options));
         }
         else if (variant.TryGetValue(out var primitive))
         {
             return(MsgPack.Serialize(primitive?.GetType() ?? typeof(object),
                                      ref bytes, offset, primitive, options));
         }
         else
         {
             return(MsgPack.Serialize(variant.Value?.GetType() ?? typeof(object),
                                      ref bytes, offset, variant.Value, options));
         }
     }
     else
     {
         return(offset);
     }
 }
            /// <inheritdoc/>
            public Variant Decode(VariantValue value, BuiltInType builtinType)
            {
                if (VariantValueEx.IsNull(value))
                {
                    return(Variant.Null);
                }

                //
                // Sanitize json input from user
                //
                value = Sanitize(value, builtinType == BuiltInType.String);

                VariantValue json;

                if (builtinType == BuiltInType.Null ||
                    (builtinType == BuiltInType.Variant &&
                     value.IsObject))
                {
                    //
                    // Let the decoder try and decode the json variant.
                    //
                    json = Serializer.FromObject(new { value });
                }
                else
                {
                    //
                    // Give decoder a hint as to the type to use to decode.
                    //
                    json = Serializer.FromObject(new {
                        value = new {
                            Body = value,
                            Type = (byte)builtinType
                        }
                    });
                }

                //
                // Decode json to a real variant
                //
                using (var text = new StringReader(Serializer.SerializeToString(json)))
                    using (var reader = new Newtonsoft.Json.JsonTextReader(text))
                        using (var decoder = new JsonDecoderEx(reader, Context)) {
                            return(decoder.ReadVariant(nameof(value)));
                        }
            }
Beispiel #9
0
        public async Task NodeReadStaticArrayByteValueVariableTestAsync()
        {
            var browser  = _services();
            var node     = "http://test.org/UA/Data/#i=10302";
            var expected = await _readExpected(_endpoint, node);

            // Act
            var result = await browser.NodeValueReadAsync(_endpoint,
                                                          new ValueReadRequestModel {
                NodeId = node
            });

            // Assert
            Assert.NotNull(result);
            Assert.NotNull(result.SourceTimestamp);
            Assert.NotNull(result.ServerTimestamp);
            AssertEqualValue(expected, result.Value);

            Assert.Equal("ByteString", result.DataType);
            Assert.True(VariantValueEx.IsNull(result.Value) || result.Value.IsBytes);
        }
        /// <summary>
        /// Consolidated
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static Dictionary <string, VariantValue> GetConsolidatedProperties(
            this DeviceTwinModel model)
        {
            var desired  = model.Properties?.Desired;
            var reported = model.Properties?.Reported;

            if (reported == null || desired == null)
            {
                return((reported ?? desired) ??
                       new Dictionary <string, VariantValue>());
            }

            var properties = new Dictionary <string, VariantValue>(desired);

            // Merge with reported
            foreach (var prop in reported)
            {
                if (properties.TryGetValue(prop.Key, out var existing))
                {
                    if (VariantValueEx.IsNull(existing) || VariantValueEx.IsNull(prop.Value))
                    {
                        if (VariantValueEx.IsNull(existing) && VariantValueEx.IsNull(prop.Value))
                        {
                            continue;
                        }
                    }
                    else if (VariantValue.DeepEquals(existing, prop.Value))
                    {
                        continue;
                    }
                    properties[prop.Key] = prop.Value;
                }
                else
                {
                    properties.Add(prop.Key, prop.Value);
                }
            }
            return(properties);
        }
            /// <summary>
            /// Sanitizes user input by removing quotes around non strings,
            /// or adding array brackets to comma seperated values that are
            /// not string type and recursing through arrays to do the same.
            /// The output is a pure json token that can be passed to the
            /// json decoder.
            /// </summary>
            /// <param name="value"></param>
            /// <param name="isString"></param>
            /// <returns></returns>
            internal VariantValue Sanitize(VariantValue value, bool isString)
            {
                if (VariantValueEx.IsNull(value))
                {
                    return(value);
                }

                if (!value.TryGetString(out var asString, true))
                {
                    asString = Serializer.SerializeToString(value);
                }

                if (!value.IsObject && !value.IsListOfValues && !value.IsString)
                {
                    //
                    // If this should be a string - return as such
                    //
                    return(isString ? asString : value);
                }

                if (string.IsNullOrWhiteSpace(asString))
                {
                    return(value);
                }

                //
                // Try to parse string as json
                //
                if (!value.IsString)
                {
                    asString = asString.Replace("\\\"", "\"");
                }
                var token = Try.Op(() => Serializer.Parse(asString));

                if (!(token is null))
                {
                    value = token;
                }

                if (value.IsString)
                {
                    //
                    // try to split the string as comma seperated list
                    //
                    var elements = asString.Split(',');
                    if (isString)
                    {
                        //
                        // If all elements are quoted, then this is a
                        // string array
                        //
                        if (elements.Length > 1)
                        {
                            var array = new List <string>();
                            foreach (var element in elements)
                            {
                                var trimmed = element.Trim().TrimQuotes();
                                if (trimmed == element)
                                {
                                    // Treat entire string as value
                                    return(value);
                                }
                                array.Add(trimmed);
                            }
                            // No need to sanitize contents
                            return(Serializer.FromObject(array));
                        }
                    }
                    else
                    {
                        //
                        // First trim any quotes from string before splitting.
                        //
                        if (elements.Length > 1)
                        {
                            //
                            // Parse as array
                            //
                            var trimmed = elements.Select(e => e.TrimQuotes()).ToArray();
                            try {
                                value = Serializer.Parse(
                                    "[" + trimmed.Aggregate((x, y) => x + "," + y) + "]");
                            }
                            catch {
                                value = Serializer.Parse(
                                    "[\"" + trimmed.Aggregate((x, y) => x + "\",\"" + y) + "\"]");
                            }
                        }
                        else
                        {
                            //
                            // Try to remove next layer of quotes and try again.
                            //
                            var trimmed = asString.Trim().TrimQuotes();
                            if (trimmed != asString)
                            {
                                return(Sanitize(trimmed, isString));
                            }
                        }
                    }
                }

                if (value.IsListOfValues)
                {
                    //
                    // Sanitize each element accordingly
                    //
                    return(Serializer.FromObject(value.Values
                                                 .Select(t => Sanitize(t, isString))));
                }
                return(value);
            }