| .. _NATS_Client_Sample: |
| |
| |
| NATS Client Implementation Sample |
| ################################# |
| |
| |
| Overview |
| ******** |
| |
| `NATS <http://nats.io/documentation/internals/nats-protocol/>`__ is a |
| publisher/subscriber protocol implemented on top of TCP. It is specified in |
| `NATS Protocol documentation <http://nats.io/documentation/internals/nats-protocol/>`__, |
| and this is a sample implementation for Zephyr using the new IP stack. |
| The API is loosely based off of the `Golang API |
| <https://github.com/nats-io/go-nats>`__. |
| |
| 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 track of subscribed subjects; that |
| must be performed by the application itself, so it can ignore unknown/undesired |
| subjects. |
| |
| TLS is not supported yet, although basic authentication 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.) |
| |
| Requirements |
| ************ |
| |
| To test the sample, build the Zephyr application for your platform. This |
| has only been tested with the QEMU emulator as provided by the Zephyr SDK, |
| but it should work with other supported hardware as long as they have enough |
| memory, the network stack has TCP enabled, and the connectivity hardware is |
| supported. |
| |
| As far as the software goes, this has been tested with the official `gnatsd |
| <https://github.com/nats-io/gnatsd>`__ for the server, and the official |
| `go-nats <https://github.com/nats-io/go-nats>`__ client library. Both the |
| server and clients were set up as per instructions found in their respective |
| ``README.md`` files. |
| |
| The client was a one-off test that is basically the same code provided in |
| the `Basic Usage |
| <https://github.com/nats-io/go-nats/blob/e6bb81b5a5f37ef7bf364bb6276e13813086c6ee/README.md#basic-usage>`__ |
| section as found in the ``go-nats`` README file, however, subscribing to the |
| topic used in this sample: ``led0``, and publishing values as described |
| above (``on``, ``off``, and ``toggle``). |
| |
| Library Usage |
| ************* |
| |
| Allocate enough space for a ``struct nats``, setting a few callbacks so |
| that you're notified as events happen: |
| |
| :: |
| |
| struct nats nats_ctx = { |
| .on_auth_required = on_auth_required, |
| .on_message = on_message |
| }; |
| |
| The ``on_auth_required()`` and ``on_message()`` functions are part of |
| your application, and each must have these signatures: |
| |
| :: |
| |
| int on_auth_required(struct nats *nats, char **user, char **pass); |
| int on_message(struct nats *nats, struct nats_msg *msg); |
| |
| Both functions should return 0 to signal that they could successfully |
| handle their role, and a negative value, if they couldn't for any |
| reason. It's recommended to use a negative integer as provided by |
| errno.h in order to ease debugging. |
| |
| The first function, ``on_auth_required()``, is called if the server |
| notifies that it requires authentication. It's not going to be called if |
| that's not the case, so it is optional. However, if the server asks for |
| credentials and this function is not provided, the connection will be |
| closed and an error will be returned by ``nats_connect()``. |
| |
| The second function, ``on_message()``, will be called whenever the |
| server has been notified of a value change. The ``struct nats_msg`` has the |
| following fields: |
| |
| :: |
| |
| struct nats_msg { |
| const char *subject; |
| const char *sid; |
| const char *reply_to; |
| }; |
| |
| The field ``reply_to`` may be passed directly to ``nats_publish()``, |
| in order to publish a reply to this message. If it's ``NULL`` (no |
| reply-to field in the message from the server), the |
| ``nats_publish()`` function will not reply to a specific mailbox and |
| will just update the topic value. |
| |
| In order to manage topic subscription, these functions can be used: |
| |
| :: |
| |
| int nats_subscribe(struct nats *nats, const char *subject, |
| const char *queue_group, const char *sid); |
| |
| ``subject`` and ``sid`` are validated so that they're actually valid |
| per the protocol rules. ``-EINVAL`` is returned if they're not. |
| |
| If ``queue_group`` is NULL, it's not sent to the server. |
| |
| :: |
| |
| int nats_unsubscribe(struct nats *nats, const char *sid, |
| size_t max_msgs); |
| |
| ``sid`` is validated so it's actually valid per the protocol rules. |
| -EINVAL is returned if it's not. |
| |
| ``max_msgs`` specifies the number of messages that the server will |
| send before actually unsubscribing the message. Can be 0 to |
| immediately unsubscribe. (See note below.) |
| |
| Both of these functions will return ``-ENOMEM`` if they couldn't build |
| the message to transmit to the server. They can also return any error |
| that ``net_context_send()`` can return. |
| |
| Note: In order to conserve resources, the library implementation will not |
| make note of subscribed topics. Both ``nats_subscribe()`` and |
| ``nats_unsubscribe()`` functions will only notify the server that the client |
| is either interested or uninterested in a particular topic. The |
| ``on_message()`` callback may be called to notify of changes in topics that |
| have not been subscribed to (or have been recently unsubscribed). It's up |
| to the application to decide to ignore the message. |
| |
| Topics can be published by using the following function: |
| |
| :: |
| |
| int nats_publish(struct nats *nats, const char *subject, |
| const char *reply_to, const char *payload, |
| size_t payload_len); |
| |
| As usual, ``subject`` is validated and ``-EINVAL`` will be returned if |
| it's in an invalid format. The ``reply_to`` field can be ``NULL``, in |
| which case, subscribers to this topic won't receive this information as |
| well. |
| |
| As ``net_subscribe()`` and ``net_unsubscribe()``, this function can |
| return ``-ENOMEM`` or any other errors that ``net_context_send()`` |
| returns. |