feat: add StreamRelayActor bridging Akka events to gRPC proto channel
This commit is contained in:
90
src/ScadaLink.Communication/Actors/StreamRelayActor.cs
Normal file
90
src/ScadaLink.Communication/Actors/StreamRelayActor.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System.Threading.Channels;
|
||||
using Akka.Actor;
|
||||
using Akka.Event;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ScadaLink.Commons.Messages.Streaming;
|
||||
using ScadaLink.Communication.Grpc;
|
||||
using AlarmState = ScadaLink.Commons.Types.Enums.AlarmState;
|
||||
|
||||
namespace ScadaLink.Communication.Actors;
|
||||
|
||||
/// <summary>
|
||||
/// Lightweight relay actor that bridges Akka domain events (AttributeValueChanged,
|
||||
/// AlarmStateChanged) to a System.Threading.Channels.Channel of protobuf SiteStreamEvent
|
||||
/// messages. The gRPC server method reads from the channel's reader side.
|
||||
/// </summary>
|
||||
public class StreamRelayActor : ReceiveActor
|
||||
{
|
||||
private readonly ILoggingAdapter _log = Context.GetLogger();
|
||||
private readonly string _correlationId;
|
||||
private readonly ChannelWriter<SiteStreamEvent> _channelWriter;
|
||||
|
||||
public StreamRelayActor(string correlationId, ChannelWriter<SiteStreamEvent> channelWriter)
|
||||
{
|
||||
_correlationId = correlationId;
|
||||
_channelWriter = channelWriter;
|
||||
|
||||
Receive<AttributeValueChanged>(HandleAttributeValueChanged);
|
||||
Receive<AlarmStateChanged>(HandleAlarmStateChanged);
|
||||
}
|
||||
|
||||
private void HandleAttributeValueChanged(AttributeValueChanged msg)
|
||||
{
|
||||
var protoEvent = new SiteStreamEvent
|
||||
{
|
||||
CorrelationId = _correlationId,
|
||||
AttributeChanged = new AttributeValueUpdate
|
||||
{
|
||||
InstanceUniqueName = msg.InstanceUniqueName,
|
||||
AttributePath = msg.AttributePath,
|
||||
AttributeName = msg.AttributeName,
|
||||
Value = msg.Value?.ToString() ?? "",
|
||||
Quality = MapQuality(msg.Quality),
|
||||
Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp)
|
||||
}
|
||||
};
|
||||
|
||||
WriteToChannel(protoEvent);
|
||||
}
|
||||
|
||||
private void HandleAlarmStateChanged(AlarmStateChanged msg)
|
||||
{
|
||||
var protoEvent = new SiteStreamEvent
|
||||
{
|
||||
CorrelationId = _correlationId,
|
||||
AlarmChanged = new AlarmStateUpdate
|
||||
{
|
||||
InstanceUniqueName = msg.InstanceUniqueName,
|
||||
AlarmName = msg.AlarmName,
|
||||
State = MapAlarmState(msg.State),
|
||||
Priority = msg.Priority,
|
||||
Timestamp = Timestamp.FromDateTimeOffset(msg.Timestamp)
|
||||
}
|
||||
};
|
||||
|
||||
WriteToChannel(protoEvent);
|
||||
}
|
||||
|
||||
private void WriteToChannel(SiteStreamEvent protoEvent)
|
||||
{
|
||||
if (!_channelWriter.TryWrite(protoEvent))
|
||||
{
|
||||
_log.Warning("Channel full, dropping event for correlation {0}", _correlationId);
|
||||
}
|
||||
}
|
||||
|
||||
private static Quality MapQuality(string quality) => quality switch
|
||||
{
|
||||
"Good" => Quality.Good,
|
||||
"Uncertain" => Quality.Uncertain,
|
||||
"Bad" => Quality.Bad,
|
||||
_ => Quality.Unspecified
|
||||
};
|
||||
|
||||
private static AlarmStateEnum MapAlarmState(AlarmState state) => state switch
|
||||
{
|
||||
AlarmState.Normal => AlarmStateEnum.AlarmStateNormal,
|
||||
AlarmState.Active => AlarmStateEnum.AlarmStateActive,
|
||||
_ => AlarmStateEnum.AlarmStateUnspecified
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user