150 lines
6.5 KiB
C#
150 lines
6.5 KiB
C#
using System;
|
|
using ZB.MOM.WW.MxGateway.Contracts.Proto;
|
|
|
|
namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
|
|
|
|
/// <summary>
|
|
/// Sink for native MxAccess alarm transitions. Bridges
|
|
/// <see cref="WnWrapAlarmConsumer"/> to the worker's event queue,
|
|
/// producing <see cref="OnAlarmTransitionEvent"/> messages via
|
|
/// <see cref="MxAccessEventMapper.CreateOnAlarmTransition"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// <see cref="AlarmDispatcher"/> owns the wire-up: it constructs the
|
|
/// consumer/sink pair, calls <see cref="Attach"/> to propagate the
|
|
/// session id, and subscribes the consumer's
|
|
/// <see cref="IMxAccessAlarmConsumer.AlarmTransitionEmitted"/> event
|
|
/// so each decoded transition reaches <see cref="EnqueueTransition"/>.
|
|
/// The <see cref="Attach"/> method here carries only the session id —
|
|
/// the alarm path needs no COM-event subscription of its own because
|
|
/// the consumer already polls and raises transition events. The
|
|
/// captured payload schema is described in
|
|
/// <c>docs/AlarmClientDiscovery.md</c> "Option A — captured".
|
|
/// </para>
|
|
/// </remarks>
|
|
public sealed class MxAccessAlarmEventSink : IMxAccessEventSink
|
|
{
|
|
private readonly MxAccessEventMapper eventMapper;
|
|
private readonly MxAccessEventQueue eventQueue;
|
|
private string sessionId = string.Empty;
|
|
private bool attached;
|
|
|
|
/// <summary>Initializes a new instance of the MxAccessAlarmEventSink class with default dependencies.</summary>
|
|
public MxAccessAlarmEventSink()
|
|
: this(new MxAccessEventQueue(), new MxAccessEventMapper())
|
|
{
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the MxAccessAlarmEventSink class.</summary>
|
|
/// <param name="eventQueue">Queue for buffering converted alarm events.</param>
|
|
/// <param name="eventMapper">Converter for alarm transitions to protobuf format.</param>
|
|
public MxAccessAlarmEventSink(
|
|
MxAccessEventQueue eventQueue,
|
|
MxAccessEventMapper eventMapper)
|
|
{
|
|
this.eventQueue = eventQueue ?? throw new ArgumentNullException(nameof(eventQueue));
|
|
this.eventMapper = eventMapper ?? throw new ArgumentNullException(nameof(eventMapper));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Attach(object mxAccessComObject, string sessionId)
|
|
{
|
|
if (mxAccessComObject is null) throw new ArgumentNullException(nameof(mxAccessComObject));
|
|
this.sessionId = sessionId ?? string.Empty;
|
|
|
|
// The alarm path needs no COM-event subscription here: the wnwrap
|
|
// consumer is polled by the worker's STA and raises transition events
|
|
// that AlarmDispatcher routes into EnqueueTransition. Attach only
|
|
// records the session id stamped onto every emitted MxEvent.
|
|
attached = true;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Detach()
|
|
{
|
|
if (!attached) return;
|
|
attached = false;
|
|
sessionId = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enqueues a decoded alarm transition. The COM-side delegate registered
|
|
/// in <see cref="Attach"/> calls this method once it pulls the alarm
|
|
/// fields out of the MxAccess event payload. Exposed internal so unit
|
|
/// tests can drive the proto build path without a real COM event
|
|
/// source.
|
|
/// </summary>
|
|
/// <param name="alarmFullReference">The fully qualified alarm object reference.</param>
|
|
/// <param name="sourceObjectReference">The object that sourced the alarm.</param>
|
|
/// <param name="alarmTypeName">The alarm type name.</param>
|
|
/// <param name="transitionKind">The kind of alarm transition.</param>
|
|
/// <param name="severity">The alarm severity level.</param>
|
|
/// <param name="originalRaiseTimestampUtc">The original alarm raise timestamp in UTC, if available.</param>
|
|
/// <param name="transitionTimestampUtc">The timestamp of this transition in UTC.</param>
|
|
/// <param name="operatorUser">The user who performed the operation, if applicable.</param>
|
|
/// <param name="operatorComment">The operator's comment, if any.</param>
|
|
/// <param name="category">The alarm category.</param>
|
|
/// <param name="description">The alarm description.</param>
|
|
/// <param name="degraded">
|
|
/// <see langword="true"/> when the transition was synthesized by the
|
|
/// subtag-provider fallback rather than the native alarmmgr path.
|
|
/// Defaults to <see langword="false"/> so existing alarmmgr callers
|
|
/// compile unchanged and stay on the parity (alarmmgr) path.
|
|
/// </param>
|
|
internal void EnqueueTransition(
|
|
string alarmFullReference,
|
|
string sourceObjectReference,
|
|
string alarmTypeName,
|
|
AlarmTransitionKind transitionKind,
|
|
int severity,
|
|
DateTime? originalRaiseTimestampUtc,
|
|
DateTime transitionTimestampUtc,
|
|
string operatorUser,
|
|
string operatorComment,
|
|
string category,
|
|
string description,
|
|
bool degraded = false)
|
|
{
|
|
try
|
|
{
|
|
// Degraded transitions come from the subtag fallback; the native
|
|
// alarmmgr (wnwrap) path stays degraded=false / ALARMMGR for parity.
|
|
AlarmProviderMode sourceProvider = degraded
|
|
? AlarmProviderMode.Subtag
|
|
: AlarmProviderMode.Alarmmgr;
|
|
MxEvent mxEvent = eventMapper.CreateOnAlarmTransition(
|
|
sessionId,
|
|
alarmFullReference,
|
|
sourceObjectReference,
|
|
alarmTypeName,
|
|
transitionKind,
|
|
severity,
|
|
originalRaiseTimestampUtc,
|
|
transitionTimestampUtc,
|
|
operatorUser,
|
|
operatorComment,
|
|
category,
|
|
description,
|
|
statuses: null,
|
|
degraded: degraded,
|
|
sourceProvider: sourceProvider);
|
|
eventQueue.Enqueue(mxEvent);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
eventQueue.RecordFault(new WorkerFault
|
|
{
|
|
Category = WorkerFaultCategory.MxaccessEventConversionFailed,
|
|
ExceptionType = exception.GetType().FullName ?? string.Empty,
|
|
DiagnosticMessage = $"{exception.GetType().FullName}: HRESULT 0x{unchecked((uint)exception.HResult):X8}",
|
|
ProtocolStatus = new ProtocolStatus
|
|
{
|
|
Code = ProtocolStatusCode.MxaccessFailure,
|
|
Message = "MXAccess alarm event conversion failed.",
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|