hfs
Version:
HTTP File Server
126 lines (125 loc) • 4.69 kB
JavaScript
"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;