@waku/core
Version:
TypeScript implementation of the Waku v2 protocol
135 lines • 4.86 kB
JavaScript
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