ethers.js/lib.esm/providers/subscriber-polling.js

231 lines
6.1 KiB
JavaScript
Raw Normal View History

2022-11-09 10:57:02 +03:00
import { assert, isHexString } from "../utils/index.js";
2022-09-05 23:57:11 +03:00
function copy(obj) {
return JSON.parse(JSON.stringify(obj));
}
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export function getPollingSubscriber(provider, event) {
if (event === "block") {
return new PollingBlockSubscriber(provider);
}
if (isHexString(event, 32)) {
return new PollingTransactionSubscriber(provider, event);
}
2022-11-09 10:57:02 +03:00
assert(false, "unsupported polling event", "UNSUPPORTED_OPERATION", {
2022-09-05 23:57:11 +03:00
operation: "getPollingSubscriber", info: { event }
});
}
// @TODO: refactor this
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export class PollingBlockSubscriber {
#provider;
#poller;
#interval;
// The most recent block we have scanned for events. The value -2
// indicates we still need to fetch an initial block number
#blockNumber;
constructor(provider) {
this.#provider = provider;
this.#poller = null;
this.#interval = 4000;
this.#blockNumber = -2;
}
get pollingInterval() { return this.#interval; }
set pollingInterval(value) { this.#interval = value; }
async #poll() {
const blockNumber = await this.#provider.getBlockNumber();
if (this.#blockNumber === -2) {
this.#blockNumber = blockNumber;
return;
}
// @TODO: Put a cap on the maximum number of events per loop?
if (blockNumber !== this.#blockNumber) {
for (let b = this.#blockNumber + 1; b <= blockNumber; b++) {
2023-02-02 12:23:07 +03:00
// We have been stopped
if (this.#poller == null) {
return;
}
await this.#provider.emit("block", b);
2022-09-05 23:57:11 +03:00
}
this.#blockNumber = blockNumber;
}
2023-02-02 12:23:07 +03:00
// We have been stopped
if (this.#poller == null) {
return;
}
2022-09-05 23:57:11 +03:00
this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
}
start() {
if (this.#poller) {
2023-02-04 11:26:34 +03:00
return;
2022-09-05 23:57:11 +03:00
}
this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
2023-02-02 12:05:47 +03:00
this.#poll();
2022-09-05 23:57:11 +03:00
}
stop() {
if (!this.#poller) {
2023-02-04 11:26:34 +03:00
return;
2022-09-05 23:57:11 +03:00
}
this.#provider._clearTimeout(this.#poller);
this.#poller = null;
}
pause(dropWhilePaused) {
this.stop();
if (dropWhilePaused) {
this.#blockNumber = -2;
}
}
resume() {
this.start();
}
}
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export class OnBlockSubscriber {
#provider;
#poll;
2023-02-04 11:26:34 +03:00
#running;
2022-09-05 23:57:11 +03:00
constructor(provider) {
this.#provider = provider;
2023-02-04 11:26:34 +03:00
this.#running = false;
2022-09-05 23:57:11 +03:00
this.#poll = (blockNumber) => {
this._poll(blockNumber, this.#provider);
};
}
async _poll(blockNumber, provider) {
throw new Error("sub-classes must override this");
}
start() {
2023-02-04 11:26:34 +03:00
if (this.#running) {
return;
}
this.#running = true;
2022-09-05 23:57:11 +03:00
this.#poll(-2);
this.#provider.on("block", this.#poll);
}
stop() {
2023-02-04 11:26:34 +03:00
if (!this.#running) {
return;
}
this.#running = false;
2022-09-05 23:57:11 +03:00
this.#provider.off("block", this.#poll);
}
pause(dropWhilePaused) { this.stop(); }
resume() { this.start(); }
}
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export class PollingOrphanSubscriber extends OnBlockSubscriber {
#filter;
constructor(provider, filter) {
super(provider);
this.#filter = copy(filter);
}
async _poll(blockNumber, provider) {
throw new Error("@TODO");
console.log(this.#filter);
}
}
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export class PollingTransactionSubscriber extends OnBlockSubscriber {
#hash;
constructor(provider, hash) {
super(provider);
this.#hash = hash;
}
async _poll(blockNumber, provider) {
const tx = await provider.getTransactionReceipt(this.#hash);
if (tx) {
provider.emit(this.#hash, tx);
}
}
}
2022-11-30 23:44:23 +03:00
/**
* @TODO
*
* @_docloc: api/providers/abstract-provider
*/
2022-09-05 23:57:11 +03:00
export class PollingEventSubscriber {
#provider;
#filter;
#poller;
2023-02-04 11:26:34 +03:00
#running;
2022-09-05 23:57:11 +03:00
// The most recent block we have scanned for events. The value -2
// indicates we still need to fetch an initial block number
#blockNumber;
constructor(provider, filter) {
this.#provider = provider;
this.#filter = copy(filter);
this.#poller = this.#poll.bind(this);
2023-02-04 11:26:34 +03:00
this.#running = false;
2022-09-05 23:57:11 +03:00
this.#blockNumber = -2;
}
async #poll(blockNumber) {
// The initial block hasn't been determined yet
if (this.#blockNumber === -2) {
return;
}
const filter = copy(this.#filter);
filter.fromBlock = this.#blockNumber + 1;
filter.toBlock = blockNumber;
const logs = await this.#provider.getLogs(filter);
// No logs could just mean the node has not indexed them yet,
// so we keep a sliding window of 60 blocks to keep scanning
if (logs.length === 0) {
if (this.#blockNumber < blockNumber - 60) {
this.#blockNumber = blockNumber - 60;
}
return;
}
this.#blockNumber = blockNumber;
for (const log of logs) {
this.#provider.emit(this.#filter, log);
}
}
start() {
2023-02-04 11:26:34 +03:00
if (this.#running) {
return;
}
this.#running = true;
2022-09-05 23:57:11 +03:00
if (this.#blockNumber === -2) {
this.#provider.getBlockNumber().then((blockNumber) => {
this.#blockNumber = blockNumber;
});
}
this.#provider.on("block", this.#poller);
}
stop() {
2023-02-04 11:26:34 +03:00
if (!this.#running) {
return;
}
this.#running = false;
2022-09-05 23:57:11 +03:00
this.#provider.off("block", this.#poller);
}
pause(dropWhilePaused) {
this.stop();
if (dropWhilePaused) {
this.#blockNumber = -2;
}
}
resume() {
this.start();
}
}
//# sourceMappingURL=subscriber-polling.js.map