UNPKG

@waku/core

Version:

TypeScript implementation of the Waku v2 protocol

135 lines 4.86 kB
import { Logger } from "@waku/utils"; const log = new Logger("dialer"); export class Dialer { libp2p; shardReader; options; dialingQueue = []; dialHistory = new Map(); failedDials = new Map(); dialingInterval = null; isProcessing = false; isImmediateDialing = false; constructor(options) { this.libp2p = options.libp2p; this.shardReader = options.shardReader; this.options = options.options; } start() { log.info("Starting dialer"); if (!this.dialingInterval) { this.dialingInterval = setInterval(() => { void this.processQueue(); }, 500); } this.dialHistory.clear(); this.failedDials.clear(); } stop() { log.info("Stopping dialer"); if (this.dialingInterval) { clearInterval(this.dialingInterval); this.dialingInterval = null; } this.dialHistory.clear(); this.failedDials.clear(); } async dial(peerId) { const shouldSkip = await this.shouldSkipPeer(peerId); if (shouldSkip) { log.info(`Skipping peer: ${peerId}`); return; } const isEmptyQueue = this.dialingQueue.length === 0; const isNotDialing = !this.isProcessing && !this.isImmediateDialing; // If queue is empty and we're not currently processing, dial immediately if (isEmptyQueue && isNotDialing) { this.isImmediateDialing = true; log.info("Dialed peer immediately"); await this.dialPeer(peerId); this.isImmediateDialing = false; log.info("Released immediate dial lock"); } else { this.dialingQueue.push(peerId); log.info(`Added peer to dialing queue, queue size: ${this.dialingQueue.length}`); } } async processQueue() { if (this.dialingQueue.length === 0 || this.isProcessing) { return; } this.isProcessing = true; try { const peersToDial = this.dialingQueue.slice(0, this.options.maxDialingPeers); this.dialingQueue = this.dialingQueue.slice(peersToDial.length); log.info(`Processing dial queue: dialing ${peersToDial.length} peers, ${this.dialingQueue.length} remaining in queue`); await Promise.all(peersToDial.map((peerId) => this.dialPeer(peerId))); } finally { this.isProcessing = false; } } async dialPeer(peerId) { try { log.info(`Dialing peer from queue: ${peerId}`); await this.libp2p.dial(peerId); this.dialHistory.set(peerId.toString(), Date.now()); this.failedDials.delete(peerId.toString()); log.info(`Successfully dialed peer from queue: ${peerId}`); } catch (error) { log.error(`Error dialing peer ${peerId}`, error); this.failedDials.set(peerId.toString(), Date.now()); } } async shouldSkipPeer(peerId) { const hasConnection = this.libp2p.getPeers().some((p) => p.equals(peerId)); if (hasConnection) { log.info(`Skipping peer ${peerId} - already connected`); return true; } if (this.isRecentlyDialed(peerId)) { log.info(`Skipping peer ${peerId} - already dialed in the last 10 seconds`); return true; } if (this.isRecentlyFailed(peerId)) { log.info(`Skipping peer ${peerId} - recently failed to dial`); return true; } try { const hasShardInfo = await this.shardReader.hasShardInfo(peerId); if (!hasShardInfo) { log.info(`Skipping peer ${peerId} - no shard info`); return false; } const isOnSameShard = await this.shardReader.isPeerOnNetwork(peerId); if (!isOnSameShard) { log.info(`Skipping peer ${peerId} - not on same shard`); return true; } return false; } catch (error) { log.error(`Error checking shard info for peer ${peerId}`, error); return true; // Skip peer when there's an error } } isRecentlyDialed(peerId) { const lastDialed = this.dialHistory.get(peerId.toString()); if (lastDialed && Date.now() - lastDialed < this.options.dialCooldown * 1000) { return true; } return false; } isRecentlyFailed(peerId) { const lastFailed = this.failedDials.get(peerId.toString()); if (lastFailed && Date.now() - lastFailed < this.options.failedDialCooldown * 1000) { return true; } return false; } } //# sourceMappingURL=dialer.js.map