nats
Version:
Node.js client for NATS, a lightweight, high-performance cloud native messaging system
195 lines • 6.99 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsMsgImpl = exports.parseInfo = exports.toJsMsg = exports.ACK = void 0;
/*
* Copyright 2021-2024 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const databuffer_1 = require("../nats-base-client/databuffer");
const codec_1 = require("../nats-base-client/codec");
const request_1 = require("../nats-base-client/request");
const mod_1 = require("../nats-base-client/mod");
const util_1 = require("../nats-base-client/util");
exports.ACK = Uint8Array.of(43, 65, 67, 75);
const NAK = Uint8Array.of(45, 78, 65, 75);
const WPI = Uint8Array.of(43, 87, 80, 73);
const NXT = Uint8Array.of(43, 78, 88, 84);
const TERM = Uint8Array.of(43, 84, 69, 82, 77);
const SPACE = Uint8Array.of(32);
function toJsMsg(m) {
return new JsMsgImpl(m);
}
exports.toJsMsg = toJsMsg;
function parseInfo(s) {
const tokens = s.split(".");
if (tokens.length === 9) {
tokens.splice(2, 0, "_", "");
}
if ((tokens.length < 11) || tokens[0] !== "$JS" || tokens[1] !== "ACK") {
throw new Error(`not js message`);
}
// old
// "$JS.ACK.<stream>.<consumer>.<redeliveryCount><streamSeq><deliverySequence>.<timestamp>.<pending>"
// new
// $JS.ACK.<domain>.<accounthash>.<stream>.<consumer>.<redeliveryCount>.<streamSeq>.<deliverySequence>.<timestamp>.<pending>.<random>
const di = {};
// if domain is "_", replace with blank
di.domain = tokens[2] === "_" ? "" : tokens[2];
di.account_hash = tokens[3];
di.stream = tokens[4];
di.consumer = tokens[5];
di.redeliveryCount = parseInt(tokens[6], 10);
di.redelivered = di.redeliveryCount > 1;
di.streamSequence = parseInt(tokens[7], 10);
di.deliverySequence = parseInt(tokens[8], 10);
di.timestampNanos = parseInt(tokens[9], 10);
di.pending = parseInt(tokens[10], 10);
return di;
}
exports.parseInfo = parseInfo;
class JsMsgImpl {
constructor(msg) {
this.msg = msg;
this.didAck = false;
}
get subject() {
return this.msg.subject;
}
get sid() {
return this.msg.sid;
}
get data() {
return this.msg.data;
}
get headers() {
return this.msg.headers;
}
get info() {
if (!this.di) {
this.di = parseInfo(this.reply);
}
return this.di;
}
get redelivered() {
return this.info.redeliveryCount > 1;
}
get reply() {
return this.msg.reply || "";
}
get seq() {
return this.info.streamSequence;
}
doAck(payload) {
if (!this.didAck) {
// all acks are final with the exception of +WPI
this.didAck = !this.isWIP(payload);
this.msg.respond(payload);
}
}
isWIP(p) {
return p.length === 4 && p[0] === WPI[0] && p[1] === WPI[1] &&
p[2] === WPI[2] && p[3] === WPI[3];
}
// this has to dig into the internals as the message has access
// to the protocol but not the high-level client.
ackAck() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const d = (0, mod_1.deferred)();
if (!this.didAck) {
this.didAck = true;
if (this.msg.reply) {
const mi = this.msg;
const proto = mi.publisher;
const trace = !(((_a = proto.options) === null || _a === void 0 ? void 0 : _a.noAsyncTraces) || false);
const r = new request_1.RequestOne(proto.muxSubscriptions, this.msg.reply, {
timeout: 1000,
}, trace);
proto.request(r);
try {
proto.publish(this.msg.reply, exports.ACK, {
reply: `${proto.muxSubscriptions.baseInbox}${r.token}`,
});
}
catch (err) {
r.cancel(err);
}
try {
yield Promise.race([r.timer, r.deferred]);
d.resolve(true);
}
catch (err) {
r.cancel(err);
d.reject(err);
}
}
else {
d.resolve(false);
}
}
else {
d.resolve(false);
}
return d;
});
}
ack() {
this.doAck(exports.ACK);
}
nak(millis) {
let payload = NAK;
if (millis) {
payload = (0, codec_1.StringCodec)().encode(`-NAK ${JSON.stringify({ delay: (0, util_1.nanos)(millis) })}`);
}
this.doAck(payload);
}
working() {
this.doAck(WPI);
}
next(subj, opts = { batch: 1 }) {
const args = {};
args.batch = opts.batch || 1;
args.no_wait = opts.no_wait || false;
if (opts.expires && opts.expires > 0) {
args.expires = (0, util_1.nanos)(opts.expires);
}
const data = (0, codec_1.JSONCodec)().encode(args);
const payload = databuffer_1.DataBuffer.concat(NXT, SPACE, data);
const reqOpts = subj ? { reply: subj } : undefined;
this.msg.respond(payload, reqOpts);
}
term(reason = "") {
let term = TERM;
if ((reason === null || reason === void 0 ? void 0 : reason.length) > 0) {
term = (0, codec_1.StringCodec)().encode(`+TERM ${reason}`);
}
this.doAck(term);
}
json() {
return this.msg.json();
}
string() {
return this.msg.string();
}
}
exports.JsMsgImpl = JsMsgImpl;
//# sourceMappingURL=jsmsg.js.map