livery_grpc_frame (livery_grpc v0.1.0)

View Source

gRPC length-prefixed message framing.

Each gRPC message on the wire is a Length-Prefixed-Message:

  Compressed-Flag (1 byte, 0 or 1) | Message-Length (4 bytes, big-endian) | Message

This module handles only the framing. Compression of the payload is livery_grpc_compression; protobuf encode/decode is livery_grpc_codec. The Compressed-Flag is surfaced as a boolean so the caller decides how to interpret the payload.

For streaming, a frame can be split across several HTTP/2 DATA chunks. Use a buffer/0: feed each inbound chunk to push/2, which returns every whole frame it can now decode plus the leftover bytes for next time.

Summary

Functions

Decode exactly one frame, returning the rest. See decode_one/2.

Decode one frame from the front of Bin.

Frame an uncompressed payload.

Frame a payload, setting the compressed flag. The payload must already be compressed when Compressed is true.

Whether the buffer holds no leftover bytes.

A fresh, empty decode buffer.

Append Data to the buffer and pull out every whole frame now available.

push/2 with a per-message size ceiling (the decoded payload length).

Types

buffer()

-opaque buffer()

frame()

-type frame() :: {Compressed :: boolean(), Payload :: binary()}.

Functions

decode_one(Bin)

-spec decode_one(binary()) ->
                    {ok, frame(), binary()} | more | {error, {message_too_large, non_neg_integer()}}.

Decode exactly one frame, returning the rest. See decode_one/2.

decode_one/2

-spec decode_one(binary(), non_neg_integer() | infinity) ->
                    {ok, frame(), binary()} | more | {error, {message_too_large, non_neg_integer()}}.

Decode one frame from the front of Bin.

{ok, Frame, Rest} on a whole frame, more when more bytes are needed, {error, {message_too_large, Len}} when the declared length exceeds Max.

encode(Payload)

-spec encode(binary()) -> iodata().

Frame an uncompressed payload.

encode(Payload, Compressed)

-spec encode(binary(), boolean()) -> iodata().

Frame a payload, setting the compressed flag. The payload must already be compressed when Compressed is true.

is_empty/1

-spec is_empty(buffer()) -> boolean().

Whether the buffer holds no leftover bytes.

new()

-spec new() -> buffer().

A fresh, empty decode buffer.

push(Data, Buffer)

-spec push(binary(), buffer()) -> {[frame()], buffer()}.

Append Data to the buffer and pull out every whole frame now available.

Returns {Frames, Buffer}: Frames is the list of complete frames in arrival order, Buffer carries the trailing partial frame (if any). No size limit is enforced; use push/3 for that.

push(Data, Buffer, Max)

-spec push(binary(), buffer(), non_neg_integer() | infinity) ->
              {ok, [frame()], buffer()} | {error, {message_too_large, non_neg_integer()}}.

push/2 with a per-message size ceiling (the decoded payload length).

Returns {ok, Frames, Buffer} or {error, {message_too_large, Len}} when a frame's declared length exceeds Max. The ceiling is checked against the length prefix before any payload is buffered, so an oversized frame is rejected without reading its bytes.