{"id":51043556,"url":"https://github.com/qoretechnologies/module-nats","last_synced_at":"2026-06-22T12:01:44.545Z","repository":{"id":344113796,"uuid":"1180120994","full_name":"qoretechnologies/module-nats","owner":"qoretechnologies","description":"Qore NATS module","archived":false,"fork":false,"pushed_at":"2026-05-02T17:56:08.000Z","size":319,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"develop","last_synced_at":"2026-05-02T19:28:22.080Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qoretechnologies.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING.MIT","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-12T18:10:50.000Z","updated_at":"2026-05-02T17:56:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/qoretechnologies/module-nats","commit_stats":null,"previous_names":["qoretechnologies/module-nats"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/qoretechnologies/module-nats","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qoretechnologies%2Fmodule-nats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qoretechnologies%2Fmodule-nats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qoretechnologies%2Fmodule-nats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qoretechnologies%2Fmodule-nats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qoretechnologies","download_url":"https://codeload.github.com/qoretechnologies/module-nats/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qoretechnologies%2Fmodule-nats/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34647750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-22T02:00:06.391Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-22T12:01:43.775Z","updated_at":"2026-06-22T12:01:44.540Z","avatar_url":"https://github.com/qoretechnologies.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Qore NATS Module\n\nQore module for [NATS](https://nats.io/) messaging, providing core publish/subscribe, request/reply, JetStream persistent messaging, and Key-Value store support.\n\n## Features\n\n- **Core NATS**: publish/subscribe, request/reply, queue groups, wildcard subscriptions\n- **JetStream**: stream and consumer management, publish with acknowledgment, push and pull subscribe\n- **Key-Value Store**: put, get, create, update (CAS), delete, purge, list keys, history\n- **TLS**: encrypted connections with mutual TLS support\n- **Authentication**: token, username/password, NKey, and credentials file\n- **Channel-based subscriptions**: Go-style async iteration with `foreach` and `channel_select()`\n- **Data providers**: `NatsDataProvider` and `NatsJetStreamDataProvider` for Qore data provider framework integration\n- **Connection providers**: `nats://` and `tls://` connection schemes\n\n## Requirements\n\n- Qore 2.0+\n- [nats.c](https://github.com/nats-io/nats.c) library (libnats)\n\n## Building\n\n```bash\nmkdir build \u0026\u0026 cd build\ncmake ..\nmake\nsudo make install\n```\n\nTo install to a specific prefix:\n\n```bash\ncmake -DCMAKE_INSTALL_PREFIX=/usr/local ..\n```\n\n## Quick Start\n\n### Publish / Subscribe\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\n\n# Subscribe using channel-based async subscription\nNatsChannelSubscription sub = client.channelSubscribe(\"events.\u003e\");\n\n# Publish a message\nclient.publishString(\"events.log\", \"Hello NATS!\");\n\n# Receive the message\n*hash\u003cNatsMsgInfo\u003e msg = sub.recv(5s);\nif (msg) {\n    printf(\"Received on %s: %s\\n\", msg.subject, msg.data.toString());\n}\n\nsub.close();\nclient.close();\n```\n\n### Request / Reply\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\n\n# Set up a responder in the background\nNatsChannelSubscription sub = client.channelSubscribe(\"service.echo\");\nbackground sub () {\n    foreach hash\u003cNatsMsgInfo\u003e msg in (sub) {\n        if (msg.reply) {\n            client.publishString(msg.reply, \"Echo: \" + msg.data.toString());\n        }\n    }\n}();\n\n# Send a request and wait for the reply\nstring reply = client.requestString(\"service.echo\", \"Hello!\", 5s);\nprintf(\"Reply: %s\\n\", reply);\n\nsub.close();\nclient.close();\n```\n\n### Queue Groups\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\n\n# Create queue subscribers -- messages are load-balanced across the group\nNatsChannelSubscription sub1 = client.channelQueueSubscribe(\"work.tasks\", \"workers\");\nNatsChannelSubscription sub2 = client.channelQueueSubscribe(\"work.tasks\", \"workers\");\n\n# Publish tasks -- each goes to only one worker\nfor (int i = 0; i \u003c 10; ++i) {\n    client.publishString(\"work.tasks\", sprintf(\"task-%d\", i));\n}\n\nsub1.close();\nsub2.close();\nclient.close();\n```\n\n### Wildcard Subscriptions\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\n\n# '*' matches a single token\nNatsChannelSubscription sub1 = client.channelSubscribe(\"orders.*\");\n\n# '\u003e' matches one or more tokens (must be last)\nNatsChannelSubscription sub2 = client.channelSubscribe(\"events.\u003e\");\n\nclient.publishString(\"orders.new\", \"order-1\");       # matched by sub1\nclient.publishString(\"events.log.error\", \"oops\");    # matched by sub2\n\nsub1.close();\nsub2.close();\nclient.close();\n```\n\n### Callback-Based Subscriptions\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\n\n# Subscribe with a callback — messages are delivered in a background thread\nNatsChannelSubscription sub = client.subscribe(\"events.\u003e\", sub (hash\u003cNatsMsgInfo\u003e msg) {\n    printf(\"Got %s: %s\\n\", msg.subject, msg.data.toString());\n});\n\n# Do other work while messages are processed in the background\nsleep(10s);\n\nsub.close();\nclient.close();\n```\n\n### Error Handling\n\nNATS operations raise exceptions on failure. Exception codes follow the pattern `NATS-\u003cCATEGORY\u003e-ERROR`:\n\n| Exception | Description |\n|---|---|\n| `NATS-CONNECTION-ERROR` | Connection or configuration failures |\n| `NATS-PUBLISH-ERROR` | Publish failures |\n| `NATS-SUBSCRIBE-ERROR` | Subscription failures |\n| `NATS-REQUEST-ERROR` | Request/reply failures |\n| `NATS-TIMEOUT-ERROR` | Operation timeouts |\n| `NATS-JETSTREAM-ERROR` | JetStream failures (includes JetStream error code) |\n| `NATS-KV-ERROR` | Key-Value store failures |\n| `NATS-AUTH-ERROR` | Authentication failures |\n| `NATS-TLS-ERROR` | TLS/SSL failures |\n\n```qore\n#!/usr/bin/env qr\n\n%requires NatsUtil\n\ntry {\n    NatsClient client(\"nats://invalid-host:4222\");\n} catch (hash\u003cExceptionInfo\u003e ex) {\n    if (ex.err == \"NATS-CONNECTION-ERROR\") {\n        printf(\"Failed to connect: %s\\n\", ex.desc);\n    }\n}\n\nNatsClient client(\"nats://localhost:4222\");\ntry {\n    string reply = client.requestString(\"service.echo\", \"hello\", 500ms);\n} catch (hash\u003cExceptionInfo\u003e ex) {\n    if (ex.err == \"NATS-TIMEOUT-ERROR\") {\n        printf(\"Request timed out: %s\\n\", ex.desc);\n    }\n}\n```\n\n### NatsConnection vs NatsClient\n\nThe module provides two levels of API:\n\n- **NatsConnection** (binary module): Low-level connection with binary publish/subscribe and direct JetStream/KV access. Use when you need direct control or binary data.\n- **NatsClient** (NatsUtil module): High-level client with string operations, channel-based async subscriptions, and callback subscriptions. Use for most applications.\n\n`NatsClient.getConnection()` returns the underlying `NatsConnection` for accessing JetStream and KV APIs.\n\n### JetStream Publish / Subscribe\n\n```qore\n#!/usr/bin/env qr\n\n%requires nats\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\nJetStreamContext js = client.getConnection().jetStream();\n\n# Create a stream\njs.addStream(\u003cNatsStreamConfig\u003e{\n    \"name\": \"ORDERS\",\n    \"subjects\": (\"orders.\u003e\",),\n});\n\n# Publish with acknowledgment\nhash\u003cNatsPubAck\u003e ack = js.publish(\"orders.new\", binary(\"order-123\"));\nprintf(\"Published to stream %s, seq %d\\n\", ack.stream, ack.sequence);\n\n# Subscribe and receive\nNatsSubscription sub = js.subscribe(\"orders.\u003e\");\n*hash\u003cNatsMsgInfo\u003e msg = sub.nextMsg(5s);\nif (msg) {\n    printf(\"Received: %s\\n\", msg.data.toString());\n    sub.ack();\n}\n\nsub.unsubscribe();\njs.deleteStream(\"ORDERS\");\nclient.close();\n```\n\n### Stream and Consumer Management\n\n```qore\n#!/usr/bin/env qr\n\n%requires nats\n\nNatsConnection conn(\"nats://localhost:4222\");\nJetStreamContext js = conn.jetStream();\n\n# Create a stream with configuration\nhash\u003cNatsStreamInfo\u003e info = js.addStream(\u003cNatsStreamConfig\u003e{\n    \"name\": \"EVENTS\",\n    \"subjects\": (\"events.\u003e\",),\n    \"retention\": NATS_RETENTION_LIMITS,\n    \"storage\": NATS_STORAGE_FILE,\n    \"max_msgs\": 1000000,\n});\n\n# Create a durable consumer\nhash\u003cNatsConsumerInfo\u003e ci = js.addConsumer(\"EVENTS\", \u003cNatsConsumerConfig\u003e{\n    \"durable_name\": \"event-processor\",\n    \"ack_policy\": NATS_ACK_EXPLICIT,\n    \"deliver_policy\": NATS_DELIVER_ALL,\n});\n\n# Get stream/consumer info\ninfo = js.getStreamInfo(\"EVENTS\");\nci = js.getConsumerInfo(\"EVENTS\", \"event-processor\");\n\n# Cleanup\njs.deleteConsumer(\"EVENTS\", \"event-processor\");\njs.deleteStream(\"EVENTS\");\nconn.close();\n```\n\n### Key-Value Store\n\n```qore\n#!/usr/bin/env qr\n\n%requires nats\n%requires NatsUtil\n\nNatsClient client(\"nats://localhost:4222\");\nJetStreamContext js = client.getConnection().jetStream();\n\n# Create a KV bucket\nNatsKeyValueStore kv = js.createKeyValue(\u003cNatsKVConfig\u003e{\n    \"bucket\": \"config\",\n    \"history\": 5,\n});\n\n# Put values\nint rev1 = kv.putString(\"app.name\", \"MyApp\");\nint rev2 = kv.putString(\"app.version\", \"1.0\");\n\n# Get a value\n*hash\u003cNatsKVEntry\u003e entry = kv.get(\"app.name\");\nif (entry) {\n    printf(\"Key: %s, Value: %s, Rev: %d\\n\",\n        entry.key, entry.value.toString(), entry.revision);\n}\n\n# CAS update\nint rev3 = kv.update(\"app.name\", binary(\"NewApp\"), rev1);\n\n# List keys and get history\nlist\u003cstring\u003e keys = kv.keys();\nlist\u003chash\u003cNatsKVEntry\u003e\u003e hist = kv.history(\"app.name\");\n\n# Cleanup\njs.deleteKeyValue(\"config\");\nclient.close();\n```\n\n### TLS Connections\n\n```qore\n#!/usr/bin/env qr\n\n%requires nats\n\n# TLS with server verification\nNatsConnection conn(\u003cNatsConnectionOptions\u003e{\n    \"url\": \"tls://nats.example.com:4222\",\n    \"tls\": \u003cNatsTlsOptions\u003e{\n        \"ca_cert\": \"/path/to/ca.crt\",\n    },\n});\n\n# Mutual TLS with client certificate\nNatsConnection conn2(\u003cNatsConnectionOptions\u003e{\n    \"url\": \"tls://nats.example.com:4222\",\n    \"tls\": \u003cNatsTlsOptions\u003e{\n        \"ca_cert\": \"/path/to/ca.crt\",\n        \"client_cert\": \"/path/to/client.crt\",\n        \"client_key\": \"/path/to/client.key\",\n    },\n});\n```\n\n### Data Provider CLI Usage\n\n```bash\n# Core NATS: publish a message\nqdp 'nats{url=nats://localhost:4222}/publish' dor subject=events.log,data=hello\n\n# Core NATS: request/reply\nqdp 'nats{url=nats://localhost:4222}/request' dor subject=service.echo,data=hello\n\n# JetStream: create a stream\nqdp 'natsjetstream{url=nats://localhost:4222}/streams/create' dor name=ORDERS,subjects=orders.\u003e\n\n# JetStream: publish with ack\nqdp 'natsjetstream{url=nats://localhost:4222}/publish' dor subject=orders.new,data=order-123\n\n# JetStream: KV put\nqdp 'natsjetstream{url=nats://localhost:4222}/kv/put' dor bucket=config,key=app.name,value=MyApp\n\n# JetStream: KV get\nqdp 'natsjetstream{url=nats://localhost:4222}/kv/get' dor bucket=config,key=app.name\n```\n\n## License\n\nMIT -- see [COPYING.MIT](COPYING.MIT) for details.\n\nCopyright (C) 2026 Qore Technologies, s.r.o.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqoretechnologies%2Fmodule-nats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqoretechnologies%2Fmodule-nats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqoretechnologies%2Fmodule-nats/lists"}