ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
nats.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file nats.h
6 * @brief NATS client protocol codec (PC_ENABLE_NATS) - zero-heap builder + parser for the
7 * text-based NATS pub/sub protocol, so a device can be a NATS client over the shipped
8 * outbound client transport.
9 *
10 * NATS is a small, line-oriented protocol; every control line ends with CRLF and fields are
11 * space-separated:
12 * @code
13 * CONNECT {json} // client -> server
14 * PUB <subject> [reply-to] <#bytes>\r\n<payload> // client -> server
15 * SUB <subject> [queue] <sid> // client -> server
16 * UNSUB <sid> [max] // client -> server
17 * MSG <subject> <sid> [reply-to] <#bytes>\r\n<payload> // server -> client
18 * PING / PONG / +OK / -ERR <msg> / INFO {json}
19 * @endcode
20 * Only PUB and MSG carry a payload (the byte count precedes a CRLF, then that many payload
21 * octets, then a trailing CRLF).
22 *
23 * The builders write a control line (plus payload) into a caller buffer; the parser decodes
24 * one inbound message at the buffer head and reports the bytes consumed. Line formats per the
25 * NATS client protocol reference.
26 *
27 * @author Douglas Quigg (dstroy0)
28 * @date 2026
29 */
30
31#ifndef PROTOCORE_NATS_H
32#define PROTOCORE_NATS_H
33
34#include "protocore_config.h"
35
36#if PC_ENABLE_NATS
37
38#include <stddef.h>
39#include <stdint.h>
40
41// ---- builders (return bytes written, or 0 on overflow / bad input) ----
42
43/** @brief CONNECT: `CONNECT <options_json>\r\n`. */
44size_t pc_nats_build_connect(char *buf, size_t cap, const char *options_json);
45
46/** @brief PUB: `PUB <subject> [reply_to] <len>\r\n<payload>\r\n` (@p reply_to may be null). */
47size_t pc_nats_build_pub(char *buf, size_t cap, const char *subject, const char *reply_to, const uint8_t *payload,
48 size_t payload_len);
49
50/**
51 * @brief HPUB (headers publish, NATS 2.2+): `HPUB <subject> [reply_to] <hdr_len> <total_len>\r\n<headers>
52 * <payload>\r\n`. @p headers is the pre-formatted header block (e.g. `NATS/1.0\r\nKey: Value\r\n\r\n`),
53 * which must be non-empty; the two length fields are the header-block length and header+payload.
54 */
55size_t pc_nats_build_hpub(char *buf, size_t cap, const char *subject, const char *reply_to, const char *headers,
56 size_t headers_len, const uint8_t *payload, size_t payload_len);
57
58/** @brief SUB: `SUB <subject> [queue] <sid>\r\n` (@p queue may be null). */
59size_t pc_nats_build_sub(char *buf, size_t cap, const char *subject, const char *queue, const char *sid);
60
61/** @brief UNSUB: `UNSUB <sid> [max]\r\n` (@p with_max controls the optional max-messages field). */
62size_t pc_nats_build_unsub(char *buf, size_t cap, const char *sid, uint32_t max_msgs, bool with_max);
63
64/** @brief PING: `PING\r\n`. */
65size_t pc_nats_build_ping(char *buf, size_t cap);
66
67/** @brief PONG: `PONG\r\n`. */
68size_t pc_nats_build_pong(char *buf, size_t cap);
69
70/** @brief Inbound message kind. */
71enum class NatsMsgType : uint8_t
72{
73 NATS_MSG, ///< a delivered message (subject/sid/reply/payload set)
74 NATS_INFO, ///< server INFO (arg = the JSON)
75 NATS_PING,
76 NATS_PONG,
77 NATS_OK, ///< +OK
78 NATS_ERR, ///< -ERR (arg = the message)
79 NATS_UNKNOWN, ///< unrecognized verb
80};
81
82/** @brief One parsed inbound protocol message. String/payload fields point INTO the buffer. */
83struct NatsMsg
84{
85 NatsMsgType type;
86 const char *subject; ///< MSG only
87 size_t subject_len;
88 const char *sid; ///< MSG only
89 size_t sid_len;
90 const char *reply; ///< MSG reply-to (may be empty)
91 size_t reply_len;
92 const uint8_t *payload; ///< MSG payload
93 size_t payload_len;
94 const char *headers; ///< HMSG header block (`NATS/1.0\r\n...`); nullptr for a header-less MSG
95 size_t headers_len;
96 const char *arg; ///< INFO / -ERR argument (the rest of the control line)
97 size_t arg_len;
98};
99
100/**
101 * @brief Parse one inbound message at the head of [buf, buf+len).
102 * @param consumed receives the message length (control line + any payload) so the caller can advance.
103 * @return true on a complete message; false if the control line or the MSG payload is not yet buffered.
104 */
105bool pc_nats_parse(const char *buf, size_t len, NatsMsg *out, size_t *consumed);
106
107#endif // PC_ENABLE_NATS
108
109#endif // PROTOCORE_NATS_H
User-facing configuration for ProtoCore.