https://github.com/zotonic/mqtt_packet_map
Encoder and decoder for MQTT v5 and earlier.
https://github.com/zotonic/mqtt_packet_map
Last synced: 13 days ago
JSON representation
Encoder and decoder for MQTT v5 and earlier.
- Host: GitHub
- URL: https://github.com/zotonic/mqtt_packet_map
- Owner: zotonic
- License: apache-2.0
- Created: 2018-02-26T12:27:24.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2020-12-28T12:51:17.000Z (over 4 years ago)
- Last Synced: 2024-04-24T02:02:40.526Z (about 1 year ago)
- Language: Erlang
- Size: 35.2 KB
- Stars: 5
- Watchers: 6
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[](https://travis-ci.org/zotonic/mqtt_packet_map)
MQTT Packet Encoder and Decoder
===============================Encoder and decoder for MQTT v5 and earlier.
Maps are used for the representation of all MQTT messages.
There are two functions:1. `mqtt_packet_map:encode/1`
2. `mqtt_packet_map:decode/1`Both have a variant where the MQTT version (protocol level) is passed.
This defaults to 5, valid values are 3, 4 (v3.1.1) and 5.Example usage:
```erlang
% Decode an incoming binary, return the message
case mqtt_packet_map:decode(Bin) of
{ok, {Msg, RestBin}} ->
% Decoded a packet, RestBin contains the
% remaining data for the next packet(s).
...;
{error, incomplete_packet} -> ...;
% Packet is too short, fetch more data first
...;
{error, malformed_header} ->
% Illegal package, close the connection
...;
{error, unknown_protocol} ->
% Only for connect messages
...
end.% Encode a message
{ok, Bin} = mqtt_packet_map:encode(Msg).% Encode a message as MQTT v3.1.1 (protocol level 4)
{ok, Bin} = mqtt_packet_map:encode(4, Msg).
```MQTT v5 Specification
=====================This library follows the following specification:
http://docs.oasis-open.org/mqtt/mqtt/v5.0/cs01/mqtt-v5.0-cs01.html
Usage
=====Include the mqtt_packet_map directly in your rebar.config:
```erlang
{deps, [
mqtt_packet_map
]}.
```Tests
=====Run tests with:
```bash
make test
```Sample output:
```
./rebar3 ct --config rebar.test.config
===> Verifying dependencies...
===> Compiling mqtt_packet_map
===> Running Common Test suites...
%%% mqtt_packet_map_SUITE ==> variable_byte_integer: OK
%%% mqtt_packet_map_SUITE ==> partial_packet: OK
%%% mqtt_packet_map_SUITE ==> connect_v5: OK
%%% mqtt_packet_map_SUITE ==> connect_v5_full: OK
%%% mqtt_packet_map_SUITE ==> connack_v5: OK
%%% mqtt_packet_map_SUITE ==> publish_v5: OK
%%% mqtt_packet_map_SUITE ==> puback_et_al_v5: OK
%%% mqtt_packet_map_SUITE ==> subscribe_v5: OK
%%% mqtt_packet_map_SUITE ==> suback_v5: OK
%%% mqtt_packet_map_SUITE ==> unsubscribe_v5: OK
%%% mqtt_packet_map_SUITE ==> unsuback_v5: OK
%%% mqtt_packet_map_SUITE ==> pingreq: OK
%%% mqtt_packet_map_SUITE ==> pingresp: OK
%%% mqtt_packet_map_SUITE ==> disconnect_v5: OK
%%% mqtt_packet_map_SUITE ==> auth_v5: OK
All 15 tests passed.
```Packet Types
============Below is the list of packet types and their fields.
Fields that are omitted are set to their defaults.
For example, `reason_code`, `qos`, and `packet_id` will
all default to `0`.Some fields, like the topic for publish, are obligatory.
The encoder will crash if you leave out oblibatory fields.Topics
------Topics are parsed as lists (i.e. they are split on the `/` separator).
When encoding, both a binary and a list are accepted.
So the following are acceptable topics for the encoder:
* `<<"foo/bar">>`
* `[ <<"foo">> | <<"bar">> ]`Which are both decoded as:
* `[ <<"foo">> | <<"bar">> ]`
Properties
----------The (optional) properties of a package are represented as a map.
Known properties have an atom as key, user properties a binary.
Below is an example map with all properties and one user (`<<"myuserprop">>`) property. The example values are random and
have no bearing in reality.```Erlang
#{
payload_format_indicator => true,
message_expiry_interval => 1,
content_type => <<"text/plain">>,
response_topic => [ <<"response">>, <<"topic">> ],
correlation_data => <<"corrdata">>,
subscription_identifier => 2,
session_expiry_interval => 3,
assigned_client_identifier => <<"assclientid">>,
server_keep_alive => 4,
authentication_method => <<"authmethod">>,
authentication_data => <<"authdata">>,
request_problem_information => true,
will_delay_interval => 5,
request_response_information => false,
response_information => <<"respinfo">>,
server_reference => <<"servref">>,
reason_string => <<"reason">>,
receive_maximum => 12345,
topic_alias_maximum => 6,
topic_alias => 7,
maximum_qos => 2,
retain_available => true,
<<"myuserprop">> => <<"foobar">>,
maximum_packet_size => 1234567,
wildcard_subscription_available => true,
subscription_identifier_available => false,
shared_subscription_available => true
}.
```The `subscription_identifier` can be present multiple times, making it either a single integer or a list of integers.
CONNECT
-------Minimal:
```Erlang
#{ type => connect }
```Complete:
```erlang
#{
type => connect,
client_id => <<"foobar">>,
username => <<"someone">>,
password => <<"secret">>,
clean_start => true,
keep_alive => 120,
properties => #{
<<"foo">> => <<"bar">>,
will_delay_interval => 10
},
will_flag => true,
will_payload => <<>>,
will_properties => #{},
will_qos => 0,
will_retain => false,
will_topic => [ <<"good">>, <<"bye">> ]
}
```CONNACK
-------Minimal:
```Erlang
#{ type = connack }
```Complete:
```erlang
#{
type => connack,
reason_code => 16#80,
session_present => true,
properties => #{
<<"foo">> => <<"bar">>
}
}
```PUBLISH
-------Minimal:
```Erlang
#{
type => publish,
topic => [ <<"foo">>, <<"bar">>, <<"la">> ]
}
```Complete:
```erlang
#{
type => publish,
topic => [ <<"foo">>, <<"bar">>, <<"la">> ],
qos => 2,
dup => true,
retain => true,
packet_id => 1234,
payload => <<"aloha">>,
properties => #{
<<"foo">> => <<"bar">>
}
}
```PUBACK / PUBREC / PUBREL / PUBCOMP
----------------------------------These for packets are the same. Only the type code is different.
Minimal:
```Erlang
% Type is one of: puback, pubrec, pubrel, or pubcomp
#{ type = puback }
```Complete:
```erlang
#{
type => puback,
reason_code => 16#81,
packet_id => 4321,
properties => #{
<<"bar">> => <<"fooooo">>
}
}
```SUBSCRIBE
-------The topics subscribed to are either maps with options or just a topic.
Minimal:
```Erlang
#{
type => subscribe,
topics => [
[ <<"foo1">>, <<"bar">> ]
]
}
```Complete:
```erlang
#{
type => subscribe,
packet_id => 1234,
topics => [
#{
topic => [ "foo1", "bar" ],
no_local => true,
qos => 2,
retain_as_published => true,
retain_handling => 2
},
#{
topic => [ <<"foo2">>, <<"bar">> ]
}
],
properties => #{
<<"foo">> => <<"bar">>
}
}
```SUBACK
-------All acknowledgements are tuples `{ok, QoS}` or `{error, ReasonCode}`.
Minimal:
```Erlang
#{
type => suback,
acks => [
{ok, 0}
]
}
```Complete (for four acks):
```erlang
#{
type => suback,
packet_id => 12345,
acks => [
{ok, 2},
{ok, 0},
{ok, 1},
{error, 16#80}
],
properties => #{
<<"foo">> => <<"bar">>
}
}
```UNSUBSCRIBE
-----------Minimal:
```Erlang
#{
type => unsubscribe,
topics => [
[ <<"foo">>, <<"bar">> ]
]
}
```Complete:
```erlang
#{
type => unsubscribe,
packet_id => 42,
topics => [
<<"foo1/bar">>,
[ <<"foo2">>, <<"bar">> ]
],
properties => #{
<<"foo">> => <<"bar">>
}
}
```UNSUBACK
-----------The acknowledgements are one of:
* `{ok, found}`
* `{ok, notfound}`
* `{error, ReasonCode}`Minimal:
```Erlang
#{
type => unsuback,
acks => [
{ok, found}
]
}
```Complete (for three acks):
```erlang
#{
type => unsuback,
packet_id => 12345,
acks => [
{ok, found},
{ok, notfound},
{error, 16#80}
],
properties => #{
<<"foo">> => <<"bar">>
}
}
```PINGREQ
-------No special fields.
```Erlang
#{ type => pingreq }
```PINGRESP
--------No special fields
```Erlang
#{ type => pingresp }
```DISCONNECT
----------The default reason code for disconnects is `0`.
Minimal:
```Erlang
#{ type => disconnect }
```Complete:
```erlang
#{
type => disconnect,
reason_code => 16#81,
properties => #{
<<"foo">> => <<"bar">>
}
}
```AUTH
----Minimal:
```Erlang
#{ type => auth }
```Complete:
```erlang
{
type => auth,
reason_code => 16#80,
properties => #{
<<"foo">> => <<"bar">>,
authentication_method => <<"...">>,
authentication_data => <<"...">>
}
}
```License
=======This library is licensed under the Apache License version 2.0.
See the LICENSE file.