d6db0ff40d
AlarmCommandHandler -> AlarmDispatcher -> IAlarmAckWriter: the dispatcher resolves the ack item through the consumer and the writer authenticates the operator and writes the comment. The executor builds AlarmAckOperator from operator_user/domain/password, maps AlarmAckOutcome to the reply (Applied/Unconfirmed Ok, AlarmNotFound/NotAckable InvalidRequest, AuthenticationFailed/WriteRejected MxaccessFailure) and reports escaping exceptions by type and HRESULT only, so operator_password cannot leak. Removes the inert managed/WNAL alarm-client ack path. Claude-Session: https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
86 lines
4.5 KiB
C#
86 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using ZB.MOM.WW.MxGateway.Contracts.Proto;
|
|
|
|
namespace ZB.MOM.WW.MxGateway.Worker.MxAccess;
|
|
|
|
/// <summary>
|
|
/// Per-session interface routing the worker's alarm IPC commands —
|
|
/// <c>SubscribeAlarmsCommand</c>, <c>AcknowledgeAlarmCommand</c>,
|
|
/// <c>UpdateAlarmWatchListCommand</c>, <c>QueryActiveAlarmsCommand</c>,
|
|
/// <c>UnsubscribeAlarmsCommand</c> —
|
|
/// to the underlying <see cref="AlarmDispatcher"/>. Production binding
|
|
/// is <see cref="AlarmCommandHandler"/>; tests substitute a fake.
|
|
/// </summary>
|
|
public interface IAlarmCommandHandler : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Begin an alarm subscription from the supplied command. The command's
|
|
/// <see cref="SubscribeAlarmsCommand.ForcedMode"/> and
|
|
/// <see cref="SubscribeAlarmsCommand.WatchList"/> select the consumer:
|
|
/// alarmmgr-only (the default), subtag-only, or an auto-failover
|
|
/// composite over both.
|
|
/// </summary>
|
|
/// <param name="command">The full SubscribeAlarms command.</param>
|
|
/// <param name="sessionId">The session identifier.</param>
|
|
void Subscribe(SubscribeAlarmsCommand command, string sessionId);
|
|
|
|
/// <summary>
|
|
/// Replace the active auto-failover subscription's subtag standby
|
|
/// targets without restarting its primary provider.
|
|
/// </summary>
|
|
/// <param name="watchList">The complete replacement watch list.</param>
|
|
void UpdateWatchList(IReadOnlyList<AlarmSubtagTarget> watchList);
|
|
|
|
/// <summary>Tear down the active subscription. No-op if not subscribed.</summary>
|
|
void Unsubscribe();
|
|
|
|
/// <summary>Acknowledges an alarm by GUID as <paramref name="ackOperator"/>.</summary>
|
|
/// <param name="alarmGuid">The alarm GUID.</param>
|
|
/// <param name="comment">The acknowledgement comment written to the alarm's ack item.</param>
|
|
/// <param name="ackOperator">The operator to authenticate as (credential-sensitive).</param>
|
|
/// <returns>The acknowledgement outcome.</returns>
|
|
AlarmAckResult Acknowledge(Guid alarmGuid, string comment, AlarmAckOperator ackOperator);
|
|
|
|
/// <summary>Acknowledges an alarm by name/provider/group as <paramref name="ackOperator"/>.</summary>
|
|
/// <param name="alarmName">The alarm (tag) name.</param>
|
|
/// <param name="providerName">The provider name.</param>
|
|
/// <param name="groupName">The group name.</param>
|
|
/// <param name="comment">The acknowledgement comment written to the alarm's ack item.</param>
|
|
/// <param name="ackOperator">The operator to authenticate as (credential-sensitive).</param>
|
|
/// <returns>The acknowledgement outcome.</returns>
|
|
AlarmAckResult AcknowledgeByName(string alarmName, string providerName, string groupName, string comment, AlarmAckOperator ackOperator);
|
|
|
|
/// <summary>
|
|
/// Snapshot the currently-active alarm set, optionally scoped to a
|
|
/// prefix matched against <c>AlarmFullReference</c>.
|
|
/// </summary>
|
|
/// <param name="alarmFilterPrefix">Optional prefix to filter alarms by.</param>
|
|
/// <param name="snapshotTruncated">
|
|
/// Receives whether the fetch behind the snapshot hit the per-fetch cap,
|
|
/// so the set may omit active alarms. Carried out alongside the records
|
|
/// rather than read from a separate property, both so the pair comes from
|
|
/// one atomic consumer read and because it is the only carrier left once
|
|
/// <paramref name="alarmFilterPrefix"/> (or an empty galaxy) filters the
|
|
/// records down to none. Never assigned when there is no active
|
|
/// subscription — that case throws rather than reporting an empty,
|
|
/// never-capped set, so a query issued before <c>SubscribeAlarms</c> is a
|
|
/// caller error and not a silent all-clear.
|
|
/// </param>
|
|
/// <returns>The currently active alarms matching the filter.</returns>
|
|
/// <exception cref="InvalidOperationException">
|
|
/// Thrown when there is no active subscription.
|
|
/// </exception>
|
|
IReadOnlyList<ActiveAlarmSnapshot> QueryActive(string? alarmFilterPrefix, out bool snapshotTruncated);
|
|
|
|
/// <summary>
|
|
/// Drives a single poll of the underlying alarm consumer on the
|
|
/// caller's thread. This is a no-op when there is no active
|
|
/// subscription. In production the caller is the worker's STA
|
|
/// (marshalled via <c>StaRuntime.InvokeAsync</c>), which satisfies
|
|
/// the <c>ThreadingModel=Apartment</c> requirement of
|
|
/// <c>wwAlarmConsumerClass</c>.
|
|
/// </summary>
|
|
void PollOnce();
|
|
}
|