UNPKG

hfs

Version:
126 lines (125 loc) 4.69 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SendListReadable = void 0; const stream_1 = require("stream"); const lodash_1 = __importDefault(require("lodash")); const cross_1 = require("./cross"); const events_1 = __importDefault(require("./events")); // offer an api for a generic dynamic list. Suitable to be the result of an api. class SendListReadable extends stream_1.Readable { constructor({ addAtStart, doAtStart, bufferTime, onEnd, diff } = {}) { super({ objectMode: true, read() { } }); this.buffer = []; if (!bufferTime) bufferTime = 200; if (diff) this.sent = []; this.processBuffer = lodash_1.default.debounce(() => { const { sent } = this; if (sent) this.buffer = this.buffer.filter(([cmd, a, b]) => { var _a; if (cmd === cross_1.LIST.add) return sent.push(...(0, cross_1.wantArray)(a)); if (cmd === cross_1.LIST.remove) return lodash_1.default.remove(sent, a); if (cmd !== cross_1.LIST.update) return true; const found = lodash_1.default.find(sent, a); if (!found) return; for (const k in b) if (b[k] === found[k]) delete b[k]; else { found[k] = b[k]; (_a = b[k]) !== null && _a !== void 0 ? _a : (b[k] = null); // go and delete it, remotely } return !lodash_1.default.isEmpty(b); }); if (!this.buffer.length) return; this.push(this.buffer); this.buffer = []; }, bufferTime, { maxWait: bufferTime }); this.on('close', () => { onEnd === null || onEnd === void 0 ? void 0 : onEnd(this); this.destroy(); }); setTimeout(() => doAtStart === null || doAtStart === void 0 ? void 0 : doAtStart(this)); // work later, when list object has been received by Koa if (addAtStart) { for (const x of addAtStart) this.add(x); this.ready(); } } _push(rec) { this.buffer.push(rec); if (this.buffer.length > 10000) // hard limit this.processBuffer.flush(); else this.processBuffer(); } add(rec) { this._push([cross_1.LIST.add, rec]); } remove(search) { const match = lodash_1.default.matches(search); const idx = lodash_1.default.findIndex(this.buffer, x => match(x[1])); const found = this.buffer[idx]; const op = found === null || found === void 0 ? void 0 : found[0]; if (op === cross_1.LIST.remove) return; if (found) { this.buffer.splice(idx, 1); if (op === cross_1.LIST.add) return; // assuming this never reached the client } this._push([cross_1.LIST.remove, search]); } update(search, change) { if (lodash_1.default.isEmpty(change)) return; const match = lodash_1.default.matches(search); const found = lodash_1.default.find(this.buffer, x => match(x[1])); const op = found === null || found === void 0 ? void 0 : found[0]; if (op === cross_1.LIST.remove) return; if (op === cross_1.LIST.add || op === cross_1.LIST.update) return Object.assign(found[op === cross_1.LIST.add ? 1 : 2], change); this._push([cross_1.LIST.update, search, change]); } ready() { this._push([cross_1.LIST.ready]); } custom(name, data) { this._push(data === undefined ? [name] : [name, data]); } props(props) { this._push([cross_1.LIST.props, props]); } error(msg, close = false, props) { this._push([cross_1.LIST.error, msg, props]); this.lastError = msg; if (close) this.close(); } getLastError() { return this.lastError; } close() { this.processBuffer.flush(); this.push(null); } events(ctx, eventMap) { ctx.res.once('close', events_1.default.multi(eventMap)); return this; } isClosed() { return this.destroyed; } } exports.SendListReadable = SendListReadable;