Table of Contents

Class MessageFramer

Namespace
DotBoxD.Services.Protocol
Assembly
DotBoxD.Services.dll

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

int

HeaderSize

Header size: 4 (length) + 4 (messageId) + 1 (type) = 9 bytes

public const int HeaderSize = 9

Field Value

int

MaxMessageSize

Maximum message size (16 MB).

public const int MaxMessageSize = 16777216

Field Value

int

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

serializer ISerializer
messageId int
type MessageType
envelope T
payload ReadOnlySpan<byte>

Returns

Payload

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

serializer ISerializer
messageId int
type MessageType
envelope TEnvelope
argument TArgument

Returns

Payload

Type Parameters

TEnvelope
TArgument

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

messageId int
type MessageType
payload ReadOnlySpan<byte>

Returns

Payload

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

stream Stream
ct CancellationToken

Returns

Task<MessageFramer.FramedMessage?>

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

source ReadOnlyMemory<byte>
messageId int
type MessageType
envelope ReadOnlyMemory<byte>
payload ReadOnlyMemory<byte>

Returns

bool

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

source ReadOnlyMemory<byte>
messageId int
type MessageType

Returns

bool

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

frame ReadOnlySpan<byte>
maxMessageSize int

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

writer IBufferWriter<byte>
messageId int
type MessageType
payload ReadOnlySpan<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

stream Stream
messageId int
type MessageType
payload ReadOnlyMemory<byte>
ct CancellationToken

Returns

Task