using ZB.MOM.WW.OtOpcUa.Commons.Messages.Alerts; using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers; using ZB.MOM.WW.OtOpcUa.Commons.Messages.Logging; using ZB.MOM.WW.OtOpcUa.Commons.Protos.Telemetry.V1; namespace ZB.MOM.WW.OtOpcUa.ControlPlane.Telemetry; /// /// Central-side projection of a wire envelope back onto its domain /// record (per-cluster mesh Phase 5). The exact reverse of TelemetryProtoMapNode: it /// transcribes every proto field onto the matching domain field and selects the domain record from /// the envelope's oneof arm. /// /// /// /// Timestamp presence is honoured. A proto google.protobuf.Timestamp field is a /// message: when the node left it unset (a null nullable-DateTime on the domain side) the /// generated property is , so the nullable domain fields map via /// ?.ToDateTime() and an absent Timestamp becomes . The /// non-nullable domain fields (published / sampled / transition timestamps) are always set by /// the node mapper, so they map via a direct .ToDateTime() (which yields a /// value). /// /// /// optional-string presence is honoured. A proto3 optional string that the node /// left unset reads back as (via the generated Has… presence), /// distinguishing null from the empty string; likewise the optional bool /// historize_to_aveva round-trips its three states (null / true / false). /// /// public static class TelemetryProtoMapCentral { /// /// Projects a wire onto its domain record, selecting the type from /// the populated oneof arm. This switch is the coverage guard: every /// value has an arm here, and an unset (or a /// future unmapped) case throws so adding a fifth oneof case /// without a converter fails the coverage test. /// /// The wire envelope to project. /// The domain record for the populated arm. /// is null. /// The envelope carries no handled oneof arm. public static object MapEvent(TelemetryEvent evt) { ArgumentNullException.ThrowIfNull(evt); return evt.EventCase switch { TelemetryEvent.EventOneofCase.AlarmTransition => ToAlarm(evt.AlarmTransition), TelemetryEvent.EventOneofCase.ScriptLog => ToScript(evt.ScriptLog), TelemetryEvent.EventOneofCase.DriverHealth => ToHealth(evt.DriverHealth), TelemetryEvent.EventOneofCase.DriverResilience => ToResilience(evt.DriverResilience), _ => throw new NotSupportedException( $"TelemetryEvent carries no handled oneof arm (EventCase = {evt.EventCase})."), }; } /// Projects an onto an . /// The proto sub-message. /// The domain record. public static AlarmTransitionEvent ToAlarm(AlarmTransition msg) { ArgumentNullException.ThrowIfNull(msg); return new AlarmTransitionEvent( AlarmId: msg.AlarmId, EquipmentPath: msg.EquipmentPath, AlarmName: msg.AlarmName, TransitionKind: msg.TransitionKind, Severity: msg.Severity, Message: msg.Message, User: msg.User, TimestampUtc: msg.TimestampUtc.ToDateTime(), AlarmTypeName: msg.AlarmTypeName, Comment: msg.HasComment ? msg.Comment : null, HistorizeToAveva: msg.HasHistorizeToAveva ? msg.HistorizeToAveva : null, ReferencingEquipmentPaths: msg.ReferencingEquipmentPaths.ToList()); } /// Projects a onto a . /// The proto sub-message. /// The domain record. public static ScriptLogEntry ToScript(ScriptLog msg) { ArgumentNullException.ThrowIfNull(msg); return new ScriptLogEntry( ScriptId: msg.ScriptId, Level: msg.Level, Message: msg.Message, TimestampUtc: msg.TimestampUtc.ToDateTime(), VirtualTagId: msg.HasVirtualTagId ? msg.VirtualTagId : null, AlarmId: msg.HasAlarmId ? msg.AlarmId : null, EquipmentId: msg.HasEquipmentId ? msg.EquipmentId : null); } /// Projects a onto a . /// The proto sub-message. /// The domain record. public static DriverHealthChanged ToHealth(DriverHealth msg) { ArgumentNullException.ThrowIfNull(msg); return new DriverHealthChanged( ClusterId: msg.ClusterId, DriverInstanceId: msg.DriverInstanceId, State: msg.State, LastSuccessfulReadUtc: msg.LastSuccessfulReadUtc?.ToDateTime(), LastError: msg.HasLastError ? msg.LastError : null, ErrorCount5Min: msg.ErrorCount5Min, PublishedUtc: msg.PublishedUtc.ToDateTime()); } /// Projects a onto a . /// The proto sub-message. /// The domain record. public static DriverResilienceStatusChanged ToResilience(DriverResilienceStatus msg) { ArgumentNullException.ThrowIfNull(msg); return new DriverResilienceStatusChanged( DriverInstanceId: msg.DriverInstanceId, HostName: msg.HostName, BreakerOpen: msg.BreakerOpen, ConsecutiveFailures: msg.ConsecutiveFailures, CurrentInFlight: msg.CurrentInFlight, LastBreakerOpenUtc: msg.LastBreakerOpenUtc?.ToDateTime(), LastSampledUtc: msg.LastSampledUtc.ToDateTime(), PublishedUtc: msg.PublishedUtc.ToDateTime()); } }