112 lines
4.7 KiB
C#
112 lines
4.7 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using MessagePack;
|
|
using Serilog;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host.Backend;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Shared;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Shared.Contracts;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host.Ipc;
|
|
|
|
/// <summary>
|
|
/// Real FOCAS frame handler. Deserializes each request DTO, delegates to
|
|
/// <see cref="IFocasBackend"/>, re-serializes the response. The backend owns the
|
|
/// Fwlib32 handle + STA thread — the handler is pure dispatch.
|
|
/// </summary>
|
|
public sealed class FwlibFrameHandler : IFrameHandler
|
|
{
|
|
private readonly IFocasBackend _backend;
|
|
private readonly ILogger _logger;
|
|
|
|
public FwlibFrameHandler(IFocasBackend backend, ILogger logger)
|
|
{
|
|
_backend = backend ?? throw new ArgumentNullException(nameof(backend));
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
public async Task HandleAsync(FocasMessageKind kind, byte[] body, FrameWriter writer, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
switch (kind)
|
|
{
|
|
case FocasMessageKind.Heartbeat:
|
|
{
|
|
var hb = MessagePackSerializer.Deserialize<Heartbeat>(body);
|
|
await writer.WriteAsync(FocasMessageKind.HeartbeatAck,
|
|
new HeartbeatAck
|
|
{
|
|
MonotonicTicks = hb.MonotonicTicks,
|
|
HostUtcUnixMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
|
}, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.OpenSessionRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<OpenSessionRequest>(body);
|
|
var resp = await _backend.OpenSessionAsync(req, ct).ConfigureAwait(false);
|
|
await writer.WriteAsync(FocasMessageKind.OpenSessionResponse, resp, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.CloseSessionRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<CloseSessionRequest>(body);
|
|
await _backend.CloseSessionAsync(req, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.ReadRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<ReadRequest>(body);
|
|
var resp = await _backend.ReadAsync(req, ct).ConfigureAwait(false);
|
|
await writer.WriteAsync(FocasMessageKind.ReadResponse, resp, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.WriteRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<WriteRequest>(body);
|
|
var resp = await _backend.WriteAsync(req, ct).ConfigureAwait(false);
|
|
await writer.WriteAsync(FocasMessageKind.WriteResponse, resp, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.PmcBitWriteRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<PmcBitWriteRequest>(body);
|
|
var resp = await _backend.PmcBitWriteAsync(req, ct).ConfigureAwait(false);
|
|
await writer.WriteAsync(FocasMessageKind.PmcBitWriteResponse, resp, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
case FocasMessageKind.ProbeRequest:
|
|
{
|
|
var req = MessagePackSerializer.Deserialize<ProbeRequest>(body);
|
|
var resp = await _backend.ProbeAsync(req, ct).ConfigureAwait(false);
|
|
await writer.WriteAsync(FocasMessageKind.ProbeResponse, resp, ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
default:
|
|
await writer.WriteAsync(FocasMessageKind.ErrorResponse,
|
|
new ErrorResponse { Code = "unknown-kind", Message = $"Kind {kind} is not handled by the Host" },
|
|
ct).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
}
|
|
catch (OperationCanceledException) { throw; }
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex, "FwlibFrameHandler error processing {Kind}", kind);
|
|
await writer.WriteAsync(FocasMessageKind.ErrorResponse,
|
|
new ErrorResponse { Code = "backend-exception", Message = ex.Message },
|
|
ct).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
public IDisposable AttachConnection(FrameWriter writer) => IFrameHandler.NoopAttachment.Instance;
|
|
}
|