A.3 (worker IPC slice): proto SubscribeAlarms/Acknowledge/QueryActive commands + executor routing
Adds the worker-side IPC surface for the alarm subsystem so the gateway can drive the AlarmDispatcher across the named-pipe boundary. Adds four proto MxCommandKind values + matching command messages and two MxCommandReply payload variants: - SubscribeAlarmsCommand(subscription_expression) - UnsubscribeAlarmsCommand - AcknowledgeAlarmCommand(alarm_guid, comment, operator_user/node/domain/full_name) - QueryActiveAlarmsCommand(alarm_filter_prefix) - AcknowledgeAlarmReplyPayload(native_status) - QueryActiveAlarmsReplyPayload(repeated ActiveAlarmSnapshot snapshots) Worker plumbing: - New IAlarmCommandHandler interface + AlarmCommandHandler production impl. Lazy-creates an AlarmDispatcher (with a wnwrap-backed consumer by default) on the first SubscribeAlarms; routes Acknowledge / QueryActive / Unsubscribe through it. Idempotent under repeated Unsubscribe; rejects a second Subscribe without an intervening Unsubscribe; cleans up the consumer if the underlying Subscribe call throws. - MxAccessCommandExecutor: 4 new switch arms map MxCommandKind values to IAlarmCommandHandler calls. Acknowledge surfaces the AVEVA native status into both MxCommandReply.Hresult and the dedicated AcknowledgeAlarmReplyPayload.NativeStatus so gateway-side consumers can echo it without unpacking the outer envelope. Invalid GUIDs and missing payloads return InvalidRequest; handler exceptions return MxaccessFailure with the exception message in DiagnosticMessage. - MxAccessStaSession: new constructor overload accepts an alarmCommandHandlerFactory; it's invoked on the STA thread during StartAsync and the resulting handler is passed into the executor. ShutdownGracefullyAsync + Dispose tear it down on the STA before the data-side cleanup runs. Tests: 20 new unit tests covering AlarmCommandHandler lazy lifecycle (Subscribe/Unsubscribe/Acknowledge/Query/Dispose, error paths) and the executor's 4 alarm switch arms (OK/InvalidRequest/MxaccessFailure paths, hresult propagation, prefix filtering). Worker test suite total: 192 passed / 3 skipped (live probes) / 1 pre-existing structure-test fail (untouched). Deferred to next slice: gateway-side WorkerAlarmRpcDispatcher that replaces NotWiredAlarmRpcDispatcher, builds + sends these commands across the IPC, and unwraps the resulting MxCommandReply into AcknowledgeAlarmReply / ActiveAlarmSnapshot stream. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -88,6 +88,10 @@ message MxCommand {
|
||||
UnAdviseItemBulkCommand un_advise_item_bulk = 31;
|
||||
SubscribeBulkCommand subscribe_bulk = 32;
|
||||
UnsubscribeBulkCommand unsubscribe_bulk = 33;
|
||||
SubscribeAlarmsCommand subscribe_alarms = 34;
|
||||
UnsubscribeAlarmsCommand unsubscribe_alarms = 35;
|
||||
AcknowledgeAlarmCommand acknowledge_alarm_command = 36;
|
||||
QueryActiveAlarmsCommand query_active_alarms_command = 37;
|
||||
PingCommand ping = 100;
|
||||
GetSessionStateCommand get_session_state = 101;
|
||||
GetWorkerInfoCommand get_worker_info = 102;
|
||||
@@ -122,6 +126,10 @@ enum MxCommandKind {
|
||||
MX_COMMAND_KIND_UN_ADVISE_ITEM_BULK = 22;
|
||||
MX_COMMAND_KIND_SUBSCRIBE_BULK = 23;
|
||||
MX_COMMAND_KIND_UNSUBSCRIBE_BULK = 24;
|
||||
MX_COMMAND_KIND_SUBSCRIBE_ALARMS = 25;
|
||||
MX_COMMAND_KIND_UNSUBSCRIBE_ALARMS = 26;
|
||||
MX_COMMAND_KIND_ACKNOWLEDGE_ALARM = 27;
|
||||
MX_COMMAND_KIND_QUERY_ACTIVE_ALARMS = 28;
|
||||
MX_COMMAND_KIND_PING = 100;
|
||||
MX_COMMAND_KIND_GET_SESSION_STATE = 101;
|
||||
MX_COMMAND_KIND_GET_WORKER_INFO = 102;
|
||||
@@ -263,6 +271,42 @@ message SubscribeBulkCommand {
|
||||
repeated string tag_addresses = 2;
|
||||
}
|
||||
|
||||
// Subscribe the worker's alarm consumer to an AVEVA alarm provider.
|
||||
// Subscription expression follows the canonical
|
||||
// `\\<machine>\Galaxy!<area>` format (literal "Galaxy" provider). The
|
||||
// worker spins up a wnwrapConsumer-backed subscription on its STA on
|
||||
// first call; subsequent calls are an error (use UnsubscribeAlarms then
|
||||
// SubscribeAlarms to reconfigure).
|
||||
message SubscribeAlarmsCommand {
|
||||
string subscription_expression = 1;
|
||||
}
|
||||
|
||||
// Tear down the worker's alarm consumer. No-op if no subscription is
|
||||
// currently active.
|
||||
message UnsubscribeAlarmsCommand {
|
||||
}
|
||||
|
||||
// Acknowledge a single alarm by its GUID. Operator identity fields are
|
||||
// recorded atomically with the ack transition in the alarm-history log.
|
||||
// The reply's hresult / native_status surfaces AVEVA's
|
||||
// AlarmAckByGUID return code.
|
||||
message AcknowledgeAlarmCommand {
|
||||
// Canonical 8-4-4-4-12 GUID string (e.g. "BCC47053-9542-4D65-BDAA-BCDEA6A32A73").
|
||||
string alarm_guid = 1;
|
||||
string comment = 2;
|
||||
string operator_user = 3;
|
||||
string operator_node = 4;
|
||||
string operator_domain = 5;
|
||||
string operator_full_name = 6;
|
||||
}
|
||||
|
||||
// Snapshot the currently-active alarm set. Optional filter prefix scopes
|
||||
// the snapshot to alarms whose alarm_full_reference starts with the
|
||||
// supplied string (matches QueryActiveAlarmsRequest.alarm_filter_prefix).
|
||||
message QueryActiveAlarmsCommand {
|
||||
string alarm_filter_prefix = 1;
|
||||
}
|
||||
|
||||
message UnsubscribeBulkCommand {
|
||||
int32 server_handle = 1;
|
||||
repeated int32 item_handles = 2;
|
||||
@@ -314,6 +358,8 @@ message MxCommandReply {
|
||||
BulkSubscribeReply un_advise_item_bulk = 31;
|
||||
BulkSubscribeReply subscribe_bulk = 32;
|
||||
BulkSubscribeReply unsubscribe_bulk = 33;
|
||||
AcknowledgeAlarmReplyPayload acknowledge_alarm = 34;
|
||||
QueryActiveAlarmsReplyPayload query_active_alarms = 35;
|
||||
SessionStateReply session_state = 100;
|
||||
WorkerInfoReply worker_info = 101;
|
||||
DrainEventsReply drain_events = 102;
|
||||
@@ -379,6 +425,24 @@ message DrainEventsReply {
|
||||
repeated MxEvent events = 1;
|
||||
}
|
||||
|
||||
// Reply payload for AcknowledgeAlarmCommand. Surfaces AVEVA's native
|
||||
// AlarmAckByGUID return code; 0 means success. The MxCommandReply's
|
||||
// hresult field carries the same value and is preferred for protocol
|
||||
// consumers — this payload exists so the gateway-side
|
||||
// WorkerAlarmRpcDispatcher can echo native_status into
|
||||
// AcknowledgeAlarmReply.hresult without unpacking the outer envelope.
|
||||
message AcknowledgeAlarmReplyPayload {
|
||||
int32 native_status = 1;
|
||||
}
|
||||
|
||||
// Reply payload for QueryActiveAlarmsCommand. The worker walks
|
||||
// IMxAccessAlarmConsumer.SnapshotActiveAlarms and packs each record as
|
||||
// an ActiveAlarmSnapshot proto for the gateway-side ConditionRefresh
|
||||
// stream.
|
||||
message QueryActiveAlarmsReplyPayload {
|
||||
repeated ActiveAlarmSnapshot snapshots = 1;
|
||||
}
|
||||
|
||||
message MxEvent {
|
||||
MxEventFamily family = 1;
|
||||
string session_id = 2;
|
||||
|
||||
Reference in New Issue
Block a user