feat: use subject dictionary to avoid creating multiple duplicated subscriptions (#67)
* feat: keep track of props subjects * Keep track of subjects for event and log trackers
This commit is contained in:
parent
556bf5191e
commit
81e09f1a8a
|
@ -1,4 +1,4 @@
|
||||||
import { ReplaySubject, BehaviorSubject } from 'rxjs';
|
import { ReplaySubject, BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
import equal from 'fast-deep-equal';
|
import equal from 'fast-deep-equal';
|
||||||
import Database from './database/database.js';
|
import Database from './database/database.js';
|
||||||
|
@ -10,6 +10,7 @@ import stripHexPrefix from 'strip-hex-prefix';
|
||||||
import {hexToDec} from 'hex2dec';
|
import {hexToDec} from 'hex2dec';
|
||||||
import EventSyncer from './eventSyncer';
|
import EventSyncer from './eventSyncer';
|
||||||
import LogSyncer from './logSyncer';
|
import LogSyncer from './logSyncer';
|
||||||
|
import hash from 'object-hash';
|
||||||
|
|
||||||
export default class Subspace {
|
export default class Subspace {
|
||||||
|
|
||||||
|
@ -30,19 +31,13 @@ export default class Subspace {
|
||||||
this.networkId = undefined;
|
this.networkId = undefined;
|
||||||
this.isWebsocketProvider = options.disableSubscriptions ? false : !!provider.on;
|
this.isWebsocketProvider = options.disableSubscriptions ? false : !!provider.on;
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
this.latestBlockNumber = undefined;
|
||||||
|
this.latestGasPrice = undefined;
|
||||||
|
this.latestBlock = undefined;
|
||||||
|
this.latest10Blocks = [];
|
||||||
|
|
||||||
// TODO: part of manager
|
this.subjects = {};
|
||||||
this.latestBlockNumber = undefined;
|
|
||||||
this.latestGasPrice = undefined;
|
|
||||||
this.latestBlock = undefined;
|
|
||||||
this.latest10Blocks = [];
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: part of manager
|
|
||||||
this.blockNumberObservable = null;
|
|
||||||
this.gasPriceObservable = null;
|
|
||||||
this.blockObservable = null;
|
|
||||||
this.blockTimeObservable = null;
|
|
||||||
|
|
||||||
this.newBlocksSubscription = null;
|
this.newBlocksSubscription = null;
|
||||||
this.intervalTracker = null;
|
this.intervalTracker = null;
|
||||||
|
@ -77,7 +72,7 @@ this.blockTimeObservable = null;
|
||||||
this.latest10Blocks = await Promise.all(this.latest10Blocks);
|
this.latest10Blocks = await Promise.all(this.latest10Blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: part of manager
|
// Initial stats
|
||||||
this.latestBlockNumber = block.number;
|
this.latestBlockNumber = block.number;
|
||||||
this.latestGasPrice = gasPrice;
|
this.latestGasPrice = gasPrice;
|
||||||
this.latestBlock = block;
|
this.latestBlock = block;
|
||||||
|
@ -149,9 +144,13 @@ this.blockTimeObservable = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: get contract abi/address instead
|
// TODO: get contract abi/address instead
|
||||||
trackEvent(contractInstance, eventName, filterConditionsOrCb) {
|
trackEvent(contractInstance, eventName, filterConditions) {
|
||||||
|
const subjectHash = hash({address: contractInstance.options.address, networkId: this.networkId, eventName, filterConditions});
|
||||||
|
|
||||||
|
if(this.subjects[subjectHash]) return this.subjects[subjectHash];
|
||||||
|
|
||||||
let deleteFrom = this.latestBlockNumber - this.options.refreshLastNBlocks;
|
let deleteFrom = this.latestBlockNumber - this.options.refreshLastNBlocks;
|
||||||
let returnSub = this.eventSyncer.track(contractInstance, eventName, filterConditionsOrCb, deleteFrom, this.networkId);
|
let returnSub = this.eventSyncer.track(contractInstance, eventName, filterConditions, deleteFrom, this.networkId);
|
||||||
|
|
||||||
returnSub.map = (prop) => {
|
returnSub.map = (prop) => {
|
||||||
return returnSub.pipe(map((x) => {
|
return returnSub.pipe(map((x) => {
|
||||||
|
@ -168,6 +167,8 @@ this.blockTimeObservable = null;
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.subjects[subjectHash] = returnSub;
|
||||||
|
|
||||||
return returnSub;
|
return returnSub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +182,14 @@ this.blockTimeObservable = null;
|
||||||
|
|
||||||
trackLogs(options, inputsABI) {
|
trackLogs(options, inputsABI) {
|
||||||
if(!this.isWebsocketProvider) console.warn("This method only works with websockets");
|
if(!this.isWebsocketProvider) console.warn("This method only works with websockets");
|
||||||
return this.logSyncer.track(options, inputsABI, this.latestBlockNumber - this.options.refreshLastNBlocks, this.networkId);
|
|
||||||
|
const subjectHash = hash({inputsABI, options});
|
||||||
|
|
||||||
|
if(this.subjects[subjectHash]) return this.subjects[subjectHash];
|
||||||
|
|
||||||
|
this.subjects[subjectHash] = this.logSyncer.track(options, inputsABI, this.latestBlockNumber - this.options.refreshLastNBlocks, this.networkId);
|
||||||
|
|
||||||
|
return this.subjects[subjectHash];
|
||||||
}
|
}
|
||||||
|
|
||||||
_initNewBlocksSubscription() {
|
_initNewBlocksSubscription() {
|
||||||
|
@ -209,22 +217,26 @@ this.blockTimeObservable = null;
|
||||||
}, this.options.callInterval);
|
}, this.options.callInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should save value in database?
|
|
||||||
trackProperty(contractInstance, propName, methodArgs = [], callArgs = {}) {
|
trackProperty(contractInstance, propName, methodArgs = [], callArgs = {}) {
|
||||||
const sub = new ReplaySubject();
|
const subjectHash = hash({address: contractInstance.options.address, networkId: this.networkId, propName, methodArgs, callArgs});
|
||||||
|
|
||||||
|
if(this.subjects[subjectHash]) return this.subjects[subjectHash];
|
||||||
|
|
||||||
|
const subject = new Subject();
|
||||||
|
|
||||||
if (!Array.isArray(methodArgs)) {
|
if (!Array.isArray(methodArgs)) {
|
||||||
methodArgs = [methodArgs]
|
methodArgs = [methodArgs]
|
||||||
}
|
}
|
||||||
|
|
||||||
const method = contractInstance.methods[propName].apply(contractInstance.methods[propName], methodArgs)
|
const method = contractInstance.methods[propName].apply(contractInstance.methods[propName], methodArgs);
|
||||||
|
|
||||||
const callContractMethod = () => {
|
const callContractMethod = () => {
|
||||||
method.call.apply(method.call, [callArgs, (err, result) => {
|
method.call.apply(method.call, [callArgs, (err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
sub.error(err);
|
subject.error(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sub.next(result);
|
subject.next(result);
|
||||||
}]);
|
}]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -232,7 +244,7 @@ this.blockTimeObservable = null;
|
||||||
|
|
||||||
this.callables.push(callContractMethod);
|
this.callables.push(callContractMethod);
|
||||||
|
|
||||||
let returnSub = sub.pipe(distinctUntilChanged((a, b) => equal(a, b)));
|
const returnSub = subject.pipe(distinctUntilChanged((a, b) => equal(a, b)));
|
||||||
|
|
||||||
returnSub.map = (prop) => {
|
returnSub.map = (prop) => {
|
||||||
return returnSub.pipe(map((x) => {
|
return returnSub.pipe(map((x) => {
|
||||||
|
@ -249,16 +261,23 @@ this.blockTimeObservable = null;
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.subjects[subjectHash] = returnSub;
|
||||||
|
|
||||||
return returnSub;
|
return returnSub;
|
||||||
}
|
}
|
||||||
|
|
||||||
_addDistinctCallable(trackAttribute, cbBuilder, subject, subjectArg = undefined) {
|
_addDistinctCallable(trackAttribute, cbBuilder, subject, subjectArg = undefined) {
|
||||||
if(this[trackAttribute]) return this[trackAttribute].pipe(distinctUntilChanged((a, b) => equal(a, b)));
|
if(this.subjects[trackAttribute]) return this.subjects[trackAttribute];
|
||||||
this[trackAttribute] = new subject(subjectArg);
|
|
||||||
const cb = cbBuilder(this[trackAttribute]);
|
const sub = new subject(subjectArg);
|
||||||
|
|
||||||
|
const cb = cbBuilder(sub);
|
||||||
cb();
|
cb();
|
||||||
this.callables.push(cb);
|
this.callables.push(cb);
|
||||||
return this[trackAttribute].pipe(distinctUntilChanged((a, b) => equal(a, b)));
|
|
||||||
|
this.subjects[trackAttribute] = sub.pipe(distinctUntilChanged((a, b) => equal(a, b)));
|
||||||
|
|
||||||
|
return this.subjects[trackAttribute];
|
||||||
}
|
}
|
||||||
|
|
||||||
trackBlock() {
|
trackBlock() {
|
||||||
|
|
Loading…
Reference in New Issue