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 eunitBuild
$ rebar3 compileUsage
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
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
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
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">>.