54 lines
2.0 KiB
C#
54 lines
2.0 KiB
C#
using System.Buffers.Binary;
|
|
|
|
namespace Lskj.AgentPet.Host.Core.ErpBridge;
|
|
|
|
public static class BridgeFrameCodec
|
|
{
|
|
public const int MaxMessageBytes = 1024 * 1024;
|
|
|
|
public static async Task WriteAsync(
|
|
Stream stream,
|
|
ReadOnlyMemory<byte> body,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(stream);
|
|
if (body.Length is <= 0 or > MaxMessageBytes)
|
|
throw new HostError("bridge_protocol_error", "ERP 桥请求长度无效或超过 1 MB。");
|
|
byte[] header = new byte[4];
|
|
BinaryPrimitives.WriteInt32LittleEndian(header, body.Length);
|
|
await stream.WriteAsync(header, cancellationToken).ConfigureAwait(false);
|
|
await stream.WriteAsync(body, cancellationToken).ConfigureAwait(false);
|
|
await stream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
public static async Task<byte[]> ReadAsync(
|
|
Stream stream,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(stream);
|
|
byte[] header = new byte[4];
|
|
await ReadExactlyAsync(stream, header, cancellationToken).ConfigureAwait(false);
|
|
int length = BinaryPrimitives.ReadInt32LittleEndian(header);
|
|
if (length is <= 0 or > MaxMessageBytes)
|
|
throw new HostError("bridge_protocol_error", "ERP 桥响应长度无效或超过 1 MB。");
|
|
byte[] body = new byte[length];
|
|
await ReadExactlyAsync(stream, body, cancellationToken).ConfigureAwait(false);
|
|
return body;
|
|
}
|
|
|
|
private static async Task ReadExactlyAsync(
|
|
Stream stream,
|
|
Memory<byte> target,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
int offset = 0;
|
|
while (offset < target.Length)
|
|
{
|
|
int count = await stream.ReadAsync(target[offset..], cancellationToken).ConfigureAwait(false);
|
|
if (count == 0)
|
|
throw new HostError("bridge_disconnected", "ERP 桥在完整消息到达前关闭。");
|
|
offset += count;
|
|
}
|
|
}
|
|
}
|