Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
nats --help
nats cheatnats account infoConnection Information:
Client ID: 8
Client IP: 127.0.0.1
RTT: 178.545µs
Headers Supported: true
Maximum Payload: 1.0 MiB
Connected URL: nats://localhost:4222
Connected Address: 127.0.0.1:4222
Connected Server ID: NCCOHA6ONXJOGAEZP4WPU4UJ3IQP2VVXEPRKTQCGBCW4IL4YYW4V4KKL
JetStream Account Information:
Memory: 0 B of 5.7 GiB
Storage: 0 B of 11 GiB
Streams: 0 of Unlimited
Max Consumers: unlimitedprof_port = 65432curl -o mem.prof http://localhost:65432/debug/pprof/allocscurl -o cpu.prof http://localhost:65432/debug/pprof/profile?seconds=30nats-server --signal <command>nats-server --signal ldmnats-server --signal stop=<pid>nats-server --signal stop=/path/to/pidfilenats-server --signal ldm=12*jetstream : {
cipher: chachapoly
key : "6dYfBV0zzEkR3vxZCNjxmnVh/aIqgid1"
}jetstream : {
cipher: chachapoly
key: $JS_KEY
}JS_KEY="mykey" nats-server -c js.confjetstream {
store_dir: nats
max_file_store: 10G
tpm {
keys_file: "keys"
encryption_password: "pwd"
}
}Error decrypting our stream metafile: chacha20poly1305: message authentication failednats stream backup ORDERS '/data/js-backup/backup1'Starting backup of Stream "ORDERS" with 13 data blocks
2.4 MiB/s [====================================================================] 100%
Received 13 MiB bytes of compressed data in 3368 chunks for stream "ORDERS" in 1.223428188s, 813 MiB uncompressednats stream restore '/data/js-backup/backup1'Starting restore of Stream "ORDERS" from file "/data/js-backup/backup1"
13 MiB/s [====================================================================] 100%
Restored stream "ORDERS" in 937.071149ms
Information for Stream ORDERS
Configuration:
Subjects: ORDERS.>
...nats account backup /data/js-backupPerforming backup of all streams to /data/js-backup
Streams: 3
Size: 14 KiB
Consumers: 2
Starting backup of Stream "EVENTS" with 0 B
Received 1.5 KiB compressed data in 2 chunks for stream "EVENTS" in 0s, 16 KiB uncompressed
Starting backup of Stream "ORDERS" with 55 B
Received 976 B compressed data in 2 chunks for stream "ORDERS" in 1ms, 9.5 KiB uncompressed
Starting backup of Stream "WORK" with 7.3 KiB
Received 7.3 KiB compressed data in 2 chunks for stream "WORK" in 0s, 30 KiB uncompressednats account restore /data/js-backupRestoring backup of all 3 streams in directory "/data/js-backup"
Starting restore of Stream "EVENTS" from file "/data/js-backup/EVENTS"
Restored stream "EVENTS" in 0s
...
Starting restore of Stream "ORDERS" from file "/data/js-backup/ORDERS"
Restored stream "ORDERS" in 1ms
...
Starting restore of Stream "WORK" from file "/data/js-backup/WORK"
Restored stream "WORK" in 0s
...nats con add --sample 100? Select a Stream ORDERS
? Consumer name NEW
? Delivery target
? Start policy (all, last, 1h, msg sequence) all
? Filter Stream by subject (blank for all) ORDERS.received
? Maximum Allowed Deliveries 20
Information for Consumer ORDERS > NEW
Configuration:
Durable Name: NEW
Pull Mode: true
Subject: ORDERS.received
Deliver All: true
Deliver Last: false
Ack Policy: explicit
Ack Wait: 30s
Replay Policy: instant
Maximum Deliveries: 20
Sampling Rate: 100
State:
Last Delivered Message: Consumer sequence: 1 Stream sequence: 1
Acknowledgment floor: Consumer sequence: 0 Stream sequence: 0
Pending Messages: 0
Redelivered Messages: 0nats con add ORDERS DISPATCH --filter ORDERS.processed --ack explicit --pull --deliver all --sample 100 --max-deliver 20nats con add ORDERS MONITOR --config monitor.jsonnats con add? Select a Stream ORDERS
? Consumer name MONITOR
? Delivery target monitor.ORDERS
? Start policy (all, last, 1h, msg sequence) last
? Acknowledgement policy none
? Replay policy instant
? Filter Stream by subject (blank for all)
? Maximum Allowed Deliveries -1
Information for Consumer ORDERS > MONITOR
Configuration:
Durable Name: MONITOR
Delivery Subject: monitor.ORDERS
Deliver All: false
Deliver Last: true
Ack Policy: none
Replay Policy: instant
State:
Last Delivered Message: Consumer sequence: 1 Stream sequence: 3
Acknowledgment floor: Consumer sequence: 0 Stream sequence: 2
Pending Messages: 0
Redelivered Messages: 0nats con add ORDERS MONITOR --ack none --target monitor.ORDERS --deliver last --replay instant --filter ''nats con add ORDERS --config monitor.jsonnats con ls ORDERSConsumers for Stream ORDERS:
DISPATCH
MONITOR
NEW$ nats con info ORDERS DISPATCH
Information for Consumer ORDERS > DISPATCH
Configuration:
Durable Name: DISPATCH
Pull Mode: true
Subject: ORDERS.processed
Deliver All: true
Deliver Last: false
Ack Policy: explicit
Ack Wait: 30s
Replay Policy: instant
Sampling Rate: 100
State:
Last Delivered Message: Consumer sequence: 1 Stream sequence: 1
Acknowledgment floor: Consumer sequence: 0 Stream sequence: 0
Pending Messages: 0
Redelivered Messages: 0nats pub ORDERS.processed "order 1"
nats pub ORDERS.processed "order 2"
nats pub ORDERS.processed "order 3"nats con next ORDERS DISPATCH--- received on ORDERS.processed
order 1
Acknowledged messagenats con next ORDERS DISPATCH--- received on ORDERS.processed
order 2
Acknowledged messagenats req '$JS.API.CONSUMER.MSG.NEXT.ORDERS.DISPATCH' ''Published [$JS.API.CONSUMER.MSG.NEXT.ORDERS.DISPATCH] : ''
Received [ORDERS.processed] : 'order 3'nats con info ORDERS MONITOR...
Delivery Subject: monitor.ORDERS
...nats sub monitor.ORDERSListening on [monitor.ORDERS]
[#3] Received on [ORDERS.processed]: 'order 3'
[#4] Received on [ORDERS.processed]: 'order 4'http_port: 8222nats-server -m 8222{
"server_id": "NACDVKFBUW4C4XA24OOT6L4MDP56MW76J5RJDFXG7HLABSB46DCMWCOW",
"version": "2.0.0",
"proto": 1,
"go": "go1.12",
"host": "0.0.0.0",
"port": 4222,
"max_connections": 65536,
"ping_interval": 120000000000,
"ping_max": 2,
"http_host": "0.0.0.0",
"http_port": 8222,
"https_port": 0,
"auth_timeout": 1,
"max_control_line": 4096,
"max_payload": 1048576,
"max_pending": 67108864,
"cluster": {},
"gateway": {},
"leaf": {},
"tls_timeout": 0.5,
"write_deadline": 2000000000,
"start": "2019-06-24T14:24:43.928582-07:00",
"now": "2019-06-24T14:24:46.894852-07:00",
"uptime": "2s",
"mem": 9617408,
"cores": 4,
"gomaxprocs": 4,
"cpu": 0,
"connections": 0,
"total_connections": 0,
"routes": 0,
"remotes": 0,
"leafnodes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"slow_consumers": 2,
"subscriptions": 0,
"http_req_stats": {
"/": 0,
"/connz": 0,
"/gatewayz": 0,
"/routez": 0,
"/subsz": 0,
"/varz": 1
},
"config_load_time": "2019-06-24T14:24:43.928582-07:00",
"slow_consumer_stats": {
"clients": 1,
"routes": 1,
"gateways": 0,
"leafs": 0
}
}{
"server_id": "NACDVKFBUW4C4XA24OOT6L4MDP56MW76J5RJDFXG7HLABSB46DCMWCOW",
"now": "2019-06-24T14:28:16.520365-07:00",
"num_connections": 2,
"total": 2,
"offset": 0,
"limit": 1024,
"connections": [
{
"cid": 5,
"kind": "Client",
"type": "nats",
"ip": "127.0.0.1",
"port": 62714,
"start": "2021-09-09T23:16:43.040862Z",
"last_activity": "2021-09-09T23:16:43.042364Z",
"rtt": "95µs",
"uptime": "5s",
"idle": "5s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 1,
"name": "NATS Benchmark",
"lang": "go",
"version": "1.12.1"
},
{
"cid": 6,
"kind": "Client",
"type": "nats",
"ip": "127.0.0.1",
"port": 62715,
"start": "2021-09-09T23:16:43.042557Z",
"last_activity": "2021-09-09T23:16:43.042811Z",
"rtt": "100µs",
"uptime": "5s",
"idle": "5s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 1,
"name": "NATS Benchmark",
"lang": "go",
"version": "1.12.1"
},
{
"cid": 7,
"kind": "Client",
"type": "mqtt",
"ip": "::1",
"port": 62718,
"start": "2021-09-09T23:16:45.391459Z",
"last_activity": "2021-09-09T23:16:45.395869Z",
"rtt": "0s",
"uptime": "2s",
"idle": "2s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 2,
"mqtt_client": "mqtt_sub"
}
]
}{
"server_id": "NACDVKFBUW4C4XA24OOT6L4MDP56MW76J5RJDFXG7HLABSB46DCMWCOW",
"now": "2019-06-24T14:29:16.046656-07:00",
"num_routes": 1,
"routes": [
{
"rid": 1,
"remote_id": "de475c0041418afc799bccf0fdd61b47",
"did_solicit": true,
"ip": "127.0.0.1",
"port": 61791,
"pending_size": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0
}
]
}{
"server_id": "NANVBOU62MDUWTXWRQ5KH3PSMYNCHCEUHQV3TW3YH7WZLS7FMJE6END6",
"now": "2019-07-24T18:02:55.597398-06:00",
"name": "region1",
"host": "2601:283:4601:1350:1895:efda:2010:95a1",
"port": 4501,
"outbound_gateways": {
"region2": {
"configured": true,
"connection": {
"cid": 7,
"ip": "127.0.0.1",
"port": 5500,
"start": "2019-07-24T18:02:48.765621-06:00",
"last_activity": "2019-07-24T18:02:48.765621-06:00",
"uptime": "6s",
"idle": "6s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0,
"name": "NCXBIYWT7MV7OAQTCR4QTKBN3X3HDFGSFWTURTCQ22ZZB6NKKJPO7MN4"
}
},
"region3": {
"configured": true,
"connection": {
"cid": 5,
"ip": "::1",
"port": 6500,
"start": "2019-07-24T18:02:48.764685-06:00",
"last_activity": "2019-07-24T18:02:48.764685-06:00",
"uptime": "6s",
"idle": "6s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0,
"name": "NCVS7Q65WX3FGIL2YQRLI77CE6MQRWO2Y453HYVLNMBMTVLOKMPW7R6K"
}
}
},
"inbound_gateways": {
"region2": [
{
"configured": false,
"connection": {
"cid": 9,
"ip": "::1",
"port": 52029,
"start": "2019-07-24T18:02:48.76677-06:00",
"last_activity": "2019-07-24T18:02:48.767096-06:00",
"uptime": "6s",
"idle": "6s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0,
"name": "NCXBIYWT7MV7OAQTCR4QTKBN3X3HDFGSFWTURTCQ22ZZB6NKKJPO7MN4"
}
}
],
"region3": [
{
"configured": false,
"connection": {
"cid": 4,
"ip": "::1",
"port": 52025,
"start": "2019-07-24T18:02:48.764577-06:00",
"last_activity": "2019-07-24T18:02:48.764994-06:00",
"uptime": "6s",
"idle": "6s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0,
"name": "NCVS7Q65WX3FGIL2YQRLI77CE6MQRWO2Y453HYVLNMBMTVLOKMPW7R6K"
}
},
{
"configured": false,
"connection": {
"cid": 8,
"ip": "127.0.0.1",
"port": 52026,
"start": "2019-07-24T18:02:48.766173-06:00",
"last_activity": "2019-07-24T18:02:48.766999-06:00",
"uptime": "6s",
"idle": "6s",
"pending_bytes": 0,
"in_msgs": 0,
"out_msgs": 0,
"in_bytes": 0,
"out_bytes": 0,
"subscriptions": 0,
"name": "NCKCYK5LE3VVGOJQ66F65KA27UFPCLBPX4N4YOPOXO3KHGMW24USPCKN"
}
}
]
}
}{
"server_id": "NC2FJCRMPBE5RI5OSRN7TKUCWQONCKNXHKJXCJIDVSAZ6727M7MQFVT3",
"now": "2019-08-27T09:07:05.841132-06:00",
"leafnodes": 1,
"leafs": [
{
"account": "$G",
"ip": "127.0.0.1",
"port": 6223,
"rtt": "200µs",
"in_msgs": 0,
"out_msgs": 10000,
"in_bytes": 0,
"out_bytes": 1280000,
"subscriptions": 1,
"subscriptions_list": ["foo"]
}
]
}{
"num_subscriptions": 2,
"num_cache": 0,
"num_inserts": 2,
"num_removes": 0,
"num_matches": 0,
"cache_hit_rate": 0,
"max_fanout": 0,
"avg_fanout": 0
}{
"server_id": "NAB2EEQ3DLS2BHU4K2YMXMPIOOOAOFOAQAC5NQRIEUI4BHZKFBI4ZU4A",
"now": "2021-02-08T17:31:29.551146-05:00",
"system_account": "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5",
"accounts": ["AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5", "$G"]
}{
"server_id": "NAB2EEQ3DLS2BHU4K2YMXMPIOOOAOFOAQAC5NQRIEUI4BHZKFBI4ZU4A",
"now": "2021-02-08T17:37:55.80856-05:00",
"system_account": "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5",
"account_detail": {
"account_name": "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5",
"update_time": "2021-02-08T17:31:22.390334-05:00",
"is_system": true,
"expired": false,
"complete": true,
"jetstream_enabled": false,
"leafnode_connections": 0,
"client_connections": 0,
"subscriptions": 42,
"exports": [
{
"subject": "$SYS.DEBUG.SUBSCRIBERS",
"type": "service",
"response_type": "Singleton"
}
],
"jwt": "eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJVVlU2VEpXRU8zS0hYWTZVMkgzM0RCVklET1A3U05DTkJPMlM0M1dPNUM2T1RTTDNVSUxBIiwiaWF0IjoxNjAzNDczNzg4LCJpc3MiOiJPQlU1TzVGSjMyNFVEUFJCSVZSR0Y3Q05FT0hHTFBTN0VZUEJUVlFaS1NCSElJWklCNkhENjZKRiIsIm5hbWUiOiJTWVMiLCJzdWIiOiJBQUFYQVVWU0dLN1RDUkhGSVJBUzRTWVhWSjc2RVdETU5YWk02QVJGR1hQN0JBU05ER0xLVTdBNSIsInR5cGUiOiJhY2NvdW50IiwibmF0cyI6eyJsaW1pdHMiOnsic3VicyI6LTEsImNvbm4iOi0xLCJsZWFmIjotMSwiaW1wb3J0cyI6LTEsImV4cG9ydHMiOi0xLCJkYXRhIjotMSwicGF5bG9hZCI6LTEsIndpbGRjYXJkcyI6dHJ1ZX19fQ.CeGo16i5oD0b1uBJ8UdGmLH-l9dL8yNqXHggkAt2T5c88fM7k4G08wLguMAnlvzrdlYvdZvOx_5tHLuDZmGgCg",
"issuer_key": "OBU5O5FJ324UDPRBIVRGF7CNEOHGLPS7EYPBTVQZKSBHIIZIB6HD66JF",
"name_tag": "SYS",
"decoded_jwt": {
"jti": "UVU6TJWEO3KHXY6U2H33DBVIDOP7SNCNBO2S43WO5C6OTSL3UILA",
"iat": 1603473788,
"iss": "OBU5O5FJ324UDPRBIVRGF7CNEOHGLPS7EYPBTVQZKSBHIIZIB6HD66JF",
"name": "SYS",
"sub": "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5",
"nats": {
"limits": {
"subs": -1,
"data": -1,
"payload": -1,
"imports": -1,
"exports": -1,
"wildcards": true,
"conn": -1,
"leaf": -1
},
"default_permissions": {
"pub": {},
"sub": {}
},
"type": "account",
"version": 1
}
},
"sublist_stats": {
"num_subscriptions": 42,
"num_cache": 6,
"num_inserts": 42,
"num_removes": 0,
"num_matches": 6,
"cache_hit_rate": 0,
"max_fanout": 1,
"avg_fanout": 0.8333333333333334
}
}
}{
"server_id": "NDJ5M4F5WAIBUA26NJ3QMH532AQPN7QNTJP3Y4SBHSHL4Y7QUAKNJEAF",
"now": "2022-10-19T17:16:20.881296749Z",
"account_statz": [
{
"acc": "default",
"conns": 31,
"leafnodes": 2,
"total_conns": 33,
"num_subscriptions": 45,
"sent": {
"msgs": 1876970,
"bytes": 246705616
},
"received": {
"msgs": 1347454,
"bytes": 219438308
},
"slow_consumers": 29
},
{
"acc": "$G",
"conns": 1,
"leafnodes": 0,
"total_conns": 1,
"num_subscriptions": 3,
"sent": {
"msgs": 0,
"bytes": 0
},
"received": {
"msgs": 107,
"bytes": 1094
},
"slow_consumers": 0
}
]
}{
"server_id": "NCVIDODSZ45C5OD67ZD7EJUIJPQDP6CM74SJX6TJIF2G7NLYS5LCVYHS",
"now": "2021-02-08T19:08:30.555533-05:00",
"config": {
"max_memory": 10485760,
"max_storage": 10485760,
"store_dir": "/var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/srv_7500251552558",
"unique_tag": "az"
},
"memory": 0,
"storage": 66,
"api": {
"total": 5,
"errors": 0
},
"total_streams": 1,
"total_consumers": 1,
"total_messages": 1,
"total_message_bytes": 33,
"meta_cluster": {
"name": "cluster_name",
"replicas": [
{
"name": "server_5500",
"current": false,
"active": 2932926000
}
]
},
"account_details": [
{
"name": "BCC_TO_HAVE_ONE_EXTRA",
"id": "BCC_TO_HAVE_ONE_EXTRA",
"memory": 0,
"storage": 0,
"api": {
"total": 0,
"errors": 0
}
},
{
"name": "ACC",
"id": "ACC",
"memory": 0,
"storage": 66,
"api": {
"total": 5,
"errors": 0
},
"stream_detail": [
{
"name": "my-stream-replicated",
"cluster": {
"name": "cluster_name",
"replicas": [
{
"name": "server_5500",
"current": false,
"active": 2931517000
}
]
},
"state": {
"messages": 1,
"bytes": 33,
"first_seq": 1,
"first_ts": "2021-02-09T00:08:27.623735Z",
"last_seq": 1,
"last_ts": "2021-02-09T00:08:27.623735Z",
"consumer_count": 1
},
"consumer_detail": [
{
"stream_name": "my-stream-replicated",
"name": "my-consumer-replicated",
"created": "2021-02-09T00:08:27.427631Z",
"delivered": {
"consumer_seq": 0,
"stream_seq": 0
},
"ack_floor": {
"consumer_seq": 0,
"stream_seq": 0
},
"num_ack_pending": 0,
"num_redelivered": 0,
"num_waiting": 0,
"num_pending": 1,
"cluster": {
"name": "cluster_name",
"replicas": [
{
"name": "server_5500",
"current": false,
"active": 2933232000
}
]
}
}
]
}
]
}
]
}{ "status": "ok" }https://demo.nats.io:8222/connz?callback=cb$.getJSON("https://demo.nats.io:8222/connz?callback=?", function (data) {
console.log(data);
});package main
import (
"flag"
"fmt"
"log"
"github.com/nats-io/jwt/v2"
"github.com/nats-io/nkeys"
)
func main() {
log.SetFlags(0)
var (
accountSeed string
operatorSeed string
name string
)
flag.StringVar(&operatorSeed, "operator", "", "Operator seed for creating an account.")
flag.StringVar(&accountSeed, "account", "", "Account seed for creating a user.")
flag.StringVar(&name, "name", "", "Account or user name to be created.")
flag.Parse()
if accountSeed != "" && operatorSeed != "" {
log.Fatal("operator and account cannot both be provided")
}
var (
jwt string
err error
)
if operatorSeed != "" {
jwt, err = createAccount(operatorSeed, name)
} else if accountSeed != "" {
jwt, err = createUser(accountSeed, name)
} else {
flag.PrintDefaults()
return
}
if err != nil {
log.Fatalf("error creating account JWT: %v", err)
}
fmt.Println(jwt)
}
func createAccount(operatorSeed, accountName string) (string, error) {
akp, err := nkeys.CreateAccount()
if err != nil {
return "", fmt.Errorf("unable to create account using nkeys: %w", err)
}
apub, err := akp.PublicKey()
if err != nil {
return "", fmt.Errorf("unable to retrieve public key: %w", err)
}
ac := jwt.NewAccountClaims(apub)
ac.Name = accountName
// Load operator key pair
okp, err := nkeys.FromSeed([]byte(operatorSeed))
if err != nil {
return "", fmt.Errorf("unable to create operator key pair from seed: %w", err)
}
// Sign the account claims and convert it into a JWT string
ajwt, err := ac.Encode(okp)
if err != nil {
return "", fmt.Errorf("unable to sign the claims: %w", err)
}
return ajwt, nil
}
func createUser(accountSeed, userName string) (string, error) {
ukp, err := nkeys.CreateUser()
if err != nil {
return "", fmt.Errorf("unable to create user using nkeys: %w", err)
}
upub, err := ukp.PublicKey()
if err != nil {
return "", fmt.Errorf("unable to retrieve public key: %w", err)
}
uc := jwt.NewUserClaims(upub)
uc.Name = userName
// Load account key pair
akp, err := nkeys.FromSeed([]byte(accountSeed))
if err != nil {
return "", fmt.Errorf("unable to create account key pair from seed: %w", err)
}
// Sign the user claims and convert it into a JWT string
ujwt, err := uc.Encode(akp)
if err != nil {
return "", fmt.Errorf("unable to sign the claims: %w", err)
}
return ujwt, nil
}func natsErrHandler(nc *nats.Conn, sub *nats.Subscription, natsErr error) {
fmt.Printf("error: %v\n", natsErr)
if natsErr == nats.ErrSlowConsumer {
pendingMsgs, _, err := sub.Pending()
if err != nil {
fmt.Printf("couldn't get pending messages: %v", err)
return
}
fmt.Printf("Falling behind with %d pending messages on subject %q.\n",
pendingMsgs, sub.Subject)
// Log error, notify operations...
}
// check for other errors
}
// Set the error handler when creating a connection.
nc, err := nats.Connect("nats://localhost:4222",
nats.ErrorHandler(natsErrHandler))error: nats: slow consumer, messages dropped
Falling behind with 65536 pending messages on subject "foo".[54083] 2017/09/28 14:45:18.001357 [INF] ::1:63283 - cid:7 - Slow Consumer Detectedwrite_deadline: 2sif err := sub.SetPendingLimits(1024*500, 1024*5000); err != nil {
log.Fatalf("Unable to set pending limits: %v", err)
}nats s reportObtaining Stream stats
+---------+---------+-----------+----------+-------+------+---------+----------------------+
| Stream | Storage | Consumers | Messages | Bytes | Lost | Deleted | Cluster |
+---------+---------+-----------+----------+-------+------+---------+----------------------+
| ORDERS | Memory | 0 | 0 | 0 B | 0 | 0 | n1-c2, n2-c2*, n3-c2 |
| RETURNS | Memory | 0 | 0 | 0 B | 0 | 0 | n1-c2*, n2-c2, n3-c2 |
+---------+---------+-----------+----------+-------+------+---------+----------------------+nats s add ARCHIVE --source ORDERS --source RETURNS? Storage backend file
? Retention Policy Limits
? Discard Policy Old
? Stream Messages Limit -1
? Message size limit -1
? Maximum message age limit -1
? Maximum individual message size -1
? Duplicate tracking time window 2m0s
? Allow message Roll-ups No
? Allow message deletion Yes
? Allow purging subjects or the entire stream Yes
? Replicas 1
? Adjust source "ORDERS" start Yes
? ORDERS Source Start Sequence 0
? ORDERS Source UTC Time Stamp (YYYY:MM:DD HH:MM:SS)
? ORDERS Source Filter source by subject
? Import "ORDERS" from a different JetStream domain No
? Import "ORDERS" from a different account No
? Adjust source "RETURNS" start No
? Import "RETURNS" from a different JetStream domain No
? Import "RETURNS" from a different account No
Stream ARCHIVE was created
Information for Stream ARCHIVE created 2022-01-21T11:49:52-08:00
Configuration:
Acknowledgements: true
Retention: File - Limits
Replicas: 1
Discard Policy: Old
Duplicate Window: 2m0s
Allows Msg Delete: true
Allows Purge: true
Allows Rollups: false
Maximum Messages: unlimited
Maximum Bytes: unlimited
Maximum Age: unlimited
Maximum Message Size: unlimited
Maximum Consumers: unlimited
Sources: ORDERS
RETURNS
State:
Messages: 0
Bytes: 0 B
FirstSeq: 0
LastSeq: 0
Active Consumers: 0nats s add REPORT --mirror ARCHIVE? Storage backend file
? Retention Policy Limits
? Discard Policy Old
? Stream Messages Limit -1
? Message size limit -1
? Maximum message age limit -1
? Maximum individual message size -1
? Allow message Roll-ups No
? Allow message deletion Yes
? Allow purging subjects or the entire stream Yes
? Replicas 1
? Adjust mirror start No
? Import mirror from a different JetStream domain No
? Import mirror from a different account No
Stream REPORT was created
Information for Stream REPORT created 2022-01-21T11:50:55-08:00
Configuration:
Acknowledgements: true
Retention: File - Limits
Replicas: 1
Discard Policy: Old
Duplicate Window: 2m0s
Allows Msg Delete: true
Allows Purge: true
Allows Rollups: false
Maximum Messages: unlimited
Maximum Bytes: unlimited
Maximum Age: unlimited
Maximum Message Size: unlimited
Maximum Consumers: unlimited
Mirror: ARCHIVE
State:
Messages: 0
Bytes: 0 B
FirstSeq: 0
LastSeq: 0
Active Consumers: 0nats stream info ARCHIVE...
Source Information:
Stream Name: ORDERS
Lag: 0
Last Seen: 2m23s
Stream Name: RETURNS
Lag: 0
Last Seen: 2m15s
...
$ nats stream info REPORT
...
Mirror Information:
Stream Name: ARCHIVE
Lag: 0
Last Seen: 2m35s
...nats s report+--------------------------------------------------------------------------------------------------------+
| Stream Report |
+---------+---------+-------------+-----------+----------+-------+------+---------+----------------------+
| Stream | Storage | Replication | Consumers | Messages | Bytes | Lost | Deleted | Cluster |
+---------+---------+-------------+-----------+----------+-------+------+---------+----------------------+
| ARCHIVE | File | Sourced | 1 | 0 | 0 B | 0 | 0 | n1-c2*, n2-c2, n3-c2 |
| ORDERS | Memory | | 1 | 0 | 0 B | 0 | 0 | n1-c2, n2-c2*, n3-c2 |
| REPORT | File | Mirror | 0 | 0 | 0 B | 0 | 0 | n1-c2* |
| RETURNS | Memory | | 1 | 0 | 0 B | 0 | 0 | n1-c2, n2-c2, n3-c2* |
+---------+---------+-------------+-----------+----------+-------+------+---------+----------------------+
+---------------------------------------------------------+
| Replication Report |
+---------+--------+---------------+--------+-----+-------+
| Stream | Kind | Source Stream | Active | Lag | Error |
+---------+--------+---------------+--------+-----+-------+
| ARCHIVE | Source | ORDERS | never | 0 | |
| ARCHIVE | Source | RETURNS | never | 0 | |
| REPORT | Mirror | ARCHIVE | never | 0 | |
+---------+--------+---------------+--------+-----+-------+nats req ORDERS.new "ORDER {{Count}}" --count 100
nats req RETURNS.new "RETURN {{Count}}" --count 100nats s report --dot replication.dotObtaining Stream stats
+---------+---------+-----------+----------+---------+------+---------+----------------------+
| Stream | Storage | Consumers | Messages | Bytes | Lost | Deleted | Cluster |
+---------+---------+-----------+----------+---------+------+---------+----------------------+
| ORDERS | Memory | 1 | 100 | 3.3 KiB | 0 | 0 | n1-c2, n2-c2*, n3-c2 |
| RETURNS | Memory | 1 | 100 | 3.5 KiB | 0 | 0 | n1-c2*, n2-c2, n3-c2 |
| ARCHIVE | File | 1 | 200 | 27 KiB | 0 | 0 | n1-c2, n2-c2, n3-c2* |
| REPORT | File | 0 | 200 | 27 KiB | 0 | 0 | n1-c2* |
+---------+---------+-----------+----------+---------+------+---------+----------------------+
+---------------------------------------------------------+
| Replication Report |
+---------+--------+---------------+--------+-----+-------+
| Stream | Kind | Source Stream | Active | Lag | Error |
+---------+--------+---------------+--------+-----+-------+
| ARCHIVE | Source | ORDERS | 14.48s | 0 | |
| ARCHIVE | Source | RETURNS | 9.83s | 0 | |
| REPORT | Mirror | ARCHIVE | 9.82s | 0 | |
+---------+--------+---------------+--------+-----+-------+

nats-server --signal reload.SOSASUSOAU-V> nats -s localhost:4222 "--creds=user.creds" pub "foo" "hello world"
> 16:56:02 Published 11 bytes to "foo"> nats -s localhost:4222 "--creds=user.creds" pub "foo" "hello world"
nats: error: nats: Maximum Payload Violation, try --help
>nsc add operator -u operator.jwt.nsc import account --file import.jwt.nats-resolverexport GO111MODULE=on
go install github.com/nats-io/nats-server/v2@latest
go install github.com/nats-io/natscli/nats@latest
go install github.com/nats-io/nkeys/nk@latest
go install github.com/nats-io/nsc/v2@latestnats-server -c server.confnats-server --signal reloadaccounts: {
A: {
users: [{user: a, password: a}]
},
B: {
users: [{user: b, password: b}]
},
}nats -s nats://a:a@localhost:4222 sub ">"nats -s nats://b:b@localhost:4222 pub "foo" "user b"nats -s nats://a:a@localhost:4222 pub "foo" "user a"17:57:06 [#1] Received on "foo"
user aaccounts: {
A: {
users: [{user: a, password: a}]
imports: [{stream: {account: B, subject: "foo"}}]
},
B: {
users: [{user: b, password: b}]
exports: [{stream: "foo"}]
},
}nats -s nats://a:a@localhost:4222 sub ">"nats -s nats://b:b@localhost:4222 pub "foo" "user b"18:28:25 [#1] Received on "foo"
user bnk -gen user -pubout > a.nkcat a.nkSUAAEZYNLTEA2MDTG7L5X7QODZXYHPOI2LT2KH5I4GD6YVP24SE766EGPA
UC435ZYS52HF72E2VMQF4GO6CUJOCHDUUPEBU7XDXW5AQLIC6JZ46PO5nk -gen user -pubout > b.nkcat b.nkSUANS4XLL5NWBTM57GSVHLN4TMFW55WGGWNI5YXXSIOYFJQYFVNHJK5GFY
UARZVI6JAV7YMJTPRANXANOOW4K3ZCD45NYP6S7C7XKCBHPVN2TFZ7ZCaccounts: {
A: {
users: [{nkey:UC435ZYS52HF72E2VMQF4GO6CUJOCHDUUPEBU7XDXW5AQLIC6JZ46PO5}]
imports: [{stream: {account: B, subject: "foo"}}]
},
B: {
users: [{nkey:UARZVI6JAV7YMJTPRANXANOOW4K3ZCD45NYP6S7C7XKCBHPVN2TFZ7ZC}]
exports: [{stream: "foo"}]
},
}[95184] 2020/10/26 12:15:44.350577 [TRC] [::1]:55551 - cid:2 - <<- [CONNECT {
"echo": true,
"headers": true,
"lang": "go",
"name": "NATS CLI",
"nkey": "UC435ZYS52HF72E2VMQF4GO6CUJOCHDUUPEBU7XDXW5AQLIC6JZ46PO5",
"no_responders": true,
"pedantic": false,
"protocol": 1,
"sig": "lopzgs98JBQYyRdw1zT_BoBpSFRDCfTvT4le5MYSKrt0IqGWZ2OXhPW1J_zo2_sBod8XaWgQc9oWohWBN0NdDg",
"tls_required": false,
"verbose": false,
"version": "1.11.0"
}]> telnet localhost 4222
Trying ::1...
Connected to localhost.
Escape character is '^]'.
INFO {
"auth_required": true,
"client_id": 3,
"client_ip": "::1",
"go": "go1.14.1",
"headers": true,
"host": "0.0.0.0",
"max_payload": 1048576,
"nonce": "-QPTE1Jsk8kI3rE",
"port": 4222,
"proto": 1,
"server_id": "NBSHIXACRHUODC4FY2Z3OYXSZSRUBRH6VWIKQNGVPKOTA7H4YTXWJRTO",
"server_name": "NBSHIXACRHUODC4FY2Z3OYXSZSRUBRH6VWIKQNGVPKOTA7H4YTXWJRTO",
"version": "2.2.0-beta.26"
}
-ERR 'Authentication Timeout'
Connection closed by foreign host.jwt.sig = sign(hash(jwt.header + jwt.body), private-key(jwt.issuer))
(jwt.issuer is part of jwt.body)nsc describe operator --json{
"iat": 1603473819,
"iss": "OBU5O5FJ324UDPRBIVRGF7CNEOHGLPS7EYPBTVQZKSBHIIZIB6HD66JF",
"jti": "57BWRLW67I6JTVYMQAZQF54G2G37DJB5WG5IFIPVYI4PEYNX57ZQ",
"name": "DEMO",
"nats": {
"account_server_url": "nats://localhost:4222",
"system_account": "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5"
},
"sub": "OBU5O5FJ324UDPRBIVRGF7CNEOHGLPS7EYPBTVQZKSBHIIZIB6HD66JF",
"type": "operator"
}{
"iat": 1603474600,
"iss": "OBU5O5FJ324UDPRBIVRGF7CNEOHGLPS7EYPBTVQZKSBHIIZIB6HD66JF",
"jti": "CZDE4PM7MGFNYHRZSE6INTP6QDU4DSLACVHPQFA7XEYNJT6R6LLQ",
"name": "demo-test",
"nats": {
"limits": {
"conn": -1,
"data": -1,
"exports": -1,
"imports": -1,
"leaf": -1,
"payload": -1,
"subs": -1,
"wildcards": true
}
},
"sub": "ADKGAJU55CHYOIF5H432K2Z2ME3NPSJ5S3VY5Q42Q3OTYOCYRRG7WOWV",
"type": "account"
}{
"iat": 1603475001,
"iss": "ADKGAJU55CHYOIF5H432K2Z2ME3NPSJ5S3VY5Q42Q3OTYOCYRRG7WOWV",
"jti": "GOOPXCFDWVMEU3U6I6MT344Z56MGBYIS42GDXMUXDFA3NYDR2RUQ",
"name": "alpha",
"nats": {
"pub": {},
"sub": {}
},
"sub": "UC56LV5NNMP5FURQZ7HZTGWCRRTWSMHZNNELQMHDLH3DCYNGX57B2TN6",
"type": "user"
}
>operator: ./trustedOperator.jwt
resolver: URL(http://localhost:9090/jwt/v1/accouts/) > telnet localhost 4222
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
INFO {
"auth_required": true,
"client_id": 5,
"client_ip": "127.0.0.1",
"go": "go1.14.1",
"headers": true,
"host": "localhost",
"max_payload": 1048576,
"nonce": "aN9-ZtS7taDoAZk",
"port": 4222,
"proto": 1,
"server_id": "NCIK6FX5MRIEPMEK22YL2ECLIWVJBH2SWFD5EQWSI5XRDQPKZXWKX3VP",
"server_name": "NCIK6FX5MRIEPMEK22YL2ECLIWVJBH2SWFD5EQWSI5XRDQPKZXWKX3VP",
"tls_required": true,
"version": "2.2.0-beta.26"
}
Connection closed by foreign host. > cat user.creds
-----BEGIN NATS USER JWT-----
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJXNkFYSFlSS1RHVTNFUklQM0dSRDdNV0FQTzQ2VzQ2Vzc3R1JNMk5SWFFIQ0VRQ0tCRjJRIiwiaWF0IjoxNjAzNDczNzg4LCJpc3MiOiJBQUFYQVVWU0dLN1RDUkhGSVJBUzRTWVhWSjc2RVdETU5YWk02QVJGR1hQN0JBU05ER0xLVTdBNSIsIm5hbWUiOiJzeXMiLCJzdWIiOiJVRE5ZMktLUFRJQVBQTk9OT0xBVE5SWlBHTVBMTkZXSFFQS1VYSjZBMllUQTQ3Tk41Vk5GSU80NSIsInR5cGUiOiJ1c2VyIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9fX0.ae3OvcapjQgbXhI2QbgIs32AWr3iBb2UFRZbXzIg0duFHNPQI5LsprR0OQoSlc2tic6e3sn8YM5x0Rt34FryDA
------END NATS USER JWT------
************************* IMPORTANT *************************
NKEY Seed printed below can be used to sign and prove identity.
NKEYs are sensitive and should be treated as secrets.
-----BEGIN USER NKEY SEED-----
SUAAZU5G7UOUR7VXQ7DBD5RQTBW54O2COGSXAVIYWVZE4GCZ5C7OCZ5JLY
------END USER NKEY SEED------
************************************************************* > nats -s localhost:4222 "--creds=user.creds" pub "foo" "hello world"nsc add operator -n <operator-name> --sysnsc list keys --all+------------------------------------------------------------------------------------------------+
| Keys |
+--------------+----------------------------------------------------------+-------------+--------+
| Entity | Key | Signing Key | Stored |
+--------------+----------------------------------------------------------+-------------+--------+
| DEMO | OD5FHU4LXGDSGDHO7UNRMLW6I36QX5VPJXRQHFHMRUIKSHOPEDSHVPBB | | * |
| DEMO | OBYAIG4T4PVR6GVYDERN74RRW7VBKRWBTI7ULLMM6BRHUID4AAQL7SGA | * | |
| ACC | ADRB4JJYFDLWKIMX4DH6MX2DMKA3TENJWGMNVM5ILYLZTT6BN7QIF5ZX | | |
| SYS | AAYVLZJC2ULKSH5HNSKMIKFMCEHCNU5VOV5KG56IRL7ENHLBUGZ27CZT | | * |
| sys | UBVZYLLCAFMHBXBUDKKKFKH62T4AW7Q5MAAE3R3KKAIRCZNYITZPDQZ3 | | * |
| sys-non-op | UDJKPL7H6QY4KP4LISNHENU6Z434G6RLDEXL2C64YZXDABNCEOAZ4YY2 | | |
+--------------+----------------------------------------------------------+-------------+--------+nsc list keys --all+------------------------------------------------------------------------------------------------+
| Keys |
+--------------+----------------------------------------------------------+-------------+--------+
| Entity | Key | Signing Key | Stored |
+--------------+----------------------------------------------------------+-------------+--------+
| DEMO | OD5FHU4LXGDSGDHO7UNRMLW6I36QX5VPJXRQHFHMRUIKSHOPEDSHVPBB | | |
| DEMO | OBYAIG4T4PVR6GVYDERN74RRW7VBKRWBTI7ULLMM6BRHUID4AAQL7SGA | * | * |
| SYS | AAYVLZJC2ULKSH5HNSKMIKFMCEHCNU5VOV5KG56IRL7ENHLBUGZ27CZT | | |
| sys-non-op | UDJKPL7H6QY4KP4LISNHENU6Z434G6RLDEXL2C64YZXDABNCEOAZ4YY2 | | * |
+--------------+----------------------------------------------------------+-------------+--------+nsc add account -n <account name> -insc add operator -n DEMO --sys[ OK ] generated and stored operator key "ODHUVOUVUA3XIBV25XSQS2NM2UN4IKJYLAMCGLWRFAV7F7KUWADCM4K6"
[ OK ] added operator "DEMO"
[ OK ] created system_account: name:SYS id:AA6W5MRDIFIQWE6UE6D4YWQT5L4YZG7ZRHSKYCPF2VIEMUHRZH3VQZ27
[ OK ] created system account user: name:sys id:UABM73CE5F3ZYFNC3ZDODAF7GIB62W2WXV5DOLMYLGEW4MEHYBC46PN4
[ OK ] system account user creds file stored in `~/test/demo/env1/keys/creds/DEMO/SYS/sys.creds`nsc edit operator --account-jwt-server-url nats://localhost:4222[ OK ] set account jwt server url to "nats://localhost:4222"
[ OK ] edited operator "DEMO"nsc list keys --all+------------------------------------------------------------------------------------------+
| Keys |
+--------+----------------------------------------------------------+-------------+--------+
| Entity | Key | Signing Key | Stored |
+--------+----------------------------------------------------------+-------------+--------+
| DEMO | ODHUVOUVUA3XIBV25XSQS2NM2UN4IKJYLAMCGLWRFAV7F7KUWADCM4K6 | | * |
| SYS | AA6W5MRDIFIQWE6UE6D4YWQT5L4YZG7ZRHSKYCPF2VIEMUHRZH3VQZ27 | | * |
| sys | UABM73CE5F3ZYFNC3ZDODAF7GIB62W2WXV5DOLMYLGEW4MEHYBC46PN4 | | * |
+--------+----------------------------------------------------------+-------------+--------++-------------------------------------------------------------------------------+
| Operator Details |
+--------------------+----------------------------------------------------------+
| Name | DEMO |
| Operator ID | ODHUVOUVUA3XIBV25XSQS2NM2UN4IKJYLAMCGLWRFAV7F7KUWADCM4K6 |
| Issuer ID | ODHUVOUVUA3XIBV25XSQS2NM2UN4IKJYLAMCGLWRFAV7F7KUWADCM4K6 |
| Issued | 2020-11-04 19:25:25 UTC |
| Expires | |
| Account JWT Server | nats://localhost:4222 |
| System Account | AA6W5MRDIFIQWE6UE6D4YWQT5L4YZG7ZRHSKYCPF2VIEMUHRZH3VQZ27 |
+--------------------+----------------------------------------------------------++--------------------------------------------------------------------------------------+
| Account Details |
+---------------------------+----------------------------------------------------------+
| Name | SYS |
| Account ID | AA6W5MRDIFIQWE6UE6D4YWQT5L4YZG7ZRHSKYCPF2VIEMUHRZH3VQZ27 |
| Issuer ID | ODHUVOUVUA3XIBV25XSQS2NM2UN4IKJYLAMCGLWRFAV7F7KUWADCM4K6 |
| Issued | 2020-11-04 19:24:41 UTC |
| Expires | |
+---------------------------+----------------------------------------------------------+
| Max Connections | Unlimited |
| Max Leaf Node Connections | Unlimited |
| Max Data | Unlimited |
| Max Exports | Unlimited |
| Max Imports | Unlimited |
| Max Msg Payload | Unlimited |
| Max Subscriptions | Unlimited |
| Exports Allows Wildcards | True |
+---------------------------+----------------------------------------------------------+
| Imports | None |
| Exports | None |
+---------------------------+----------------------------------------------------------+nsc generate config --nats-resolver > nats-res.cfg
nats-server -c nats-res.cfg --addr localhost --port 4222 &[2] 30129
[30129] 2020/11/04 14:30:14.062132 [INF] Starting nats-server version 2.2.0-beta.26
[30129] 2020/11/04 14:30:14.062215 [INF] Git commit [not set]
[30129] 2020/11/04 14:30:14.062219 [INF] Using configuration file: nats-res.cfg
[30129] 2020/11/04 14:30:14.062220 [INF] Trusted Operators
[30129] 2020/11/04 14:30:14.062224 [INF] System : ""
[30129] 2020/11/04 14:30:14.062226 [INF] Operator: "DEMO"
[30129] 2020/11/04 14:30:14.062241 [INF] Issued : 2020-11-04 14:25:25 -0500 EST
[30129] 2020/11/04 14:30:14.062244 [INF] Expires : 1969-12-31 19:00:00 -0500 EST
[30129] 2020/11/04 14:30:14.062652 [INF] Managing all jwt in exclusive directory /demo/env1/jwt
[30129] 2020/11/04 14:30:14.065888 [INF] Listening for client connections on localhost:4222
[30129] 2020/11/04 14:30:14.065896 [INF] Server id is NBQ6AG5YIRC6PRCUPCAUSVCSCQWAAWW2XQXIM6UPW5AFPGZBUKZJTRRS
[30129] 2020/11/04 14:30:14.065898 [INF] Server name is NBQ6AG5YIRC6PRCUPCAUSVCSCQWAAWW2XQXIM6UPW5AFPGZBUKZJTRRS
[30129] 2020/11/04 14:30:14.065900 [INF] Server is ready
>nsc add account -n TEST[ OK ] generated and stored account key "ADXDDDR2QJNNOSZZX44C2HYBPRUIPJSQ5J3YG2XOUOOEOPOBNMMFLAIU"
[ OK ] added account "TEST"nsc add user -a TEST -n foo[ OK ] generated and stored user key "UA62PGBNKKQQWDTILKP5U4LYUYF3B6NQHVPNHLS6IZIPPQH6A7XSRWE2"
[ OK ] generated user creds file `/DEMO/TEST/foo.creds`
[ OK ] added user "foo" to account "TEST"nats -s nats://localhost:4222 pub --creds=/DEMO/TEST/foo.creds "hello" "world"nats: error: read tcp 127.0.0.1:60061->127.0.0.1:4222: i/o timeout, try --help
[9174] 2020/11/05 16:49:34.331078 [WRN] Account [ADI4H2XRYMT5ENVBBS3UKYC2FBLGB3NF4VV5L57HUZIO4AMYROB4LMYF] fetch took 2.000142625s
[9174] 2020/11/05 16:49:34.331123 [WRN] Account fetch failed: fetching jwt timed out
[9174] 2020/11/05 16:49:34.331182 [ERR] 127.0.0.1:60061 - cid:5 - "v1.11.0:go:NATS CLI Version development" - authentication error
[9174] 2020/11/05 16:49:34.331258 [WRN] 127.0.0.1:60061 - cid:5 - "v1.11.0:go:NATS CLI Version development" - Readloop processing time: 2.000592801snsc push -a TEST[ OK ] push to nats-server "nats://localhost:4222" using system account "SYS" user "sys":
[ OK ] push TEST to nats-server with nats account resolver:
[ OK ] pushed "TEST" to nats-server NBQ6AG5YIRC6PRCUPCAUSVCSCQWAAWW2XQXIM6UPW5AFPGZBUKZJTRRS: jwt updated
[ OK ] pushed to a total of 1 nats-servernsc push --all[ OK ] push to nats-server "nats://localhost:4222" using system account "SYS" user "sys":
[ OK ] push SYS to nats-server with nats account resolver:
[ OK ] pushed "SYS" to nats-server NBENVYIBPNQGYVP32Y3P6WLGBOISORNAZYHA6SCW6LTBE42ORTIQMWHX: jwt updated
[ OK ] pushed to a total of 1 nats-server
[ OK ] push TEST to nats-server with nats account resolver:
[ OK ] pushed "TEST" to nats-server NBENVYIBPNQGYVP32Y3P6WLGBOISORNAZYHA6SCW6LTBE42ORTIQMWHX: jwt updated
[ OK ] pushed to a total of 1 nats-servernats -s nats://localhost:4222 pub --creds=/DEMO/TEST/foo.creds "hello" "world"func GetAccountSigningKey() nkeys.KeyPair {
// Content of the account signing key seed can come from a file or an environment variable as well
accSeed := []byte("SAAJGCAHPHHM6AVJJWQ2YAS3I4NETXMWVQSTCQMJ7VVTGAJF5UCN3IX7J4")
accountSigningKey, err := nkeys.ParseDecoratedNKey(accSeed)
if err != nil {
panic(err)
}
return accountSigningKey
}
func RequestUser() {
// Setup! Obtain the account signing key!
accountPublicKey := GetAccountPublicKey()
accountSigningKey := GetAccountSigningKey()
userPublicKey, userSeed, userKeyPair := generateUserKey()
userJWT := generateUserJWT(userPublicKey, accountPublicKey, accountSigningKey)
// userJWT and userKeyPair can be used in conjunction with this nats.Option
var jwtAuthOption nats.Option
jwtAuthOption = nats.UserJWT(func() (string, error) {
return userJWT, nil
},
func(bytes []byte) ([]byte, error) {
return userKeyPair.Sign(bytes)
},
)
// Alternatively you can create a creds file and use it as nats.Option
credsContent, err := jwt.FormatUserConfig(userJWT, userSeed);
if err != nil {
panic(err)
}
ioutil.WriteFile("my.creds", credsContent, 0644)
jwtAuthOption = nats.UserCredentials("my.creds")
// use in a connection as desired
nc, err := nats.Connect("nats://localhost:4222", jwtAuthOption)
// ...
}func generateUserKey() (userPublicKey string, userSeed []byte, userKeyPair nkeys.KeyPair) {
kp, err := nkeys.CreateUser()
if err != nil {
return "", nil, nil
}
if userSeed, err = kp.Seed(); err != nil {
return "", nil, nil
} else if userPublicKey, err = kp.PublicKey(); err != nil {
return "", nil, nil
}
return
}func generateUserJWT(userPublicKey, accountPublicKey string, accountSigningKey nkeys.KeyPair) (userJWT string) {
uc := jwt.NewUserClaims(userPublicKey)
uc.Pub.Allow.Add("subject.foo") // only allow publishing to subject.foo
uc.Expires = time.Now().Add(time.Hour).Unix() // expire in an hour
uc.IssuerAccount = accountPublicKey
vr := jwt.ValidationResults{}
uc.Validate(&vr)
if vr.IsBlocking(true) {
panic("Generated user claim is invalid")
}
var err error
userJWT, err = uc.Encode(accountSigningKey)
if err != nil {
return ""
}
return
}func ObtainAuthorizationToken() interface{} {
// whatever you want, 3rd party token/username&password
return ""
}
func IsTokenAuthorized(token interface{}) bool {
// whatever logic to determine if the input authorizes the requester to obtain a user jwt
return token.(string) == ""
}
// request struct to exchange data
type userRequest struct {
UserJWTResponseChan chan string
UserPublicKey string
AuthInfo interface{}
}
func startUserProvisioningService(isAuthorizedCb func(token interface{}) bool) chan userRequest {
userRequestChan := make(chan userRequest) // channel to send requests for jwt to
go func() {
accountSigningKey := GetAccountSigningKey() // Setup, obtain account signing key
for {
req := <-userRequestChan // receive request
if !isAuthorizedCb(req.AuthInfo) {
fmt.Printf("Request is not authorized to receive a JWT, timeout on purpose")
} else if userJWT := generateUserJWT(req.UserPublicKey, accountSigningKey); userJWT != "" {
req.UserJWTResponseChan <- userJWT // respond with jwt
}
}
}()
return userRequestChan
}
func startUserProcess(userRequestChan chan userRequest, obtainAuthorizationCb func() interface{}) {
requestUser := func(userRequestChan chan userRequest, authInfo interface{}) (jwtAuthOption nats.Option) {
userPublicKey, _, userKeyPair := generateUserKey()
respChan := make(chan string)
// request jwt
userRequestChan <- userRequest{
respChan,
userPublicKey,
authInfo,
}
userJWT := <-respChan // wait for response
// userJWT and userKeyPair can be used in conjunction with this nats.Option
jwtAuthOption = nats.UserJWT(func() (string, error) {
return userJWT, nil
},
func(bytes []byte) ([]byte, error) {
return userKeyPair.Sign(bytes)
},
)
// Alternatively you can create a creds file and use it as nats.Option
return
}
go func() {
jwtAuthOption := requestUser(userRequestChan, obtainAuthorizationCb())
nc, err := nats.Connect("nats://localhost:4222", jwtAuthOption)
if err != nil {
return
}
defer nc.Close()
time.Sleep(time.Second) // simulate work one would want to do
}()
}
func RequestUserDistributed() {
reqChan := startUserProvisioningService(IsTokenAuthorized)
defer close(reqChan)
// start multiple user processes
for i := 0; i < 4; i++ {
startUserProcess(reqChan, ObtainAuthorizationToken)
}
time.Sleep(5 * time.Second)
}// dotnet add package NATS.NKeys --prerelease
// dotnet add package SimpleBase
using NATS.NKeys;
using System.Security.Cryptography;
using System.Text;
string creds = IssueUserCreds();
Console.WriteLine(creds);
static string IssueUserJwt(string userKeyPub)
{
// Load account signing key and account identity for
// the account you wish to issue users for
const string accSeed = "SAANWFZ3JINNPERWT3ALE45U7GYT2ZDW6GJUIVPDKUF6GKAX6AISZJMAS4";
const string accId = "ACV63DGCZGOIT3P5ZA7PQT3KYJ6UDFFHZ7KETHYMDMZ4N44KYAQ2ZZ5F";
KeyPair accountSigningKey = KeyPair.FromSeed(accSeed);
string accSigningKeyPub = accountSigningKey.GetPublicKey();
// Use nsc to create a user any way you like.
// Export the user as json using:
// nsc describe user --name <user name> --account <account name> --json
// Turn the output into a format string and replace values you want replaced.
// Fields that need to be replaced are:
// iat (issued at), iss (issuer), sub (subject) and jti (claim hash)
const string claimFmt = @"{{
""iat"": {0},
""iss"": ""{1}"",
""jti"": ""{2}"",
""name"": ""{3}"",
""nats"": {{
""data"": -1,
""issuer_account"": ""{4}"",
""payload"": -1,
""pub"": {{}},
""sub"": {{}},
""subs"": -1,
""type"": ""user"",
""version"": 2
}},
""sub"": ""{3}""
}}";
const string header = @"{
""typ"":""JWT"",
""alg"":""ed25519-nkey""
}";
// Issue At time is stored in unix seconds
long issuedAt = DateTimeOffset.Now.ToUnixTimeSeconds();
// Generate a claim without jti so we can compute jti off of it
string claim = string.Format(
claimFmt,
issuedAt,
accSigningKeyPub,
"", /* blank jti */
userKeyPub,
accId);
// Compute jti, a base32 encoded sha256 hash
string jti = SimpleBase.Base32.Rfc4648.Encode(
SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(claim)),
false);
// recreate full claim with jti set
claim = string.Format(
claimFmt,
issuedAt,
accSigningKeyPub,
jti,
userKeyPub,
accId
);
// all three components (header/body/signature) are base64url encoded
string encHeader = ToBase64Url(Encoding.UTF8.GetBytes(header));
string encBody = ToBase64Url(Encoding.UTF8.GetBytes(claim));
// compute the signature off of header + body (. included on purpose)
byte[] sig = Encoding.UTF8.GetBytes($"{encHeader}.{encBody}");
var signature = new byte[64];
accountSigningKey.Sign(sig, signature);
string encSig = ToBase64Url(signature);
// append signature to header and body and return it
return $"{encHeader}.{encBody}.{encSig}";
}
static string IssueUserCreds()
{
// Generate a user NKEY for the new user.
// The private portion of the NKEY is not needed when issuing the jwt.
// Therefore generating the key can also be done separately from the JWT.
// Say by the requester.
KeyPair userSeed = KeyPair.CreatePair(PrefixByte.User);
string userKeyPub = userSeed.GetPublicKey();
string jwt = IssueUserJwt(userKeyPub);
// return jwt and corresponding user seed as creds
return $@"-----BEGIN NATS USER JWT-----
{jwt}
------END NATS USER JWT------
************************* IMPORTANT *************************
NKEY Seed printed below can be used to sign and prove identity.
NKEYs are sensitive and should be treated as secrets.
-----BEGIN USER NKEY SEED-----
{userSeed.GetSeed()}
------END USER NKEY SEED------
*************************************************************";
}
static string ToBase64Url(byte[] input)
{
var stringBuilder = new StringBuilder(Convert.ToBase64String(input).TrimEnd('='));
stringBuilder.Replace('+', '-');
stringBuilder.Replace('/', '_');
return stringBuilder.ToString();
}// dotnet add package NATS.Jwt --prerelease
using NATS.Jwt;
using NATS.Jwt.Models;
using NATS.NKeys;
const string accSeed = "SAANWFZ3JINNPERWT3ALE45U7GYT2ZDW6GJUIVPDKUF6GKAX6AISZJMAS4";
const string accId = "ACV63DGCZGOIT3P5ZA7PQT3KYJ6UDFFHZ7KETHYMDMZ4N44KYAQ2ZZ5F";
var jwt = new NatsJwt();
// Load account signing key
KeyPair accountSigningKey = KeyPair.FromSeed(accSeed);
// Create a user keypair
KeyPair ukp = KeyPair.CreatePair(PrefixByte.User);
string upk = ukp.GetPublicKey();
NatsUserClaims uc = jwt.NewUserClaims(upk);
// Set to the public ID of the account
uc.User.IssuerAccount = accId;
// Sign the user claims with the account signing key
string userJwt = jwt.EncodeUserClaims(uc, accountSigningKey);
// The seed is a version of the keypair that is stored as text
// and it is considered sensitive information.
string userSeed = ukp.GetSeed();
// Generate a creds formatted file that can be used by a NATS client
string creds = jwt.FormatUserConfig(userJwt, userSeed);
Console.WriteLine(creds);system_account: AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5leafnodes {
remotes = [
{
url: "nats://localhost:4222"
credentials: "./your-account.creds"
},
{
url: "nats://localhost:4222"
account: "$SYS"
credentials: "./system-account.creds"
},
]
}operator: ./trustedOperator.jwt
system_account: AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5
leafnodes {
remotes = [
{
url: "nats://localhost:4222"
account: "ADKGAJU55CHYOIF5H432K2Z2ME3NPSJ5S3VY5Q42Q3OTYOCYRRG7WOWV"
credentials: "./your-account.creds"
},
{
url: "nats://localhost:4222"
account: "AAAXAUVSGK7TCRHFIRAS4SYXVJ76EWDMNXZM6ARFGXP7BASNDGLKU7A5"
credentials: "./system-account.creds"
},
]
}nsc add import --account test --src-account ACJ6G45BE7LLOFCVAZSZR3RY4XELXQ32BOQRI7KQMQLICXXXJRP4P45Q --remote-subject foo --local-subject bar[ OK ] added stream import "blo"nsc revocations add-user --account SYS --name sys[ OK ] revoked user "UCL5YXXUKCEO4HDTTYUOHDMHP4JJ6MGE3SVQBDWFZUGJUMUKE24DEUCU"nsc revocations list-users+------------------------------------------------------------------------------------------+
| Revoked Users for test5 |
+----------------------------------------------------------+-------------------------------+
| Public Key | Revoke Credentials Before |
+----------------------------------------------------------+-------------------------------+
| UAX7KQJJNL5NIRTSQSANKE3DNBHLLFUYKRXCD5QRKI75XBEHQOA4ZZGV | Wed, 10 Feb 2021 12:51:09 EST |
+----------------------------------------------------------+-------------------------------+nsc revocations add-activation --account <account name> --subject <export name> \
--target-account <account identity public NKEY>nsc revocations delete_activation --account <account name> \
--subject <export name> --target-account <account identity public NKEY>nsc revocations add-activation --account SYS --subject foo \
--target-account AAUDEW26FB4TOJAQN3DYMDLCVXZMNIJWP2EMOAM5HGKLF6RGMO2PV7WP[ OK ] revoked activation "foo" for account AAUDEW26FB4TOJAQN3DYMDLCVXZMNIJWP2EMOAM5HGKLF6RGMO2PV7WPnsc revocations list-activations --account SYS+------------------------------------------------------------------------------------------+
| Revoked Accounts for stream foo |
+----------------------------------------------------------+-------------------------------+
| Public Key | Revoke Credentials Before |
+----------------------------------------------------------+-------------------------------+
| AAUDEW26FB4TOJAQN3DYMDLCVXZMNIJWP2EMOAM5HGKLF6RGMO2PV7WP | Wed, 10 Feb 2021 13:22:11 EST |
+----------------------------------------------------------+-------------------------------+ [98019] 2020/10/26 16:07:53.861612 [TRC] 127.0.0.1:56830 - cid:4 - <<- [CONNECT {
"echo": true,
"headers": true,
"jwt": "eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJXNkFYSFlSS1RHVTNFUklQM0dSRDdNV0FQTzQ2VzQ2Vzc3R1JNMk5SWFFIQ0VRQ0tCRjJRIiwiaWF0IjoxNjAzNDczNzg4LCJpc3MiOiJBQUFYQVVWU0dLN1RDUkhGSVJBUzRTWVhWSjc2RVdETU5YWk02QVJGR1hQN0JBU05ER0xLVTdBNSIsIm5hbWUiOiJzeXMiLCJzdWIiOiJVRE5ZMktLUFRJQVBQTk9OT0xBVE5SWlBHTVBMTkZXSFFQS1VYSjZBMllUQTQ3Tk41Vk5GSU80NSIsInR5cGUiOiJ1c2VyIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9fX0.ae3OvcapjQgbXhI2QbgIs32AWr3iBb2UFRZbXzIg0duFHNPQI5LsprR0OQoSlc2tic6e3sn8YM5x0Rt34FryDA",
"lang": "go",
"name": "NATS CLI",
"no_responders": true,
"pedantic": false,
"protocol": 1,
"sig": "VirwM--xq5i2RI9VEQiFYv_6JBs-IR4oObypglR7qVxYtXDUtIKIr1qXW_M54iHFB6Afu698J_in5CfBRjuVBg",
"tls_required": true,
"verbose": false,
"version": "1.11.0"
}]nats str add ORDERS? Subjects to consume ORDERS.*
? Storage backend file
? Retention Policy Limits
? Discard Policy Old
? Message count limit -1
? Message size limit -1
? Maximum message age limit 1y
? Maximum individual message size [? for help] (-1) -1
Stream ORDERS was created
Information for Stream ORDERS
Configuration:
Subjects: ORDERS.*
Acknowledgements: true
Retention: File - Limits
Replicas: 1
Maximum Messages: -1
Maximum Bytes: -1
Maximum Age: 8760h0m0s
Maximum Message Size: -1
Maximum Consumers: -1
Statistics:
Messages: 0
Bytes: 0 B
FirstSeq: 0
LastSeq: 0
Active Consumers: 0nats str add ORDERS --subjects "ORDERS.*" --ack --max-msgs=-1 --max-bytes=-1 --max-age=1y --storage file --retention limits --max-msg-size=-1 --discard old --dupe-window="0s" --replicas 1nats str add ORDERS --config orders.jsonnats str lsStreams:
ORDERSnats str info ORDERSInformation for Stream ORDERS created 2021-02-27T16:49:36-07:00
Configuration:
Subjects: ORDERS.*
Acknowledgements: true
Retention: File - Limits
Replicas: 1
Discard Policy: Old
Duplicate Window: 2m0s
Maximum Messages: unlimited
Maximum Bytes: unlimited
Maximum Age: 1y0d0h0m0s
Maximum Message Size: unlimited
Maximum Consumers: unlimited
State:
Messages: 0
Bytes: 0 B
FirstSeq: 0
LastSeq: 0
Active Consumers: 0nats str info ORDERS -j{
"config": {
"name": "ORDERS",
"subjects": [
"ORDERS.*"
],
"retention": "limits",
"max_consumers": -1,
"max_msgs": -1,
"max_bytes": -1,
"max_age": 31536000000000000,
"max_msg_size": -1,
"storage": "file",
"discard": "old",
"num_replicas": 1,
"duplicate_window": 120000000000
},
"created": "2021-02-27T23:49:36.700424Z",
"state": {
"messages": 0,
"bytes": 0,
"first_seq": 0,
"first_ts": "0001-01-01T00:00:00Z",
"last_seq": 0,
"last_ts": "0001-01-01T00:00:00Z",
"consumer_count": 0
}
}nats str cp ORDERS ARCHIVE --subjects "ORDERS_ARCHIVE.*" --max-age 2yStream ORDERS was created
Information for Stream ORDERS created 2021-02-27T16:52:46-07:00
Configuration:
Subjects: ORDERS_ARCHIVE.*
Acknowledgements: true
Retention: File - Limits
Replicas: 1
Discard Policy: Old
Duplicate Window: 2m0s
Maximum Messages: unlimited
Maximum Bytes: unlimited
Maximum Age: 2y0d0h0m0s
Maximum Message Size: unlimited
Maximum Consumers: unlimited
State:
Messages: 0
Bytes: 0 B
FirstSeq: 0
LastSeq: 0
Active Consumers: 0nats str info ORDERS -j | jq .config.subjects[
"ORDERS.new"
]nats str edit ORDERS --subjects "ORDERS.*"Stream ORDERS was updated
Information for Stream ORDERS
Configuration:
Subjects: ORDERS.*
....nats str edit ORDERS --config orders.jsonnats pub ORDERS.scratch hellonats req ORDERS.scratch hello13:45:03 Sending request on [ORDERS.scratch]
13:45:03 Received on [_INBOX.M8drJkd8O5otORAo0sMNkg.scHnSafY]: '+OK'nats str info ORDERSInformation for Stream ORDERS
...
Statistics:
Messages: 3
Bytes: 147 B
FirstSeq: 1
LastSeq: 3
Active Consumers: 0nats str purge ORDERS -f...
State:
Messages: 0
Bytes: 0 B
FirstSeq: 1,000,001
LastSeq: 1,000,000
Active Consumers: 0nats str rmm ORDERS 1 -fnats str rm ORDERS -f
nats str add ORDERS --subjects "ORDERS.*" --ack --max-msgs=-1 --max-bytes=-1 --max-age=1y --storage file --retention limits --max-msg-size=-1 --discard old --dupe-window="0s" --replicas 1