Ejemplo n.º 1
0
 /// <summary>
 /// Decode with data type as string
 /// </summary>
 /// <param name="encoder"></param>
 /// <param name="value"></param>
 /// <param name="type"></param>
 /// <param name="context"></param>
 /// <returns></returns>
 public static Variant Decode(this IVariantEncoder encoder, JToken value,
                              string type, ServiceMessageContext context)
 {
     return(encoder.Decode(value,
                           string.IsNullOrEmpty(type) || context == null ? BuiltInType.Null :
                           TypeInfo.GetBuiltInType(type.ToNodeId(context)), context));
 }
            /// <summary>
            /// Create new
            /// </summary>
            /// <param name="session"></param>
            /// <param name="codec"></param>
            /// <returns></returns>
            internal void Create(Session session, IVariantEncoder codec)
            {
                Item = new MonitoredItem {
                    Handle = this,

                    DisplayName  = Template.DisplayName,
                    AttributeId  = ((uint?)Template.AttributeId) ?? Attributes.Value,
                    IndexRange   = Template.IndexRange,
                    RelativePath = Template.RelativePath?
                                   .ToRelativePath(session.MessageContext)?
                                   .Format(session.NodeCache.TypeTree),
                    MonitoringMode = Template.MonitoringMode.ToStackType() ??
                                     Opc.Ua.MonitoringMode.Reporting,
                    StartNodeId      = Template.StartNodeId.ToNodeId(session.MessageContext),
                    QueueSize        = Template.QueueSize ?? 0,
                    SamplingInterval =
                        (int?)Template.SamplingInterval?.TotalMilliseconds ?? -1,
                    DiscardOldest = !(Template.DiscardNew ?? false),
                    Filter        =
                        Template.DataChangeFilter.ToStackModel() ??
                        codec.Decode(Template.EventFilter, true) ??
                        ((MonitoringFilter)Template.AggregateFilter
                         .ToStackModel(session.MessageContext))
                };
            }
 /// <summary>
 /// Create source stream importer
 /// </summary>
 /// <param name="factory"></param>
 /// <param name="codec"></param>
 /// <param name="logger"></param>
 public SourceStreamImporter(IItemContainerFactory factory, IVariantEncoder codec,
                             ILogger logger)
 {
     _logger  = logger ?? throw new ArgumentNullException(nameof(logger));
     _codec   = codec ?? throw new ArgumentNullException(nameof(codec));
     _factory = factory ?? throw new ArgumentNullException(nameof(factory));
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Convert to results
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static HistoricValueModel[] DecodeValues(this IVariantEncoder codec, VariantValue result)
        {
            var extensionObject = codec.DecodeExtensionObject(result);

            if (extensionObject?.Body is HistoryData data)
            {
                var results = data.DataValues.Select(d => new HistoricValueModel {
                    ServerPicoseconds = d.ServerPicoseconds.ToNullable((ushort)0),
                    SourcePicoseconds = d.SourcePicoseconds.ToNullable((ushort)0),
                    ServerTimestamp   = d.ServerTimestamp.ToNullable(DateTime.MinValue),
                    SourceTimestamp   = d.SourceTimestamp.ToNullable(DateTime.MinValue),
                    StatusCode        = d.StatusCode.ToNullable(StatusCodes.Good)?.CodeBits,
                    Value             = d.WrappedValue == Variant.Null ? null : codec.Encode(d.WrappedValue)
                }).ToArray();
                if (extensionObject?.Body is HistoryModifiedData modified)
                {
                    if (modified.ModificationInfos.Count != data.DataValues.Count)
                    {
                        throw new FormatException("Modification infos and data value count is not the same");
                    }
                    for (var i = 0; i < modified.ModificationInfos.Count; i++)
                    {
                        results[i].ModificationInfo = new ModificationInfoModel {
                            ModificationTime =
                                modified.ModificationInfos[i].ModificationTime.ToNullable(DateTime.MinValue),
                            UserName =
                                modified.ModificationInfos[i].UserName
                        };
                    }
                }
                return(results);
            }
            return(null);
        }
        /// <summary>
        /// Convert read processed details
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="details"></param>
        /// <returns></returns>
        public static JToken Encode(this IVariantEncoder codec, ReadProcessedValuesDetailsModel details)
        {
            if (details == null)
            {
                throw new ArgumentNullException(nameof(details));
            }
            if (details.EndTime == null && details.StartTime == null)
            {
                throw new ArgumentException("Start time and end time cannot both be null", nameof(details));
            }
            // Convert aggregate id with a temporary namespace table that will contain the aggregate namespace
            var context   = new ServiceMessageContext();
            var aggregate = details.AggregateTypeId?.ToNodeId(context);

            return(codec.Encode(new ExtensionObject(new ReadProcessedDetails {
                EndTime = details.EndTime ?? DateTime.MinValue,
                StartTime = details.StartTime ?? DateTime.MinValue,
                AggregateType = aggregate == null ? null : new NodeIdCollection(aggregate.YieldReturn()),
                ProcessingInterval = details.ProcessingInterval ?? 0,
                AggregateConfiguration = details.AggregateConfiguration == null ? null :
                                         new AggregateConfiguration {
                    PercentDataBad =
                        details.AggregateConfiguration.PercentDataBad ?? 0,
                    PercentDataGood =
                        details.AggregateConfiguration.PercentDataGood ?? 0,
                    TreatUncertainAsBad =
                        details.AggregateConfiguration.TreatUncertainAsBad ?? false,
                    UseServerCapabilitiesDefaults =
                        details.AggregateConfiguration.UseServerCapabilitiesDefaults ?? false,
                    UseSlopedExtrapolation =
                        details.AggregateConfiguration.UseSlopedExtrapolation ?? false
                }
            }), context)); // Reapplies the aggregate namespace uri during encoding using the context's table
        }
        /// <summary>
        /// Encode extension object
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="o"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        internal static JToken Encode(this IVariantEncoder codec,
                                      ExtensionObject o, ServiceMessageContext context = null)
        {
            var variant = o == null ? Variant.Null : new Variant(o);

            return(codec.Encode(variant, out _, context));
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Create service
 /// </summary>
 /// <param name="client"></param>
 /// <param name="codec"></param>
 /// <param name="logger"></param>
 public HistoricAccessAdapter(IHistoricAccessServices <T> client, IVariantEncoder codec,
                              ILogger logger)
 {
     _codec  = codec ?? throw new ArgumentNullException(nameof(codec));
     _client = client ?? throw new ArgumentNullException(nameof(client));
     _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Encode extension object
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        internal static ExtensionObject DecodeExtensionObject(this IVariantEncoder codec,
                                                              JToken result)
        {
            if (result == null)
            {
                return(null);
            }
            var variant = codec.Decode(result, BuiltInType.ExtensionObject);

            return(variant.Value as ExtensionObject);
        }
 /// <summary>
 /// Convert to service model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <returns></returns>
 public static ContentFilterModel Encode(this IVariantEncoder encoder, ContentFilter model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ContentFilterModel {
         Elements = model.Elements?
                    .Select(e => encoder.Encode(e))
                    .ToList()
     });
 }
Ejemplo n.º 10
0
 /// <summary>
 /// Convert delete raw modified details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, DeleteModifiedValuesDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     return(codec.Encode(new ExtensionObject(new DeleteRawModifiedDetails {
         NodeId = NodeId.Null,
         EndTime = details.EndTime ?? DateTime.MinValue,
         StartTime = details.StartTime ?? DateTime.MinValue,
         IsDeleteModified = true
     })));
 }
        /// <summary>
        /// Convert from service result to diagnostics info
        /// </summary>
        /// <param name="result"></param>
        /// <param name="config"></param>
        /// <param name="codec"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static DiagnosticInfo Decode(this IVariantEncoder codec,
                                            ServiceResultModel result, DiagnosticsModel config, out StatusCode code)
        {
            if (result == null)
            {
                code = StatusCodes.Good;
                return(null);
            }
            code = new StatusCode(result.StatusCode ?? StatusCodes.Good);
            var results = codec.Decode(result, config);

            return(results?.LastOrDefault()?.DiagnosticsInfo);
        }
 /// <summary>
 /// Convert to stack model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <param name="onlySimpleAttributeOperands"></param>
 /// <returns></returns>
 public static ContentFilter Decode(this IVariantEncoder encoder, ContentFilterModel model,
                                    bool onlySimpleAttributeOperands = false)
 {
     if (model == null)
     {
         return(new ContentFilter());
     }
     return(new ContentFilter {
         Elements = new ContentFilterElementCollection(model.Elements == null ?
                                                       Enumerable.Empty <ContentFilterElement>() : model.Elements
                                                       .Select(e => encoder.Decode(e, onlySimpleAttributeOperands)))
     });
 }
 /// <summary>
 /// Convert to stack model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <returns></returns>
 public static EventFilterModel Encode(this IVariantEncoder encoder, EventFilter model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new EventFilterModel {
         SelectClauses = model.SelectClauses?
                         .Select(c => c.ToServiceModel(encoder.Context))
                         .ToList(),
         WhereClause = encoder.Encode(model.WhereClause)
     });
 }
        /// <summary>
        /// Convert operation results to json
        /// </summary>
        /// <param name="results"></param>
        /// <param name="config"></param>
        /// <param name="codec"></param>
        /// <returns></returns>
        private static VariantValue Write(this IVariantEncoder codec,
                                          List <OperationResultModel> results, DiagnosticsModel config)
        {
            var level = config?.Level ?? Core.Models.DiagnosticsLevel.Status;

            if (level == Core.Models.DiagnosticsLevel.None)
            {
                return(null);
            }
            using (var stream = new MemoryStream()) {
                var root = kDiagnosticsProperty;
                using (var encoder = new JsonEncoderEx(stream, codec.Context)
                {
                    UseAdvancedEncoding = true,
                    IgnoreDefaultValues = true
                }) {
                    switch (level)
                    {
                    case Core.Models.DiagnosticsLevel.Diagnostics:
                    case Core.Models.DiagnosticsLevel.Verbose:
                        encoder.WriteEncodeableArray(root, results);
                        break;

                    case Core.Models.DiagnosticsLevel.Operations:
                        var codes = results
                                    .GroupBy(d => d.StatusCode.CodeBits);
                        root = null;
                        foreach (var code in codes)
                        {
                            encoder.WriteStringArray(StatusCode.LookupSymbolicId(code.Key),
                                                     code.Select(c => c.Operation).ToArray());
                        }
                        break;

                    case Core.Models.DiagnosticsLevel.Status:
                        var statusCodes = results
                                          .Select(d => StatusCode.LookupSymbolicId(d.StatusCode.CodeBits))
                                          .Where(s => !string.IsNullOrEmpty(s))
                                          .Distinct();
                        if (!statusCodes.Any())
                        {
                            return(null);
                        }
                        encoder.WriteStringArray(root, statusCodes.ToArray());
                        break;
                    }
                }
                var o = codec.Serializer.Parse(stream.ToArray());
                return(root != null ? o[root] : o);
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Convert to results
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static HistoricEventModel[] DecodeEvents(this IVariantEncoder codec, JToken result)
        {
            var extensionObject = codec.DecodeExtensionObject(result);

            if (extensionObject?.Body is HistoryEvent ev)
            {
                return(ev.Events.Select(d => new HistoricEventModel {
                    EventFields = d.EventFields
                                  .Select(v => v == Variant.Null ? null : codec.Encode(v))
                                  .ToList()
                }).ToArray());
            }
            return(null);
        }
Ejemplo n.º 16
0
 /// <summary>
 /// Convert delete at time details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, DeleteValuesAtTimesDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.ReqTimes == null || details.ReqTimes.Length == 0)
     {
         throw new ArgumentException(nameof(details.ReqTimes));
     }
     return(codec.Encode(new ExtensionObject(new DeleteAtTimeDetails {
         NodeId = NodeId.Null,
         ReqTimes = new DateTimeCollection(details.ReqTimes)
     })));
 }
 /// <summary>
 /// Convert to stack model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <param name="onlySimpleAttributeOperands"></param>
 /// <returns></returns>
 public static ContentFilterElement Decode(this IVariantEncoder encoder,
                                           ContentFilterElementModel model, bool onlySimpleAttributeOperands = false)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ContentFilterElement {
         FilterOperands = new ExtensionObjectCollection(model?.FilterOperands == null ?
                                                        Enumerable.Empty <ExtensionObject>() : model.FilterOperands
                                                        .Select(e => new ExtensionObject(
                                                                    encoder.Decode(e, onlySimpleAttributeOperands)))),
         FilterOperator = model.FilterOperator.ToStackType()
     });
 }
Ejemplo n.º 18
0
 /// <summary>
 /// Convert delete event details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, DeleteEventsDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.EventIds == null || details.EventIds.Count == 0)
     {
         throw new ArgumentException(nameof(details.EventIds));
     }
     return(codec.Encode(new ExtensionObject(new DeleteEventDetails {
         NodeId = NodeId.Null,
         EventIds = new ByteStringCollection(details.EventIds)
     })));
 }
Ejemplo n.º 19
0
 /// <summary>
 /// Convert read at time details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, ReadValuesAtTimesDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.ReqTimes == null || details.ReqTimes.Length == 0)
     {
         throw new ArgumentException(nameof(details.ReqTimes));
     }
     return(codec.Encode(new ExtensionObject(new ReadAtTimeDetails {
         ReqTimes = new DateTimeCollection(details.ReqTimes),
         UseSimpleBounds = details.UseSimpleBounds ?? false
     })));
 }
 /// <summary>
 /// Convert from diagnostics info to service result
 /// </summary>
 /// <param name="diagnostics"></param>
 /// <param name="code"></param>
 /// <param name="operation"></param>
 /// <param name="config"></param>
 /// <param name="codec"></param>
 /// <returns></returns>
 public static ServiceResultModel Encode(this IVariantEncoder codec,
                                         DiagnosticInfo diagnostics,
                                         StatusCode code, string operation, DiagnosticsModel config)
 {
     if (code == StatusCodes.Good)
     {
         return(null);
     }
     return(codec.Encode(new List <OperationResultModel> {
         new OperationResultModel {
             DiagnosticsInfo = diagnostics,
             Operation = operation,
             StatusCode = code
         }
     }, config));
 }
 /// <summary>
 /// Convert to service model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <returns></returns>
 public static ContentFilterElementModel Encode(this IVariantEncoder encoder,
                                                ContentFilterElement model)
 {
     if (model == null)
     {
         return(null);
     }
     return(new ContentFilterElementModel {
         FilterOperands = model.FilterOperands
                          .Select(e => e.Body)
                          .Cast <FilterOperand>()
                          .Select(o => encoder.Encode(o))
                          .ToList(),
         FilterOperator = model.FilterOperator.ToServiceType()
     });
 }
Ejemplo n.º 22
0
 /// <summary>
 /// Convert delete raw modified details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static VariantValue Encode(this IVariantEncoder codec, DeleteValuesDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.EndTime == null && details.StartTime == null)
     {
         throw new ArgumentException("Start time and end time cannot both be null", nameof(details));
     }
     return(codec.Encode(new ExtensionObject(new DeleteRawModifiedDetails {
         NodeId = NodeId.Null,
         EndTime = details.EndTime ?? DateTime.MinValue,
         StartTime = details.StartTime ?? DateTime.MinValue,
         IsDeleteModified = false
     })));
 }
 /// <summary>
 /// Convert to stack model
 /// </summary>
 /// <param name="model"></param>
 /// <param name="encoder"></param>
 /// <param name="noDefaultFilter"></param>
 /// <returns></returns>
 public static EventFilter Decode(this IVariantEncoder encoder, EventFilterModel model,
                                  bool noDefaultFilter = false)
 {
     if (model == null || !(model.SelectClauses?.Any() ?? false))
     {
         return(noDefaultFilter ? null : GetDefaultEventFilter());
     }
     return(new EventFilter {
         SelectClauses = new SimpleAttributeOperandCollection(
             model.SelectClauses == null ? Enumerable.Empty <SimpleAttributeOperand>() :
             model.SelectClauses.Select(c => c.ToStackModel(encoder.Context))),
         //
         // Per Part 4 only allow simple attribute operands in where clause
         // elements of event filters.
         //
         WhereClause = encoder.Decode(model.WhereClause, true)
     });
 }
        /// <summary>
        /// Convert to service model
        /// </summary>
        /// <param name="diagnostics"></param>
        /// <param name="config"></param>
        /// <param name="codec"></param>
        /// <returns></returns>
        public static ServiceResultModel Encode(this IVariantEncoder codec,
                                                List <OperationResultModel> diagnostics, DiagnosticsModel config)
        {
            if ((diagnostics?.Count ?? 0) == 0)
            {
                return(null); // All well
            }
            var result     = diagnostics.LastOrDefault(d => !d.TraceOnly);
            var statusCode = result?.StatusCode;

            return(new ServiceResultModel {
                // The last operation result is the one that caused the service to fail.
                StatusCode = statusCode?.Code,
                ErrorMessage = result?.DiagnosticsInfo?.AdditionalInfo ?? (statusCode == null ?
                                                                           null : StatusCode.LookupSymbolicId(statusCode.Value.CodeBits)),
                Diagnostics = codec.Write(diagnostics, config)
            });
        }
        /// <summary>
        /// Convert to service model
        /// </summary>
        /// <param name="model"></param>
        /// <param name="encoder"></param>
        /// <returns></returns>
        public static FilterOperandModel Encode(this IVariantEncoder encoder,
                                                FilterOperand model)
        {
            if (model == null)
            {
                return(null);
            }
            switch (model)
            {
            case ElementOperand elem:
                return(new FilterOperandModel {
                    Index = elem.Index
                });

            case LiteralOperand lit:
                return(new FilterOperandModel {
                    Value = encoder.Encode(lit.Value, out _)
                });

            case AttributeOperand attr:
                return(new FilterOperandModel {
                    NodeId = attr.NodeId.AsString(encoder.Context),
                    AttributeId = (NodeAttribute)attr.AttributeId,
                    BrowsePath = attr.BrowsePath.AsString(encoder.Context),
                    IndexRange = attr.IndexRange,
                    Alias = attr.Alias
                });

            case SimpleAttributeOperand sattr:
                return(new FilterOperandModel {
                    NodeId = sattr.TypeDefinitionId.AsString(encoder.Context),
                    AttributeId = (NodeAttribute)sattr.AttributeId,
                    BrowsePath = sattr.BrowsePath?
                                 .Select(p => p.AsString(encoder.Context))
                                 .ToArray(),
                    IndexRange = sattr.IndexRange
                });

            default:
                throw new NotSupportedException("Operand not supported");
            }
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Convert read processed details
        /// </summary>
        /// <param name="codec"></param>
        /// <param name="details"></param>
        /// <returns></returns>
        public static JToken Encode(this IVariantEncoder codec, ReadProcessedValuesDetailsModel details)
        {
            if (details == null)
            {
                throw new ArgumentNullException(nameof(details));
            }
            if (details.EndTime == null && details.StartTime == null)
            {
                throw new ArgumentException("Start time and end time cannot both be null", nameof(details));
            }
            var aggregate = details.AggregateTypeId?.ToNodeId(codec.Context);

            return(codec.Encode(new ExtensionObject(new ReadProcessedDetails {
                EndTime = details.EndTime ?? DateTime.MinValue,
                StartTime = details.StartTime ?? DateTime.MinValue,
                AggregateType = aggregate == null ? null : new NodeIdCollection(aggregate.YieldReturn()),
                ProcessingInterval = details.ProcessingInterval ?? 0,
                AggregateConfiguration = details.AggregateConfiguration.ToStackModel()
            }))); // Reapplies the aggregate namespace uri during encoding using the context's table
        }
 /// <summary>
 /// Convert read event details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, ReadEventsDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.EndTime == null && details.StartTime == null)
     {
         throw new ArgumentException("Start time and end time cannot both be null", nameof(details));
     }
     if ((details.StartTime == null || details.EndTime == null) && ((details.NumEvents ?? 0) == 0))
     {
         throw new ArgumentException("Value bound must be set", nameof(details.NumEvents));
     }
     return(codec.Encode(new ExtensionObject(new ReadEventDetails {
         EndTime = details.EndTime ?? DateTime.MinValue,
         StartTime = details.StartTime ?? DateTime.MinValue,
         Filter = details.Filter?.ToObject <EventFilter>() ?? new EventFilter(),
         NumValuesPerNode = details.NumEvents ?? 0
     })));
 }
Ejemplo n.º 28
0
 /// <summary>
 /// Convert read modified details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, ReadModifiedValuesDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.EndTime == null && details.StartTime == null)
     {
         throw new ArgumentException("Start time and end time cannot both be null", nameof(details));
     }
     if ((details.StartTime == null || details.EndTime == null) && ((details.NumValues ?? 0) == 0))
     {
         throw new ArgumentException("Value bound must be set", nameof(details.NumValues));
     }
     return(codec.Encode(new ExtensionObject(new ReadRawModifiedDetails {
         EndTime = details.EndTime ?? DateTime.MinValue,
         StartTime = details.StartTime ?? DateTime.MinValue,
         IsReadModified = true,
         NumValuesPerNode = details.NumValues ?? 0
     })));
 }
Ejemplo n.º 29
0
 /// <summary>
 /// Convert update event details
 /// </summary>
 /// <param name="codec"></param>
 /// <param name="details"></param>
 /// <returns></returns>
 public static JToken Encode(this IVariantEncoder codec, InsertEventsDetailsModel details)
 {
     if (details == null)
     {
         throw new ArgumentNullException(nameof(details));
     }
     if (details.Events == null || details.Events.Count == 0)
     {
         throw new ArgumentException(nameof(details.Events));
     }
     return(codec.Encode(new ExtensionObject(new UpdateEventDetails {
         NodeId = NodeId.Null,
         PerformInsertReplace = PerformUpdateType.Insert,
         Filter = codec.Decode(details.Filter),
         EventData = new HistoryEventFieldListCollection(details.Events
                                                         .Select(d => new HistoryEventFieldList {
             EventFields = new VariantCollection(d.EventFields
                                                 .Select(f => new Variant(new EncodeableJToken(f))))
         }))
     })));
 }
 /// <summary>
 /// Convert to service model
 /// </summary>
 /// <param name="statusCode"></param>
 /// <param name="diagnosticsInfo"></param>
 /// <param name="config"></param>
 /// <param name="codec"></param>
 /// <returns></returns>
 public static ServiceResultModel Encode(this IVariantEncoder codec,
                                         StatusCode?statusCode, DiagnosticInfo diagnosticsInfo = null,
                                         DiagnosticsModel config = null)
 {
     if ((statusCode?.Code ?? StatusCodes.Good) == StatusCodes.Good)
     {
         return(null); // All well
     }
     return(new ServiceResultModel {
         // The last operation result is the one that caused the service to fail.
         StatusCode = statusCode?.Code,
         ErrorMessage = diagnosticsInfo?.AdditionalInfo ?? (statusCode == null ?
                                                            null : StatusCode.LookupSymbolicId(statusCode.Value.CodeBits)),
         Diagnostics = config == null ? null : codec.Write(
             new List <OperationResultModel> {
             new OperationResultModel {
                 DiagnosticsInfo = diagnosticsInfo,
                 StatusCode = statusCode.Value
             }
         }, config)
     });
 }