UNPKG

badmfck-signal

Version:

An implementation of a signaling mechanism used to connect components and transfer data between them

152 lines (150 loc) 4.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataProvider = void 0; const _1 = __importDefault(require(".")); /** K - request type T - data type */ class DataProvider { response = null; busy = false; options; lastFetchTime = -1; callbacks = new _1.default(); subscribers = new _1.default(); name; executor = null; defaultNotificator = null; lastRequestHash = null; static nextID = 0; constructor(opt, name) { if (!opt) { opt = { cacheTime: -1, }; } this.options = opt; this.setOptions(opt); if (!name) name = "DataProvider_" + DataProvider.nextID++; this.name = name; } reset() { this.response = null; this.busy = false; this.lastFetchTime = -1; this.lastRequestHash = null; this.response = null; } isBusy() { return this.busy; } isEmpty() { return this.getError() !== null || this.getData() === null; } setExecutor(executor) { this.executor = executor; return this; } getData() { if (!this.response || !this.response.data) return null; if (Array.isArray(this.response?.data)) return [...this.response?.data]; else if (typeof this.response?.data === "object") return { ...this.response?.data }; return this.response?.data; } setOptions(opt) { this.options = opt; } getError() { if (!this.response || !this.response.error) return null; return { ...this.response.error }; } setDefaultNotificator(notificator) { this.defaultNotificator = notificator; return this; } /** Subscribe to data loading complete event. will fire response and remove subscribtion */ subscribe(cb) { this.subscribers.subscribe(cb); } async load(req) { if (!this.executor) throw Error("Executor not registered in data provider, " + this.name); const promise = new Promise((resolve, reject) => { this.callbacks.subscribe(data => { resolve(data); this.subscribers.invoke(data); this.subscribers.removeAll(); if (this.defaultNotificator) { if (!this.isEmpty()) this.defaultNotificator.invoke(this.getData()); else this.defaultNotificator.invoke(this.getError()); } }); }); const requestHash = fastHash(JSON.stringify(req ?? "")); if (requestHash !== this.lastRequestHash) { this.response = null; this.busy = false; } this.lastRequestHash = requestHash; // if (this.defaultNotificator) { if (!this.isEmpty()) { this.defaultNotificator.invoke(this.getData()); } else { this.defaultNotificator?.invoke(this.getError()); } } if (this.busy) return promise; if (this.options && this.options.cacheTime > -1 && this.response && !this.response.error) { if (this.options.cacheTime === 0) { this.callbacks.invoke(this.response); return this.response; } if (+new Date() - this.lastFetchTime < this.options.cacheTime) { this.callbacks.invoke(this.response); return this.response; } } this.busy = true; this.response = await this.executor(req); this.lastFetchTime = +new Date(); this.busy = false; this.callbacks.invoke(this.response); this.callbacks.removeAll(); return promise; } } exports.DataProvider = DataProvider; const fastHash = (str) => { let hash = 0; let i; for (i = 0; i < str.length; i++) { hash = (hash << 5) - hash + str.charCodeAt(i); hash |= 0; // Convert to 32bit integer } let f = "P"; if (hash < 0) { hash = hash & 0x7fffffff; f = "N"; } return f + hash.toString(16).toUpperCase(); };