All files / lib/gossip GossipSyncWatcher.ts

100% Statements 30/30
100% Branches 6/6
100% Functions 11/11
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103          1x 1x 1x 1x 1x               1x 12x                   12x 12x 12x   12x             1x             1x               5x 5x 5x 5x 5x                       5x 4x 4x 4x               2x 1x 1x   2x       5x         9x       4x 4x      
import { ILogger } from "@node-lightning/logger";
import { ChannelAnnouncementMessage } from "../messages/ChannelAnnouncementMessage";
import { ChannelUpdateMessage } from "../messages/ChannelUpdateMessage";
import { NodeAnnouncementMessage } from "../messages/NodeAnnouncementMessage";
 
export enum GossipSyncWatcherState {
    Idle,
    Watching,
    Complete,
    Canceled,
}
 
/**
 * GossipSyncWatcher monitors the progress of a GossipSync operation for the
 * completion of the synchronization and signals once the sync has completed
 * or timed out.
 */
export class GossipSyncWatcher {
    public completeAfterMs = 5000;
 
    private _state: GossipSyncWatcherState;
    private _timeoutHandle: NodeJS.Timeout;
    private _messageCounter: number;
 
    private _resolve: (value: void) => void;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    private _reject: (reason: any) => void;
 
    constructor(readonly logger: ILogger) {
        this._state = GossipSyncWatcherState.Idle;
        this._messageCounter = 0;
        // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
        this._onTimeout = this._onTimeout.bind(this);
    }
 
    /**
     * Gets the state of the Watcher: IDLE, WATCHING, COMPLETE, FAILED
     */
    public get state(): GossipSyncWatcherState {
        return this._state;
    }
 
    /**
     * Gets the number of messages that have been seen while watching
     */
    public get messageCounter(): number {
        return this._messageCounter;
    }
 
    /**
     * Watches gossip traffic until a completion event occurs or watching is
     * cancelled.
     */
    public watch(): Promise<void> {
        return new Promise((resolve, reject) => {
            this._state = GossipSyncWatcherState.Watching;
            this._setTimeout();
            this._resolve = resolve;
            this._reject = reject;
        });
    }
 
    /**
     * Process a message and debounce when it is a gossip message
     * @param msg
     */
    public onGossipMessage(
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        msg: ChannelAnnouncementMessage | ChannelUpdateMessage | NodeAnnouncementMessage,
    ): void {
        if (this._state === GossipSyncWatcherState.Watching) {
            this._messageCounter += 1;
            this._clearTimeout();
            this._setTimeout();
        }
    }
 
    /**
     * Cancels watching and sends a failure signal.
     */
    public cancel(): void {
        if (this._state === GossipSyncWatcherState.Watching) {
            this._clearTimeout();
            this._resolve();
        }
        this._state = GossipSyncWatcherState.Canceled;
    }
 
    private _clearTimeout() {
        clearTimeout(this._timeoutHandle);
    }
 
    private _setTimeout() {
        // eslint-disable-next-line @typescript-eslint/unbound-method
        this._timeoutHandle = setTimeout(this._onTimeout, this.completeAfterMs);
    }
 
    private _onTimeout() {
        this._state = GossipSyncWatcherState.Complete;
        this._resolve();
    }
}