/* ========================================================================
* 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;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Opc.Ua.Client.Subscriptions.MonitoredItems;
namespace Opc.Ua.Client.Subscriptions
{
///
///
/// Data value change observed on a monitored item during the V2
/// publish dispatch.
///
///
/// Lifetime note (pooled notifications): when the V2 subscription
/// manager has
/// enabled, the underlying MonitoredItemNotification that
/// supplied this struct's fields is recycled back to its
/// activator pool after the handler returns. This struct's
/// references (, )
/// project the inner DataValue / DiagnosticInfo
/// instances directly — those are not themselves pooled (out of
/// scope), so a handler may safely copy this struct by value and
/// continue using after the call. Pool-aware
/// projection audit: confirmed safe — no reference to a pooled
/// instance is surfaced.
///
///
///
///
///
public record struct DataValueChange(IMonitoredItem? MonitoredItem,
DataValue Value, DiagnosticInfo? DiagnosticInfo);
///
///
/// Event notification observed during the V2 publish dispatch.
///
///
/// Lifetime note (pooled notifications): when the V2 subscription
/// manager has
/// enabled, the underlying EventFieldList is recycled back
/// to its activator pool after the handler returns. The
/// property is captured by value as an
/// wrapping the original event-fields
/// array. Arrays are not pooled in this design (out of scope), so
/// the captured backing array survives the recycle. Pool-aware
/// projection audit: confirmed safe — no reference to a pooled
/// instance is surfaced.
///
///
///
///
public record struct EventNotification(IMonitoredItem? MonitoredItem,
ArrayOf Fields);
///
/// Notification handler
///
public interface ISubscriptionNotificationHandler
{
///
/// Process data change notification
///
///
///
///
///
///
///
///
ValueTask OnDataChangeNotificationAsync(ISubscription subscription,
uint sequenceNumber, DateTime publishTime,
ReadOnlyMemory notification,
PublishState publishStateMask, IReadOnlyList stringTable);
///
/// Process event notification
///
///
///
///
///
///
///
///
ValueTask OnEventDataNotificationAsync(ISubscription subscription,
uint sequenceNumber, DateTime publishTime,
ReadOnlyMemory notification,
PublishState publishStateMask, IReadOnlyList stringTable);
///
/// Process keep alive notification
///
///
///
///
///
///
ValueTask OnKeepAliveNotificationAsync(ISubscription subscription,
uint sequenceNumber, DateTime publishTime,
PublishState publishStateMask);
///
/// Surface a transition in the subscription's lifecycle
/// () or publish-side status
/// (). Fires from the V2
/// engine on:
///
/// - Lifecycle transitions —
/// ,
/// ,
/// ,
/// .
/// - Publish-side transitions —
/// (a gap was detected and
/// a republish was issued),
/// (a missing message arrived or publishing resumed after a
/// stop), (the
/// subscription was taken over on a different session via
/// TransferSubscriptions).
///
///
/// Handlers that need derived state (publishing stopped, last
/// keep-alive, republish-pending, etc.) maintain it themselves
/// by responding to this callback — V2 is handler-centric and
/// the engine deliberately does not expose those as polled
/// properties on .
///
///
/// Per-subscription delivery ordering is guaranteed by the V2
/// prioritized publish-ack channel: data / event / keep-alive
/// callbacks for a given subscription always fire in
/// publish-sequence order. State-change callbacks interleave
/// with the notification stream at the moment the transition
/// is observed.
///
///
///
///
///
///
ValueTask OnSubscriptionStateChangedAsync(ISubscription subscription,
SubscriptionState state, PublishState publishStateMask,
CancellationToken ct = default);
}
}