/* ========================================================================
* 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
};
}
}
}