import { fetchTransactions } from '../../api-node/transactions'; import { indexBy, keys, prop } from '../utils'; import { EventEmitter } from 'typed-ts-events'; export class Watch { constructor(base, address, tx, interval) { this._emitter = new EventEmitter(); this._timer = null; this.address = address; this._interval = interval || 1000; this._base = base; this._lastBlock = { lastId: (tx === null || tx === void 0 ? void 0 : tx.id) || '', height: (tx === null || tx === void 0 ? void 0 : tx.height) || 0, transactions: tx ? [tx] : [] }; this._addTimeout(); } on(event, handler) { this._emitter.on(event, handler); } once(event, handler) { this._emitter.once(event, handler); } off(event, handler) { this._emitter.off(event, handler); } _run() { if (this._timer) { clearTimeout(this._timer); } const onError = () => this._addTimeout(); fetchTransactions(this._base, this.address, 1) .then(([tx]) => { if (!tx) { this._addTimeout(); return null; } this.getTransactionsInHeight(tx, 310) .then(list => { const hash = Watch._groupByHeight(list); const heightList = keys(hash) .map(Number) .sort((a, b) => b - a); const [last, prev] = heightList; if (!this._lastBlock.height) { this._lastBlock = { height: last, lastId: hash[prev] && hash[prev].length ? hash[prev][0].id : '', transactions: hash[last] }; this._emitter.trigger('change-state', list); } else { const wasDispatchHash = indexBy(prop('id'), this._lastBlock.transactions); const toDispatch = Watch._getTransactionsToDispatch([...hash[last], ...(hash[prev] || [])], wasDispatchHash, this._lastBlock.lastId); if (this._lastBlock.height !== last) { this._lastBlock = { height: last, lastId: hash[prev] && hash[prev].length ? hash[prev][0].id : '', transactions: hash[last] }; } else { this._lastBlock.transactions.push(...toDispatch); } if (toDispatch.length) { this._emitter.trigger('change-state', toDispatch); } } this._addTimeout(); }, onError); }) .catch(onError); } getTransactionsInHeight(from, limit) { const height = from.height; const loop = (downloaded) => { if (downloaded.length >= limit) { return Promise.resolve(downloaded); } return fetchTransactions(this._base, this.address, downloaded.length + 100).then(list => { if (downloaded.length === list.length) { return downloaded; } const hash = Watch._groupByHeight(list); const heightList = keys(hash) .map(Number) .sort((a, b) => b - a); const [last, prev] = heightList; if (last === height) { return prev ? [...hash[last], hash[prev][0]] : loop(list); } else { return loop(list); } }); }; return loop([from]); } _addTimeout() { this._timer = setTimeout(() => { this._run(); }, this._interval); } static _groupByHeight(list) { return list.reduce((hash, tx) => { if (!hash[tx.height]) { hash[tx.height] = [tx]; } else { hash[tx.height].push(tx); } return hash; }, Object.create(null)); } static _getTransactionsToDispatch(list, dispatched, lastId) { const result = []; for (let i = 0; i < list.length; i++) { const tx = list[i]; if (tx.id === lastId) { break; } if (!dispatched[tx.id]) { result.push(tx); } } return result; } } export default function (base, address, interval) { return fetchTransactions(base, address, 1) .then(([tx]) => new Watch(base, address, tx, interval)); } //# sourceMappingURL=watch.js.map