Fix Subscriber model when removed within emit callback.

This commit is contained in:
Richard Moore 2023-02-04 03:12:04 -05:00
parent 32b1e7827a
commit d0ed91840c
5 changed files with 43 additions and 59 deletions

@ -161,6 +161,8 @@ type Sub = {
nameMap: Map<string, string>
addressableMap: WeakMap<Addressable, string>;
listeners: Array<{ listener: Listener, once: boolean }>;
// @TODO: get rid of this, as it is (and has to be)
// tracked in subscriber
started: boolean;
subscriber: Subscriber;
};

@ -27,15 +27,21 @@ export class BlockConnectionSubscriber implements Subscriber {
#provider: ConnectionRpcProvider;
#blockNumber: number;
#running: boolean;
#filterId: null | number;
constructor(provider: ConnectionRpcProvider) {
this.#provider = provider;
this.#blockNumber = -2;
this.#running = false;
this.#filterId = null;
}
start(): void {
if (this.#running) { return; }
this.#running = true;
this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => {
const blockNumber = getNumber(result.number);
const initial = (this.#blockNumber === -2) ? blockNumber: (this.#blockNumber + 1)
@ -47,6 +53,9 @@ export class BlockConnectionSubscriber implements Subscriber {
}
stop(): void {
if (!this.#running) { return; }
this.#running = false;
if (this.#filterId != null) {
this.#provider._unsubscribe(this.#filterId);
this.#filterId = null;

@ -26,6 +26,8 @@ export class FilterIdSubscriber implements Subscriber {
#filterIdPromise: null | Promise<string>;
#poller: (b: number) => Promise<void>;
#running: boolean;
#network: null | Network;
#hault: boolean;
@ -36,6 +38,8 @@ export class FilterIdSubscriber implements Subscriber {
this.#filterIdPromise = null;
this.#poller = this.#poll.bind(this);
this.#running = false;
this.#network = null;
this.#hault = false;
@ -91,9 +95,17 @@ export class FilterIdSubscriber implements Subscriber {
}
}
start(): void { this.#poll(-2); }
start(): void {
if (this.#running) { return; }
this.#running = true;
this.#poll(-2);
}
stop(): void {
if (!this.#running) { return; }
this.#running = false;
this.#hault = true;
this.#teardown();
this.#provider.off("block", this.#poller);

@ -76,13 +76,13 @@ export class PollingBlockSubscriber implements Subscriber {
}
start(): void {
if (this.#poller) { throw new Error("subscriber already running"); }
if (this.#poller) { return; }
this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval);
this.#poll();
}
stop(): void {
if (!this.#poller) { throw new Error("subscriber not running"); }
if (!this.#poller) { return; }
this.#provider._clearTimeout(this.#poller);
this.#poller = null;
}
@ -105,9 +105,11 @@ export class PollingBlockSubscriber implements Subscriber {
export class OnBlockSubscriber implements Subscriber {
#provider: AbstractProvider;
#poll: (b: number) => void;
#running: boolean;
constructor(provider: AbstractProvider) {
this.#provider = provider;
this.#running = false;
this.#poll = (blockNumber: number) => {
this._poll(blockNumber, this.#provider);
}
@ -118,11 +120,17 @@ export class OnBlockSubscriber implements Subscriber {
}
start(): void {
if (this.#running) { return; }
this.#running = true;
this.#poll(-2);
this.#provider.on("block", this.#poll);
}
stop(): void {
if (!this.#running) { return; }
this.#running = false;
this.#provider.off("block", this.#poll);
}
@ -178,6 +186,8 @@ export class PollingEventSubscriber implements Subscriber {
#filter: EventFilter;
#poller: (b: number) => void;
#running: boolean;
// The most recent block we have scanned for events. The value -2
// indicates we still need to fetch an initial block number
#blockNumber: number;
@ -186,6 +196,7 @@ export class PollingEventSubscriber implements Subscriber {
this.#provider = provider;
this.#filter = copy(filter);
this.#poller = this.#poll.bind(this);
this.#running = false;
this.#blockNumber = -2;
}
@ -215,6 +226,9 @@ export class PollingEventSubscriber implements Subscriber {
}
start(): void {
if (this.#running) { return; }
this.#running = true;
if (this.#blockNumber === -2) {
this.#provider.getBlockNumber().then((blockNumber) => {
this.#blockNumber = blockNumber;
@ -224,6 +238,9 @@ export class PollingEventSubscriber implements Subscriber {
}
stop(): void {
if (!this.#running) { return; }
this.#running = false;
this.#provider.off("block", this.#poller);
}

@ -1,56 +0,0 @@
/*
import { defineProperties } from "@ethersproject/properties";
export type EventCommon = "block" | "debug" | "blockObject";
export type Event = EventCommon | string | { address?: string, topics: Array<string | Array<string>> }
export type EventLike = Event | Array<string>;
export function getTag(eventName: Event): string {
if (typeof(eventName) === "string") { return eventName; }
if (typeof(eventName) === "object") {
return (eventName.address || "*") + (eventName.topics || []).map((topic) => {
if (typeof(topic) === "string") { return topic; }
return topic.join("|");
}).join("&");
}
throw new Error("FOO");
}
export function getEvent(tag: string): Event {
}
let nextId = 1;
export class Subscriber {
readonly id!: number;
readonly tag!: string;
#paused: boolean;
#blockNumber: number;
constructor(tag: string) {
this.#paused = false;
this.#blockNumber = -1;
defineProperties<Subscriber>(this, { id: nextId++, tag });
}
get blockNumber(): number {
return this.#blockNumber;
}
_setBlockNumber(blockNumber: number): void { this.#blockNumber = blockNumber; }
setup(): void { }
teardown(): void { }
isPaused(): boolean { return this.#paused; }
pause(): void { this.#paused = true; }
resume(): void { this.#paused = false; }
resubscribeInfo(): string { return this.tag; }
resubscribe(info: string): boolean { return true; }
}
*/