/* ======================================================================== * Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; namespace Opc.Ua.Client.Subscriptions.MonitoredItems { /// /// Immutable snapshot of a V2 's /// configuration plus the server-side identifiers needed to take /// over the item on a transferred subscription. /// /// /// /// Produced by and consumed by /// . /// Per-item runtime values (filter result, last sample, /// current sampling interval) are intentionally not captured — the /// transfer path re-binds them from the server via /// GetMonitoredItems, and the recreate path mints fresh ones. /// /// /// The snapshot is itself an via the /// source generator. The fields /// carried on the wire are simple primitives (e.g. /// milliseconds for durations, for enums); the /// non-encoded projection exposes a /// consumer-friendly built from /// those surrogate fields. The companion /// factory does the inverse mapping at /// time. /// /// [DataType(Namespace = Namespaces.OpcUaXsd)] public sealed partial record class MonitoredItemStateSnapshot { /// /// Stable, manager-unique name (the lookup key used by /// /// and by ). /// [DataTypeField(Order = 1)] public partial string Name { get; init; } /// /// Client-assigned handle at snapshot time. Used by the /// transfer leg of restore to re-bind to the server-side /// monitored item via the saved ; /// ignored by the recreate leg (the V2 state machine mints a /// fresh client handle). /// [DataTypeField(Order = 2)] public partial uint ClientHandle { get; init; } /// /// Server-assigned monitored item id, or 0 if the item /// had not been created on the server yet. Used by the /// transfer leg to match this item via the /// GetMonitoredItems server-handle table. /// [DataTypeField(Order = 3)] public partial uint ServerId { get; init; } /// /// Client handle of the monitored item that triggers this item, /// or 0 if not triggered. /// [DataTypeField(Order = 4)] public partial uint TriggeringItemClientHandle { get; init; } /// /// surrogate. /// [DataTypeField(Order = 10)] public partial uint Order { get; init; } /// /// surrogate. /// Null sentinel: . /// [DataTypeField(Order = 11)] public partial NodeId StartNodeId { get; init; } /// /// surrogate. /// [DataTypeField(Order = 12)] public partial uint TimestampsToReturn { get; init; } /// /// surrogate. /// [DataTypeField(Order = 13)] public partial uint AttributeId { get; init; } /// /// surrogate. /// [DataTypeField(Order = 14)] public partial string IndexRange { get; init; } /// /// surrogate. Null /// sentinel: . /// [DataTypeField(Order = 15)] public partial QualifiedName Encoding { get; init; } /// /// surrogate. /// [DataTypeField(Order = 16)] public partial uint MonitoringMode { get; init; } /// /// as whole /// milliseconds. /// [DataTypeField(Order = 17)] public partial int SamplingIntervalMs { get; init; } /// /// surrogate. /// Polymorphic; encoded via so the /// concrete / /// / /// type round-trips. /// [DataTypeField(Order = 18, StructureHandling = StructureHandling.ExtensionObject)] public partial MonitoringFilter? Filter { get; init; } /// /// surrogate. /// [DataTypeField(Order = 19)] public partial uint QueueSize { get; init; } /// /// surrogate. /// [DataTypeField(Order = 20)] public partial bool DiscardOldest { get; init; } /// /// surrogate. /// [DataTypeField(Order = 21)] public partial bool AutoSetQueueSize { get; init; } /// /// Project the encoded surrogate fields back into a live /// . Not serialized. /// public MonitoredItemOptions ToOptions() { return new MonitoredItemOptions { Order = Order, StartNodeId = StartNodeId.IsNull ? NodeId.Null : StartNodeId, TimestampsToReturn = (TimestampsToReturn)TimestampsToReturn, AttributeId = AttributeId, IndexRange = IndexRange, Encoding = Encoding.IsNull ? null : Encoding, MonitoringMode = (MonitoringMode)MonitoringMode, SamplingInterval = TimeSpan.FromMilliseconds(SamplingIntervalMs), Filter = Filter, QueueSize = QueueSize, DiscardOldest = DiscardOldest, AutoSetQueueSize = AutoSetQueueSize }; } /// /// Construct a from a /// live + the captured /// server-side state. /// public static MonitoredItemStateSnapshot AsOptions( string name, MonitoredItemOptions options, uint clientHandle, uint serverId, uint triggeringItemClientHandle) { if (options == null) { throw new ArgumentNullException(nameof(options)); } return new MonitoredItemStateSnapshot { Name = name ?? string.Empty, ClientHandle = clientHandle, ServerId = serverId, TriggeringItemClientHandle = triggeringItemClientHandle, Order = options.Order, StartNodeId = options.StartNodeId.IsNull ? NodeId.Null : options.StartNodeId, TimestampsToReturn = (uint)options.TimestampsToReturn, AttributeId = options.AttributeId, IndexRange = options.IndexRange ?? string.Empty, Encoding = options.Encoding.HasValue && !options.Encoding.Value.IsNull ? options.Encoding.Value : QualifiedName.Null, MonitoringMode = (uint)options.MonitoringMode, SamplingIntervalMs = (int)Math.Min( int.MaxValue, Math.Max(0, options.SamplingInterval.TotalMilliseconds)), Filter = options.Filter, QueueSize = options.QueueSize, DiscardOldest = options.DiscardOldest, AutoSetQueueSize = options.AutoSetQueueSize }; } } }