# `FireMQ.Frame`
[🔗](https://github.com/FireMQ/firemq-elixir/blob/v0.1.0/lib/firemq/frame.ex#L1)

Encodes and decodes FireMQ protocol frames.

On TCP and TLS a frame is:

    len : u32 | op : u8 | hlen : u32 | header (MessagePack map) | payload

`len` counts every byte after itself. The header is a MessagePack map with string keys
and the payload is the raw message body. All integers are big-endian.

The connection reads frames with the socket option `packet: 4`, so the runtime strips
the length prefix and `decode_body/1` sees `op | hlen | header | payload`. `decode/2`
handles a byte stream that still carries the prefix.

# `t`

```elixir
@type t() :: {op :: atom() | {:unknown, byte()}, header :: map(), payload :: binary()}
```

A decoded frame: the op name, its header map (string keys) and the payload.

# `decode`

```elixir
@spec decode(binary(), pos_integer()) ::
  {:ok, t(), binary()} | :more | {:error, String.t()}
```

Splits one frame off the front of a byte stream that carries length prefixes.

Returns `{:ok, frame, rest}`, `:more` when the buffer does not hold a whole frame yet,
or `{:error, reason}`. `max_frame` bounds the value of the length prefix.

# `decode_body`

```elixir
@spec decode_body(binary()) :: {:ok, t()} | {:error, String.t()}
```

Decodes a frame without its length prefix.

# `encode`

```elixir
@spec encode(atom(), map(), iodata()) :: iodata()
```

Encodes a frame with its length prefix, as sent on TCP.

# `encode_body`

```elixir
@spec encode_body(atom(), map(), iodata()) :: iodata()
```

Encodes a frame without its length prefix: the form used on WebSocket and with the
socket option `packet: 4`.

# `magic`

The 4 bytes a TCP or TLS client sends before its first frame.

# `max_hello_frame`

Largest frame accepted before `welcome`, counted from the op byte.

# `op_code`

The op code for an op name.

# `op_name`

The op name for an op code, or `{:unknown, code}`.

# `ops`

Every op name, in op-code order.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
