24static void put_str(Buf *b,
const char *s)
33 size_t n = strnlen(s, b->cap + 1);
34 if (b->pos + n > b->cap)
39 memcpy(b->p + b->pos, s, n);
43static void put_bytes(Buf *b,
const uint8_t *d,
size_t n)
47 if (b->pos + n > b->cap)
53 memcpy(b->p + b->pos, d, n);
57static void put_ch(Buf *b,
char c)
61 if (b->pos + 1 > b->cap)
69static void put_uint(Buf *b, uint64_t v)
79 rev[r++] = (char)(
'0' + (
int)(v % 10));
84 put_bytes(b, (
const uint8_t *)tmp, n);
87static size_t finish(Buf *b)
96size_t nats_build_connect(
char *buf,
size_t cap,
const char *options_json)
98 if (!buf || !options_json)
100 Buf b = {buf, cap, 0,
true};
101 put_str(&b,
"CONNECT ");
102 put_str(&b, options_json);
107size_t nats_build_pub(
char *buf,
size_t cap,
const char *subject,
const char *reply_to,
const uint8_t *payload,
110 if (!buf || !subject || (payload_len && !payload))
112 Buf b = {buf, cap, 0,
true};
114 put_str(&b, subject);
118 put_str(&b, reply_to);
121 put_uint(&b, payload_len);
123 put_bytes(&b, payload, payload_len);
128size_t nats_build_sub(
char *buf,
size_t cap,
const char *subject,
const char *queue,
const char *sid)
130 if (!buf || !subject || !sid)
132 Buf b = {buf, cap, 0,
true};
134 put_str(&b, subject);
146size_t nats_build_unsub(
char *buf,
size_t cap,
const char *sid, uint32_t max_msgs,
bool with_max)
150 Buf b = {buf, cap, 0,
true};
151 put_str(&b,
"UNSUB ");
156 put_uint(&b, max_msgs);
162size_t nats_build_ping(
char *buf,
size_t cap)
164 Buf b = {buf, cap, 0,
true};
165 put_str(&b,
"PING\r\n");
169size_t nats_build_pong(
char *buf,
size_t cap)
171 Buf b = {buf, cap, 0,
true};
172 put_str(&b,
"PONG\r\n");
177static size_t find_crlf(
const char *buf,
size_t len)
179 for (
size_t i = 0; i + 1 < len; i++)
180 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n')
186static bool parse_uint(
const char *s,
size_t n,
size_t *out)
192 for (
size_t i = 0; i < n; i++)
194 if (s[i] <
'0' || s[i] >
'9')
196 v = v * 10 + (size_t)(s[i] -
'0');
203static bool verb_is(
const char *buf,
size_t line_len,
const char *op)
205 size_t n = strnlen(op, line_len + 1);
208 if (memcmp(buf, op, n) != 0)
210 return line_len == n || buf[n] ==
' ' || buf[n] ==
'\t';
213bool nats_parse(
const char *buf,
size_t len, NatsMsg *out,
size_t *consumed)
215 if (!buf || !out || !consumed)
217 size_t crlf = find_crlf(buf, len);
220 size_t line_len = crlf;
221 size_t after_line = crlf + 2;
223 out->subject = out->sid = out->reply = out->arg =
nullptr;
224 out->subject_len = out->sid_len = out->reply_len = out->arg_len = 0;
225 out->payload =
nullptr;
226 out->payload_len = 0;
228 if (verb_is(buf, line_len,
"PING"))
230 out->type = NatsMsgType::NATS_PING;
231 *consumed = after_line;
234 if (verb_is(buf, line_len,
"PONG"))
236 out->type = NatsMsgType::NATS_PONG;
237 *consumed = after_line;
240 if (verb_is(buf, line_len,
"+OK"))
242 out->type = NatsMsgType::NATS_OK;
243 *consumed = after_line;
246 if (verb_is(buf, line_len,
"-ERR") || verb_is(buf, line_len,
"INFO"))
248 out->type = (buf[0] ==
'-') ? NatsMsgType::NATS_ERR : NatsMsgType::NATS_INFO;
250 while (a < line_len && (buf[a] ==
' ' || buf[a] ==
'\t'))
253 out->arg_len = line_len - a;
254 *consumed = after_line;
257 if (verb_is(buf, line_len,
"MSG"))
264 while (i < line_len && ntok < 4)
266 while (i < line_len && (buf[i] ==
' ' || buf[i] ==
'\t'))
271 while (i < line_len && buf[i] !=
' ' && buf[i] !=
'\t')
273 tok[ntok] = buf + start;
274 tlen[ntok] = i - start;
277 if (ntok != 3 && ntok != 4)
280 if (!parse_uint(tok[ntok - 1], tlen[ntok - 1], &size))
284 if (after_line + 2 > len || size > len - after_line - 2)
286 size_t total = after_line + size + 2;
287 out->type = NatsMsgType::NATS_MSG;
288 out->subject = tok[0];
289 out->subject_len = tlen[0];
291 out->sid_len = tlen[1];
295 out->reply_len = tlen[2];
297 out->payload = (
const uint8_t *)(buf + after_line);
298 out->payload_len = size;
303 out->type = NatsMsgType::NATS_UNKNOWN;
304 *consumed = after_line;
NATS client protocol codec (DETWS_ENABLE_NATS) - zero-heap builder + parser for the text-based NATS p...