Skip to content

Commit b2a06f0

Browse files
lpereiraAnas Nashif
authored andcommitted
samples: net: NATS protocol sample
NATS is a publisher/subscriber protocol implemented on top of TCP. It is specified in [1], and this is a sample implementation for Zephyr using the new IP stack. The API is loosely based off of [2]. With this sample, it's possible to subscribe/unsubscribe to a given subject, and be notified of changes asynchronously. In order to conserve resources, the implementation does not keep its own track of subscribed subjects; that must be performed by the application itself, so it ignore unknown/undesired subjects. TLS is not supported yet, although basic auth is. The client will indicate if it supports username/password if a certain callback is set in the struct nats. This callback will then be called, and the user must copy the username/password to the supplied user/pass buffers. Content might be also published for a given subject. The sample application lets one observe the subject "led0", and turn it "on", "off", or "toggle" its value. Changing the value will, if supported, act on a status LED on the development board. The new status will be published. Also worth noting is that most of the networking and GPIO boilerplate has been shamelessly copied from the IRC bot example. (Curiously, both protocols are similar.) [1] http://nats.io/documentation/internals/nats-protocol/ [2] https://github.com/nats-io/go-nats Jira: ZEP-1012 Change-Id: I204adc61c4c533661eacfb8c28c1c08870debd91 Signed-off-by: Leandro Pereira <[email protected]>
1 parent 04f142c commit b2a06f0

File tree

7 files changed

+1147
-0
lines changed

7 files changed

+1147
-0
lines changed

samples/net/nats/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Makefile - NATS client sample
2+
3+
#
4+
# Copyright (c) 2017 Intel Corporation
5+
#
6+
# SPDX-License-Identifier: Apache-2.0
7+
#
8+
9+
BOARD ?= qemu_x86
10+
CONF_FILE ?= prj_$(BOARD).conf
11+
12+
include $(ZEPHYR_BASE)/Makefile.inc
13+
14+
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack

samples/net/nats/README.rst

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
.. _NATS_Client_Sample:
2+
3+
4+
NATS Client Implementation Sample
5+
#################################
6+
7+
8+
Overview
9+
********
10+
11+
`NATS <http://nats.io/documentation/internals/nats-protocol/>`__ is a
12+
publisher/subscriber protocol implemented on top of TCP. It is specified in
13+
`NATS Protocol documentation <http://nats.io/documentation/internals/nats-protocol/>`__,
14+
and this is a sample implementation for Zephyr using the new IP stack.
15+
The API is loosely based off of the `Golang API
16+
<https://github.com/nats-io/go-nats>`__.
17+
18+
With this sample, it's possible to subscribe/unsubscribe to a given subject,
19+
and be notified of changes asynchronously. In order to conserve resources,
20+
the implementation does not keep track of subscribed subjects; that
21+
must be performed by the application itself, so it can ignore unknown/undesired
22+
subjects.
23+
24+
TLS is not supported yet, although basic authentication is. The client will indicate
25+
if it supports username/password if a certain callback is set in the ``struct
26+
nats``. This callback will then be called, and the user must copy the
27+
username/password to the supplied user/pass buffers.
28+
29+
Content might be also published for a given subject.
30+
31+
The sample application lets one observe the subject "led0", and turn it
32+
"on", "off", or "toggle" its value. Changing the value will, if supported,
33+
act on a status LED on the development board. The new status will be
34+
published.
35+
36+
Also worth noting is that most of the networking and GPIO boilerplate has
37+
been shamelessly copied from the IRC bot example. (Curiously, both
38+
protocols are similar.)
39+
40+
Requirements
41+
************
42+
43+
To test the sample, build the Zephyr application for your platform. This
44+
has only been tested with the QEMU emulator as provided by the Zephyr SDK,
45+
but it should work with other supported hardware as long as they have enough
46+
memory, the network stack has TCP enabled, and the connectivity hardware is
47+
supported.
48+
49+
As far as the software goes, this has been tested with the official `gnatsd
50+
<https://github.com/nats-io/gnatsd>`__ for the server, and the official
51+
`go-nats <https://github.com/nats-io/go-nats>`__ client library. Both the
52+
server and clients were set up as per instructions found in their respective
53+
``README.md`` files.
54+
55+
The client was a one-off test that is basically the same code provided in
56+
the `Basic Usage
57+
<https://github.com/nats-io/go-nats/blob/e6bb81b5a5f37ef7bf364bb6276e13813086c6ee/README.md#basic-usage>`__
58+
section as found in the ``go-nats`` README file, however, subscribing to the
59+
topic used in this sample: ``led0``, and publishing values as described
60+
above (``on``, ``off``, and ``toggle``).
61+
62+
Library Usage
63+
*************
64+
65+
Allocate enough space for a ``struct nats``, setting a few callbacks so
66+
that you're notified as events happen:
67+
68+
::
69+
70+
struct nats nats_ctx = {
71+
.on_auth_required = on_auth_required,
72+
.on_message = on_message
73+
};
74+
75+
The ``on_auth_required()`` and ``on_message()`` functions are part of
76+
your application, and each must have these signatures:
77+
78+
::
79+
80+
int on_auth_required(struct nats *nats, char **user, char **pass);
81+
int on_message(struct nats *nats, struct nats_msg *msg);
82+
83+
Both functions should return 0 to signal that they could successfully
84+
handle their role, and a negative value, if they couldn't for any
85+
reason. It's recommended to use a negative integer as provided by
86+
errno.h in order to ease debugging.
87+
88+
The first function, ``on_auth_required()``, is called if the server
89+
notifies that it requires authentication. It's not going to be called if
90+
that's not the case, so it is optional. However, if the server asks for
91+
credentials and this function is not provided, the connection will be
92+
closed and an error will be returned by ``nats_connect()``.
93+
94+
The second function, ``on_message()``, will be called whenever the
95+
server has been notified of a value change. The ``struct nats_msg`` has the
96+
following fields:
97+
98+
::
99+
100+
struct nats_msg {
101+
const char *subject;
102+
const char *sid;
103+
const char *reply_to;
104+
};
105+
106+
The field ``reply_to`` may be passed directly to ``nats_publish()``,
107+
in order to publish a reply to this message. If it's ``NULL`` (no
108+
reply-to field in the message from the server), the
109+
``nats_publish()`` function will not reply to a specific mailbox and
110+
will just update the topic value.
111+
112+
In order to manage topic subscription, these functions can be used:
113+
114+
::
115+
116+
int nats_subscribe(struct nats *nats, const char *subject,
117+
const char *queue_group, const char *sid);
118+
119+
``subject`` and ``sid`` are validated so that they're actually valid
120+
per the protocol rules. ``-EINVAL`` is returned if they're not.
121+
122+
If ``queue_group`` is NULL, it's not sent to the server.
123+
124+
::
125+
126+
int nats_unsubscribe(struct nats *nats, const char *sid,
127+
size_t max_msgs);
128+
129+
``sid`` is validated so it's actually valid per the protocol rules.
130+
-EINVAL is returned if it's not.
131+
132+
``max_msgs`` specifies the number of messages that the server will
133+
send before actually unsubscribing the message. Can be 0 to
134+
immediately unsubscribe.
135+
136+
Both of these functions will return ``-ENOMEM`` if they couldn't build
137+
the message to transmit to the server. They can also return any error
138+
that ``net_context_send()`` can return.
139+
140+
In order to conserve resources, the Zephyr implementation will not make
141+
not of subscribed topics. This is left as a task for the user of the API
142+
to handle, for instance, when the ``on_message()`` callback is called.
143+
144+
Topics can be published by using the following function:
145+
146+
::
147+
148+
int nats_publish(struct nats *nats, const char *subject,
149+
const char *reply_to, const char *payload,
150+
size_t payload_len);
151+
152+
As usual, ``subject`` is validated and ``-EINVAL`` will be returned if
153+
it's in an invalid format. The ``reply_to`` field can be ``NULL``, in
154+
which case, subscribers to this topic won't receive this information as
155+
well.
156+
157+
As ``net_subscribe()`` and ``net_unsubscribe()``, this function can
158+
return ``ENOMEM`` -or any other errors that ``net_context_send()``
159+
returns.

samples/net/nats/prj_qemu_x86.conf

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
CONFIG_INIT_STACKS=y
2+
3+
CONFIG_NET_LOG_ENABLED=y
4+
CONFIG_SYS_LOG_NET_LEVEL=2
5+
CONFIG_NET_DHCPV4=y
6+
CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=3
7+
CONFIG_NET_IPV6=y
8+
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=3
9+
CONFIG_NET_LOG=y
10+
CONFIG_NET_MAX_CONTEXTS=10
11+
CONFIG_NET_NBUF_DATA_COUNT=30
12+
CONFIG_NET_NBUF_RX_COUNT=14
13+
CONFIG_NET_NBUF_TX_COUNT=14
14+
CONFIG_NET_SHELL=y
15+
CONFIG_NET_SLIP_TAP=y
16+
CONFIG_NET_STATISTICS=y
17+
CONFIG_NET_TCP=y
18+
CONFIG_NETWORKING=y
19+
CONFIG_DNS_RESOLVER=n
20+
21+
CONFIG_PRINTK=y
22+
CONFIG_SYS_LOG_SHOW_COLOR=y
23+
24+
CONFIG_NET_SAMPLES_IP_ADDRESSES=y
25+
CONFIG_NET_SAMPLES_MY_IPV6_ADDR="2001:db8::1"
26+
CONFIG_NET_SAMPLES_PEER_IPV6_ADDR="2001:db8::2"
27+
28+
CONFIG_TEST_RANDOM_GENERATOR=y
29+
30+
CONFIG_JSON_LIBRARY=y

samples/net/nats/src/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
obj-y = main.o nats.o
2+
3+
ccflags-y += -I${ZEPHYR_BASE}/lib/json/

0 commit comments

Comments
 (0)