nats-micro
Version:
NATS micro compatible extra-lightweight microservice library
261 lines • 12.1 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
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());
});
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NatsBroker = void 0;
const nats = __importStar(require("nats"));
const debug_js_1 = require("./debug.js");
const tokenEventEmitter_js_1 = require("./tokenEventEmitter.js");
const index_js_1 = require("./utils/index.js");
class NatsBroker {
// eslint-disable-next-line no-useless-constructor, no-empty-function
constructor(options) {
this.options = options;
this.ee = new tokenEventEmitter_js_1.TokenEventEmitter();
// eslint-disable-next-line new-cap
this.codec = nats.JSONCodec();
this.subscriptions = {};
}
get name() {
var _a, _b;
return (_a = this.options.name) !== null && _a !== void 0 ? _a : ((_b = process.env.MICROSERVICE_NODE_NAME) !== null && _b !== void 0 ? _b : '');
}
connect() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
debug_js_1.debug.broker.info(`Connecting to ${this.options.servers} as "${this.options.name}"`);
try {
this.connection = yield nats.connect(this.options);
this.clientId = (_a = this.connection.info) === null || _a === void 0 ? void 0 : _a.client_id;
this.connectionClosedWaiter = this.connection.closed();
debug_js_1.debug.broker.info(`Connected as ${this.clientId}`);
return this;
}
catch (err) {
debug_js_1.debug.broker.error(`Failed to connect: ${(0, index_js_1.errorToString)(err)}`);
throw err;
}
});
}
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
debug_js_1.debug.broker.info('Disconnecting from server');
try {
if (!this.connection) {
debug_js_1.debug.broker.info('Not connected to server');
return;
}
yield this.connection.close();
this.subscriptions = {};
const err = yield this.connectionClosedWaiter;
if (err)
throw err;
debug_js_1.debug.broker.info('Disconnected from server');
}
catch (err) {
debug_js_1.debug.broker.error(`Error disconnecting from server: ${(0, index_js_1.errorToString)(err)}`);
throw err;
}
});
}
createInbox() {
return nats.createInbox();
}
decode(msg) {
const str = msg.string();
if (str === '')
return '';
return this.codec.decode(msg.data);
}
handleMessageFromSubscription(err, msg) {
if (err) {
debug_js_1.debug.broker.error(`Incoming error in message on "${msg.subject}": ${JSON.stringify(err)}`);
}
else {
debug_js_1.debug.broker.debug(`Incoming message on "${msg.subject}": ${JSON.stringify(msg.string())}`);
try {
this.ee.emit(msg.subject, {
data: this.decode(msg),
headers: this.decodeHeaders(msg.headers),
replyTo: msg.reply,
});
}
catch (ex) {
let content;
try {
content = msg.string();
}
catch (_a) {
content = `${msg.data.byteLength} bytes`;
}
debug_js_1.debug.broker.error(`Error decoding JSON from "${content}"`);
debug_js_1.debug.broker.debug(String(ex));
}
}
}
encodeHeaders(headers) {
const result = nats.headers();
if (headers)
for (const [k, v] of headers)
result.append(k, v.replace(/[\r\n]+/g, ' '));
return result;
}
decodeHeaders(headers) {
if (!headers)
return [];
const result = [];
for (const key of headers.keys())
for (const value of headers.values(key))
result.push([key, value]);
return result;
}
subscribe(subject, queue) {
if (!this.connection)
throw new Error('Not connected');
debug_js_1.debug.broker.debug(`Subscribing to "${subject}"`);
return this.connection.subscribe(subject, {
queue,
callback: this.handleMessageFromSubscription.bind(this),
});
}
unsubscribe(subscription) {
if (!this.connection)
throw new Error('Not connected');
debug_js_1.debug.broker.debug(`Unsubscribing from "${subscription.getSubject()}"`);
subscription.unsubscribe();
}
on(subject, listener, queue = undefined) {
const subj = (0, index_js_1.subjectToString)(subject);
if (!this.subscriptions[subj]) {
this.subscriptions[subj] = this.subscribe(subj, queue);
}
this.ee.on(subj, listener);
}
off(subject, listener) {
const subj = (0, index_js_1.subjectToString)(subject);
this.ee.off(subj, listener);
if (this.subscriptions[subj]) {
if (!this.ee['handlers'].find((handler) => handler.wildcard === subj)) {
this.unsubscribe(this.subscriptions[subj]);
delete (this.subscriptions[subj]);
}
}
}
send(subject, data, options) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.connection)
throw new Error('Not connected');
yield this.connection.publish((0, index_js_1.subjectToString)(subject), this.codec.encode(data), {
headers: this.encodeHeaders((0, index_js_1.addThreadContextHeaders)(options === null || options === void 0 ? void 0 : options.headers)),
reply: (options && options.replyTo)
? options.replyTo
: undefined,
});
});
}
requestMany(subject, data, options) {
var _a, _b, _c;
return __asyncGenerator(this, arguments, function* requestMany_1() {
if (!this.connection)
throw new Error('Not connected');
const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 30000;
try {
const responses = yield __await(this.connection.requestMany((0, index_js_1.subjectToString)(subject), this.codec.encode(data), {
headers: this.encodeHeaders((0, index_js_1.addThreadContextHeaders)(options === null || options === void 0 ? void 0 : options.headers)),
noMux: true,
strategy: ((_b = options === null || options === void 0 ? void 0 : options.limit) !== null && _b !== void 0 ? _b : 0) < 0
? nats.RequestStrategy.Timer
: nats.RequestStrategy.Count,
maxMessages: ((_c = options === null || options === void 0 ? void 0 : options.limit) !== null && _c !== void 0 ? _c : 0) < 0
? undefined
: options === null || options === void 0 ? void 0 : options.limit,
maxWait: timeout,
// reply: `_INBOX.${microservice}.${randomId()}`,
// timeout,
}));
const iterator = responses[Symbol.asyncIterator]();
let result = yield __await(iterator.next());
while (!result.done) {
yield yield __await({
data: this.codec.decode(result.value.data),
headers: this.decodeHeaders(result.value.headers),
subject: result.value.subject,
});
result = yield __await(iterator.next());
}
}
catch (err) {
if (typeof (err) === 'object' && err && 'code' in err && err.code === '503')
return yield __await(void 0); // NATS no responders available
throw err;
}
});
}
request(subject, data, options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (!this.connection)
throw new Error('Not connected');
const timeout = (_a = options === null || options === void 0 ? void 0 : options.timeout) !== null && _a !== void 0 ? _a : 30000;
const res = yield this.connection.request((0, index_js_1.subjectToString)(subject), this.codec.encode(data), {
headers: this.encodeHeaders((0, index_js_1.addThreadContextHeaders)(options === null || options === void 0 ? void 0 : options.headers)),
noMux: true,
reply: `_INBOX.${(0, index_js_1.randomId)()}`,
timeout,
});
const headers = this.decodeHeaders(res.headers);
const error = (0, index_js_1.errorFromHeaders)(headers);
if (error)
throw error;
return {
data: this.codec.decode(res.data),
headers,
subject: res.subject,
};
});
}
}
exports.NatsBroker = NatsBroker;
//# sourceMappingURL=natsBroker.js.map