nats_msg

nats_msg is a pure Erlang NATS message encoder/decoder library for NATS high performance messaging platform. For details about NATS protocol, see: NATS Protocol. It doesn't have any dependency other than Erlang/OTP install (16+ should be OK) and rebar3.

Install

nats_msg uses rebar3 to build and tests and it is available on hex.pm. Just include the following in your rebar.config:

{deps[nats_msg]}.

Alternatively (for whatever reason you don't like to use hex.pm):

{deps, [
    {nat_msg, {git, "https://github.com/yuce/nats_msg.git", {branch, "master"}}.

Or, you can just copy src/nats_msg.erl to your project to use it.

Tests

Run the tests using:

$ rebar3 eunit

Build

$ rebar3 compile

Usage

Binaries are used exclusively throught the library. Encoding a message produces a binary. Decoding a binary produces a {Messages, RemainingBinary} tuple. Messages is a list of messages and RemainingBinary is the part of the input which wasn't decoded and returned. The latter is very useful when dealing with streams, where the input is chunked and requires appending chunks to be able to decode messages. In those situations, just prepend RemaningBinary to the next binary chunk.

Currently, no error handling is performed.

INFO

NATS Spec

Encode

This message requires a JSON object but in order to not introduce a dependency, nats_msg:info/1 takes a binary. You can use jsx or jiffy to convert an Erlang map to binary:

ServerInfo = #{<<"auth_required">> => true, <<"server_id">> => <<"0001-SERVER">>},
BinaryInfo = jsx:encode(ServerInfo),
BinaryMsg = nats_msg:info(BinaryInfo).

Decode

This message requires a JSON object but in order to not introduce a dependency, nats_msg:decode/1 returns {info, BinaryInfo} messages. You can use jsx or jiffy to convert BinaryInfo to a map:

Chunk = <<"INFO {\"auth_required\":true,\"server_id\":\"0001-SERVER\"}\r\n">>,
{[Msg], _} = nats_msg:decode(Chunk),
{info, BinaryInfo} = Msg,
ServerInfo = jsx:decode(BinaryInfo, [return_maps]).

CONNECT

NATS Spec

Encode

This message requires a JSON object but in order to not introduce a dependency, nats_msg:connect/1 takes a binary. You can use jsx or jiffy to convert an Erlang map to binary:

ConnectInfo = #{<<"auth_required">> => true, <<"server_id">> => <<"0001-SERVER">>},
BinaryInfo = jsx:encode(ServerInfo),
BinaryMsg = nats_msg:connect(BinaryInfo).

Decode

This message requires a JSON object but in order to not introduce a dependency, nats_msg:decode/1 returns {connect, BinaryInfo} messages. You can use jsx or jiffy to convert BinaryInfo to a map:

Chunk = <<"CONNECT {\"verbose\":true,\"name\":\"the_client\"}\r\n">>,
{[Msg], _} = nats_msg:decode(Chunk),
{connect, BinaryInfo} = Msg,
ClientInfo = jsx:decode(BinaryInfo, [return_maps]).

PUB

NATS Spec

Encode

Notify subscribers of a subject:

BinaryMsg = nats_msg:pub(<<"NOTIFY.INBOX">>).

Send some data (payload) to subscribers, providing a reply subject:

BinaryMsg = nats_msg:pub(<<"FOOBAR">>, <<"REPRAP">>, <<"Hello, World!">>).

Send some data (payload) to subscribers (without a reply subject):

BinaryMsg = nats_msg:pub(<<"FOOBAR">>, undefined, <<"Hello, World!">>).

Decode

Notification:

Chunk = <<"PUB NOTIFY 0\r\n\r\n">>,
{[Msg], _} = nats_msg:decode(Chunk),
{pub, {Subject, ReplyTo, PayloadSize}, Payload} = Msg,
% Subject = <<"NOTIFY">>,
% ReplyTo = undefined,
% PayloadSize = 0,
% Payload = <<>>.

Publish message with replier and payload:

Chunk = <<"PUB FRONT.DOOR INBOX.22 11\r\nKnock Knock\r\n">>,
{[Msg], _} = nats_msg:decode(Chunk),
{pub, {Subject, ReplyTo, PayloadSize}, Payload} = Msg,
% Subject = <<"FRONT.DOOR">>,
% ReplyTo = <<"INBOX.22">>,
% PayloadSize = 11,
% Payload = <<"Knock Knock">>.

SUB

NATS Spec

UNSUB

NATS Spec

MSG

NATS Spec

PING

NATS Spec

PONG

NATS Spec

+OK

NATS Spec

-ERR

NATS Spec