Class MessageFramer
Handles message framing for the DotBoxD protocol. Stream frame: [4 bytes: Total Length][4 bytes: MessageId][1 byte: MessageType][N bytes: Body]. For RPC messages the body is un-nested as [4 bytes: Envelope Length][E bytes: Envelope][P bytes: Payload], so the trailing payload can be handed to callers as a zero-copy slice of the frame buffer.
public static class MessageFramer
- Inheritance
-
MessageFramer
- Inherited Members
Fields
EnvelopeLengthSize
Length prefix written before the serialized envelope so the trailing payload can be located without the serializer reporting how many bytes it consumed.
public const int EnvelopeLengthSize = 4
Field Value
HeaderSize
Header size: 4 (length) + 4 (messageId) + 1 (type) = 9 bytes
public const int HeaderSize = 9
Field Value
MaxMessageSize
Maximum message size (16 MB).
public const int MaxMessageSize = 16777216
Field Value
Methods
FrameMessage<T>(ISerializer, int, MessageType, T, ReadOnlySpan<byte>)
Serializes envelope and appends the raw payload bytes
behind a frame header into a single pooled buffer, then patches the total length and the
envelope length. The caller owns the returned Payload.
public static Payload FrameMessage<T>(ISerializer serializer, int messageId, MessageType type, T envelope, ReadOnlySpan<byte> payload)
Parameters
serializerISerializermessageIdinttypeMessageTypeenvelopeTpayloadReadOnlySpan<byte>
Returns
Type Parameters
T
FrameRequest<TEnvelope, TArgument>(ISerializer, int, MessageType, TEnvelope, TArgument)
Serializes envelope followed immediately by argument
behind a frame header into a single pooled buffer. Unlike FrameMessage<T>(ISerializer, int, MessageType, T, ReadOnlySpan<byte>) this
serializes the argument straight into the frame writer, avoiding the intermediate payload
buffer and the copy. The caller owns the returned Payload.
public static Payload FrameRequest<TEnvelope, TArgument>(ISerializer serializer, int messageId, MessageType type, TEnvelope envelope, TArgument argument)
Parameters
serializerISerializermessageIdinttypeMessageTypeenvelopeTEnvelopeargumentTArgument
Returns
Type Parameters
TEnvelopeTArgument
FrameToPayload(int, MessageType, ReadOnlySpan<byte>)
Frames a message into an exact-size rented Payload. The caller owns the result.
public static Payload FrameToPayload(int messageId, MessageType type, ReadOnlySpan<byte> payload)
Parameters
messageIdinttypeMessageTypepayloadReadOnlySpan<byte>
Returns
ReadMessageAsync(Stream, CancellationToken)
Reads a framed message from a stream. Returns null when the connection is closed.
The caller owns the returned Body and must dispose it.
public static Task<MessageFramer.FramedMessage?> ReadMessageAsync(Stream stream, CancellationToken ct = default)
Parameters
streamStreamctCancellationToken
Returns
TryReadFrame(ReadOnlyMemory<byte>, out int, out MessageType, out ReadOnlyMemory<byte>, out ReadOnlyMemory<byte>)
Parses an un-nested RPC frame out of an in-memory buffer without copying. Both
envelope and payload are slices of
source and share its lifetime.
public static bool TryReadFrame(ReadOnlyMemory<byte> source, out int messageId, out MessageType type, out ReadOnlyMemory<byte> envelope, out ReadOnlyMemory<byte> payload)
Parameters
sourceReadOnlyMemory<byte>messageIdinttypeMessageTypeenvelopeReadOnlyMemory<byte>payloadReadOnlyMemory<byte>
Returns
TryReadFrameHeader(ReadOnlyMemory<byte>, out int, out MessageType)
Parses just the DotBoxD frame header. This supports envelope-less control frames such as request cancellation without requiring an RPC envelope prefix.
public static bool TryReadFrameHeader(ReadOnlyMemory<byte> source, out int messageId, out MessageType type)
Parameters
sourceReadOnlyMemory<byte>messageIdinttypeMessageType
Returns
ValidateOutgoingFrame(ReadOnlySpan<byte>, int)
Validates that frame is a well-formed outgoing wire frame: at least a full
header, a length prefix that exactly matches the buffer length, and within
maxMessageSize. Shared by every transport's send path so a malformed frame
is rejected locally instead of being shipped to the peer (where behaviour would otherwise
differ by transport). Throws InvalidDataException on a bad frame.
public static void ValidateOutgoingFrame(ReadOnlySpan<byte> frame, int maxMessageSize = 16777216)
Parameters
frameReadOnlySpan<byte>maxMessageSizeint
WriteFrame(IBufferWriter<byte>, int, MessageType, ReadOnlySpan<byte>)
Writes a complete frame (header + payload) into the supplied buffer writer.
public static void WriteFrame(IBufferWriter<byte> writer, int messageId, MessageType type, ReadOnlySpan<byte> payload)
Parameters
writerIBufferWriter<byte>messageIdinttypeMessageTypepayloadReadOnlySpan<byte>
WriteMessageAsync(Stream, int, MessageType, ReadOnlyMemory<byte>, CancellationToken)
Writes a framed message to a stream.
public static Task WriteMessageAsync(Stream stream, int messageId, MessageType type, ReadOnlyMemory<byte> payload, CancellationToken ct = default)
Parameters
streamStreammessageIdinttypeMessageTypepayloadReadOnlyMemory<byte>ctCancellationToken