nats
Version:
Node.js client for NATS, a lightweight, high-performance cloud native messaging system
283 lines • 11.5 kB
JavaScript
;
/*
* Copyright 2021-2022 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.
*/
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.StoredMsgImpl = exports.StreamAPIImpl = exports.convertStreamSourceDomain = void 0;
const types_1 = require("./types");
const jsbaseclient_api_1 = require("./jsbaseclient_api");
const jslister_1 = require("./jslister");
const jsutil_1 = require("./jsutil");
const headers_1 = require("./headers");
const kv_1 = require("./kv");
const objectstore_1 = require("./objectstore");
function convertStreamSourceDomain(s) {
if (s === undefined) {
return undefined;
}
const { domain } = s;
if (domain === undefined) {
return s;
}
const copy = Object.assign({}, s);
delete copy.domain;
if (domain === "") {
return copy;
}
if (copy.external) {
throw new Error("domain and external are both set");
}
copy.external = { api: `$JS.${domain}.API` };
return copy;
}
exports.convertStreamSourceDomain = convertStreamSourceDomain;
class StreamAPIImpl extends jsbaseclient_api_1.BaseApiClient {
constructor(nc, opts) {
super(nc, opts);
}
add(cfg = {}) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
(0, jsutil_1.validateStreamName)(cfg.name);
cfg.mirror = convertStreamSourceDomain(cfg.mirror);
//@ts-ignore: the sources are either set or not - so no item should be undefined in the list
cfg.sources = (_a = cfg.sources) === null || _a === void 0 ? void 0 : _a.map(convertStreamSourceDomain);
const r = yield this._request(`${this.prefix}.STREAM.CREATE.${cfg.name}`, cfg);
const si = r;
this._fixInfo(si);
return si;
});
}
delete(stream) {
return __awaiter(this, void 0, void 0, function* () {
(0, jsutil_1.validateStreamName)(stream);
const r = yield this._request(`${this.prefix}.STREAM.DELETE.${stream}`);
const cr = r;
return cr.success;
});
}
update(name, cfg = {}) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
if (typeof name === "object") {
const sc = name;
name = sc.name;
cfg = sc;
console.trace(`\u001B[33m >> streams.update(config: StreamConfig) api changed to streams.update(name: string, config: StreamUpdateConfig) - this shim will be removed - update your code. \u001B[0m`);
}
(0, jsutil_1.validateStreamName)(name);
const old = yield this.info(name);
const update = Object.assign(old.config, cfg);
update.mirror = convertStreamSourceDomain(update.mirror);
//@ts-ignore: the sources are either set or not - so no item should be undefined in the list
update.sources = (_a = update.sources) === null || _a === void 0 ? void 0 : _a.map(convertStreamSourceDomain);
const r = yield this._request(`${this.prefix}.STREAM.UPDATE.${name}`, update);
const si = r;
this._fixInfo(si);
return si;
});
}
info(name, data) {
return __awaiter(this, void 0, void 0, function* () {
(0, jsutil_1.validateStreamName)(name);
const subj = `${this.prefix}.STREAM.INFO.${name}`;
const r = yield this._request(subj, data);
let si = r;
let { total, limit } = si;
// check how many subjects we got in the first request
let have = si.state.subjects
? Object.getOwnPropertyNames(si.state.subjects).length
: 1;
// if the response is paged, we have a large list of subjects
// handle the paging and return a StreamInfo with all of it
if (total && total > have) {
const infos = [si];
const paged = data || {};
let i = 0;
// total could change, so it is possible to have collected
// more that the total
while (total > have) {
i++;
paged.offset = limit * i;
const r = yield this._request(subj, paged);
// update it in case it changed
total = r.total;
infos.push(r);
const count = Object.getOwnPropertyNames(r.state.subjects).length;
have += count;
// if request returns less than limit it is done
if (count < limit) {
// done
break;
}
}
// collect all the subjects
let subjects = {};
for (let i = 0; i < infos.length; i++) {
si = infos[i];
if (si.state.subjects) {
subjects = Object.assign(subjects, si.state.subjects);
}
}
// don't give the impression we paged
si.offset = 0;
si.total = 0;
si.limit = 0;
si.state.subjects = subjects;
}
this._fixInfo(si);
return si;
});
}
list(subject = "") {
const payload = (subject === null || subject === void 0 ? void 0 : subject.length) ? { subject } : {};
const listerFilter = (v) => {
const slr = v;
slr.streams.forEach((si) => {
this._fixInfo(si);
});
return slr.streams;
};
const subj = `${this.prefix}.STREAM.LIST`;
return new jslister_1.ListerImpl(subj, listerFilter, this, payload);
}
// FIXME: init of sealed, deny_delete, deny_purge shouldn't be necessary
// https://github.com/nats-io/nats-server/issues/2633
_fixInfo(si) {
si.config.sealed = si.config.sealed || false;
si.config.deny_delete = si.config.deny_delete || false;
si.config.deny_purge = si.config.deny_purge || false;
si.config.allow_rollup_hdrs = si.config.allow_rollup_hdrs || false;
}
purge(name, opts) {
return __awaiter(this, void 0, void 0, function* () {
if (opts) {
const { keep, seq } = opts;
if (typeof keep === "number" && typeof seq === "number") {
throw new Error("can specify one of keep or seq");
}
}
(0, jsutil_1.validateStreamName)(name);
const v = yield this._request(`${this.prefix}.STREAM.PURGE.${name}`, opts);
return v;
});
}
deleteMessage(stream, seq, erase = true) {
return __awaiter(this, void 0, void 0, function* () {
(0, jsutil_1.validateStreamName)(stream);
const dr = { seq };
if (!erase) {
dr.no_erase = true;
}
const r = yield this._request(`${this.prefix}.STREAM.MSG.DELETE.${stream}`, dr);
const cr = r;
return cr.success;
});
}
getMessage(stream, query) {
return __awaiter(this, void 0, void 0, function* () {
(0, jsutil_1.validateStreamName)(stream);
const r = yield this._request(`${this.prefix}.STREAM.MSG.GET.${stream}`, query);
const sm = r;
return new StoredMsgImpl(sm);
});
}
find(subject) {
return this.findStream(subject);
}
listKvs() {
const filter = (v) => {
var _a, _b;
const slr = v;
const kvStreams = slr.streams.filter((v) => {
return v.config.name.startsWith(kv_1.kvPrefix);
});
kvStreams.forEach((si) => {
this._fixInfo(si);
});
let cluster = "";
if (kvStreams.length) {
cluster = (_b = (_a = this.nc.info) === null || _a === void 0 ? void 0 : _a.cluster) !== null && _b !== void 0 ? _b : "";
}
const status = kvStreams.map((si) => {
return new kv_1.KvStatusImpl(si, cluster);
});
return status;
};
const subj = `${this.prefix}.STREAM.LIST`;
return new jslister_1.ListerImpl(subj, filter, this);
}
listObjectStores() {
const filter = (v) => {
const slr = v;
const objStreams = slr.streams.filter((v) => {
return v.config.name.startsWith(objectstore_1.osPrefix);
});
objStreams.forEach((si) => {
this._fixInfo(si);
});
const status = objStreams.map((si) => {
return new objectstore_1.ObjectStoreStatusImpl(si);
});
return status;
};
const subj = `${this.prefix}.STREAM.LIST`;
return new jslister_1.ListerImpl(subj, filter, this);
}
names(subject = "") {
const payload = (subject === null || subject === void 0 ? void 0 : subject.length) ? { subject } : {};
const listerFilter = (v) => {
const slr = v;
return slr.streams;
};
const subj = `${this.prefix}.STREAM.NAMES`;
return new jslister_1.ListerImpl(subj, listerFilter, this, payload);
}
}
exports.StreamAPIImpl = StreamAPIImpl;
class StoredMsgImpl {
constructor(smr) {
this.subject = smr.message.subject;
this.seq = smr.message.seq;
this.time = new Date(Date.parse(smr.message.time));
this.data = smr.message.data ? this._parse(smr.message.data) : types_1.Empty;
if (smr.message.hdrs) {
const hd = this._parse(smr.message.hdrs);
this.header = headers_1.MsgHdrsImpl.decode(hd);
}
else {
this.header = (0, headers_1.headers)();
}
}
_parse(s) {
const bs = atob(s);
const len = bs.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = bs.charCodeAt(i);
}
return bytes;
}
}
exports.StoredMsgImpl = StoredMsgImpl;
//# sourceMappingURL=jsmstream_api.js.map