24static void put_str(Buf *b,
const char *s)
36 size_t n = strnlen(s, b->cap + 1);
37 if (b->pos + n > b->cap)
42 memcpy(b->p + b->pos, s, n);
46static void put_bytes(Buf *b,
const uint8_t *d,
size_t n)
52 if (b->pos + n > b->cap)
59 memcpy(b->p + b->pos, d, n);
64static void put_ch(Buf *b,
char c)
70 if (b->pos + 1 > b->cap)
78static void put_uint(Buf *b, uint64_t v)
90 rev[r++] = (char)(
'0' + (
int)(v % 10));
97 put_bytes(b, (
const uint8_t *)tmp, n);
100static size_t finish(Buf *b)
113size_t pc_nats_build_connect(
char *buf,
size_t cap,
const char *options_json)
115 if (!buf || !options_json)
119 Buf b = {buf, cap, 0,
true};
120 put_str(&b,
"CONNECT ");
121 put_str(&b, options_json);
126size_t pc_nats_build_pub(
char *buf,
size_t cap,
const char *subject,
const char *reply_to,
const uint8_t *payload,
129 if (!buf || !subject || (payload_len && !payload))
133 Buf b = {buf, cap, 0,
true};
135 put_str(&b, subject);
139 put_str(&b, reply_to);
142 put_uint(&b, payload_len);
144 put_bytes(&b, payload, payload_len);
149size_t pc_nats_build_hpub(
char *buf,
size_t cap,
const char *subject,
const char *reply_to,
const char *headers,
150 size_t headers_len,
const uint8_t *payload,
size_t payload_len)
152 if (!buf || !subject || !headers || headers_len == 0 || (payload_len && !payload))
156 Buf b = {buf, cap, 0,
true};
157 put_str(&b,
"HPUB ");
158 put_str(&b, subject);
162 put_str(&b, reply_to);
165 put_uint(&b, headers_len);
167 put_uint(&b, headers_len + payload_len);
169 put_bytes(&b, (
const uint8_t *)headers, headers_len);
170 put_bytes(&b, payload, payload_len);
175size_t pc_nats_build_sub(
char *buf,
size_t cap,
const char *subject,
const char *queue,
const char *sid)
177 if (!buf || !subject || !sid)
181 Buf b = {buf, cap, 0,
true};
183 put_str(&b, subject);
195size_t pc_nats_build_unsub(
char *buf,
size_t cap,
const char *sid, uint32_t max_msgs,
bool with_max)
201 Buf b = {buf, cap, 0,
true};
202 put_str(&b,
"UNSUB ");
207 put_uint(&b, max_msgs);
213size_t pc_nats_build_ping(
char *buf,
size_t cap)
215 Buf b = {buf, cap, 0,
true};
216 put_str(&b,
"PING\r\n");
220size_t pc_nats_build_pong(
char *buf,
size_t cap)
222 Buf b = {buf, cap, 0,
true};
223 put_str(&b,
"PONG\r\n");
228static size_t find_crlf(
const char *buf,
size_t len)
230 for (
size_t i = 0; i + 1 < len; i++)
232 if (buf[i] ==
'\r' && buf[i + 1] ==
'\n')
241static bool parse_uint(
const char *s,
size_t n,
size_t *out)
250 for (
size_t i = 0; i < n; i++)
252 if (s[i] <
'0' || s[i] >
'9')
256 v = v * 10 + (size_t)(s[i] -
'0');
263static bool verb_is(
const char *buf,
size_t line_len,
const char *op)
265 size_t n = strnlen(op, line_len + 1);
270 if (memcmp(buf, op, n) != 0)
274 return line_len == n || buf[n] ==
' ' || buf[n] ==
'\t';
277bool pc_nats_parse(
const char *buf,
size_t len, NatsMsg *out,
size_t *consumed)
279 if (!buf || !out || !consumed)
283 size_t crlf = find_crlf(buf, len);
288 size_t line_len = crlf;
289 size_t after_line = crlf + 2;
291 out->subject = out->sid = out->reply = out->arg =
nullptr;
292 out->subject_len = out->sid_len = out->reply_len = out->arg_len = 0;
293 out->payload =
nullptr;
294 out->payload_len = 0;
295 out->headers =
nullptr;
296 out->headers_len = 0;
298 if (verb_is(buf, line_len,
"PING"))
300 out->type = NatsMsgType::NATS_PING;
301 *consumed = after_line;
304 if (verb_is(buf, line_len,
"PONG"))
306 out->type = NatsMsgType::NATS_PONG;
307 *consumed = after_line;
310 if (verb_is(buf, line_len,
"+OK"))
312 out->type = NatsMsgType::NATS_OK;
313 *consumed = after_line;
316 if (verb_is(buf, line_len,
"-ERR") || verb_is(buf, line_len,
"INFO"))
318 out->type = (buf[0] ==
'-') ? NatsMsgType::NATS_ERR : NatsMsgType::NATS_INFO;
320 while (a < line_len && (buf[a] ==
' ' || buf[a] ==
'\t'))
325 out->arg_len = line_len - a;
326 *consumed = after_line;
329 if (verb_is(buf, line_len,
"MSG"))
336 while (i < line_len && ntok < 4)
338 while (i < line_len && (buf[i] ==
' ' || buf[i] ==
'\t'))
347 while (i < line_len && buf[i] !=
' ' && buf[i] !=
'\t')
351 tok[ntok] = buf + start;
352 tlen[ntok] = i - start;
355 if (ntok != 3 && ntok != 4)
360 if (!parse_uint(tok[ntok - 1], tlen[ntok - 1], &size))
366 if (after_line + 2 > len || size > len - after_line - 2)
370 size_t total = after_line + size + 2;
371 out->type = NatsMsgType::NATS_MSG;
372 out->subject = tok[0];
373 out->subject_len = tlen[0];
375 out->sid_len = tlen[1];
379 out->reply_len = tlen[2];
381 out->payload = (
const uint8_t *)(buf + after_line);
382 out->payload_len = size;
386 if (verb_is(buf, line_len,
"HMSG"))
393 while (i < line_len && ntok < 5)
395 while (i < line_len && (buf[i] ==
' ' || buf[i] ==
'\t'))
404 while (i < line_len && buf[i] !=
' ' && buf[i] !=
'\t')
408 tok[ntok] = buf + start;
409 tlen[ntok] = i - start;
412 if (ntok != 4 && ntok != 5)
416 size_t hdr_len, total_size;
417 if (!parse_uint(tok[ntok - 2], tlen[ntok - 2], &hdr_len) ||
418 !parse_uint(tok[ntok - 1], tlen[ntok - 1], &total_size))
422 if (hdr_len > total_size)
427 if (after_line + 2 > len || total_size > len - after_line - 2)
431 size_t total = after_line + total_size + 2;
432 out->type = NatsMsgType::NATS_MSG;
433 out->subject = tok[0];
434 out->subject_len = tlen[0];
436 out->sid_len = tlen[1];
440 out->reply_len = tlen[2];
442 out->headers = buf + after_line;
443 out->headers_len = hdr_len;
444 out->payload = (
const uint8_t *)(buf + after_line + hdr_len);
445 out->payload_len = total_size - hdr_len;
450 out->type = NatsMsgType::NATS_UNKNOWN;
451 *consumed = after_line;
NATS client protocol codec (PC_ENABLE_NATS) - zero-heap builder + parser for the text-based NATS pub/...