mirror of https://github.com/waku-org/js-waku.git
feat: fix peer renewal, change Filter keep alive (#2065)
* move util, create stream manager folder * change default keep alive, improve peer renewal * address nit
This commit is contained in:
parent
09a81302c1
commit
00635b7afe
|
@ -22,6 +22,6 @@ export { waitForRemotePeer } from "./lib/wait_for_remote_peer.js";
|
||||||
export { ConnectionManager } from "./lib/connection_manager.js";
|
export { ConnectionManager } from "./lib/connection_manager.js";
|
||||||
|
|
||||||
export { KeepAliveManager } from "./lib/keep_alive_manager.js";
|
export { KeepAliveManager } from "./lib/keep_alive_manager.js";
|
||||||
export { StreamManager } from "./lib/stream_manager.js";
|
export { StreamManager } from "./lib/stream_manager/index.js";
|
||||||
|
|
||||||
export { MetadataCodec, wakuMetadata } from "./lib/metadata/index.js";
|
export { MetadataCodec, wakuMetadata } from "./lib/metadata/index.js";
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
} from "@waku/utils/libp2p";
|
} from "@waku/utils/libp2p";
|
||||||
|
|
||||||
import { filterPeersByDiscovery } from "./filterPeers.js";
|
import { filterPeersByDiscovery } from "./filterPeers.js";
|
||||||
import { StreamManager } from "./stream_manager.js";
|
import { StreamManager } from "./stream_manager/index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class with predefined helpers, to be used as a base to implement Waku
|
* A class with predefined helpers, to be used as a base to implement Waku
|
||||||
|
@ -47,6 +47,7 @@ export class BaseProtocol implements IBaseProtocolCore {
|
||||||
this.addLibp2pEventListener
|
this.addLibp2pEventListener
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getStream(peer: Peer): Promise<Stream> {
|
protected async getStream(peer: Peer): Promise<Stream> {
|
||||||
return this.streamManager.getStream(peer);
|
return this.streamManager.getStream(peer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ export class ConnectionManager
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(): void {
|
public stop(): void {
|
||||||
this.keepAliveManager.stopAll();
|
this.keepAliveManager.stopAll();
|
||||||
this.libp2p.removeEventListener(
|
this.libp2p.removeEventListener(
|
||||||
"peer:connect",
|
"peer:connect",
|
||||||
|
@ -105,7 +105,7 @@ export class ConnectionManager
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async dropConnection(peerId: PeerId): Promise<void> {
|
public async dropConnection(peerId: PeerId): Promise<void> {
|
||||||
try {
|
try {
|
||||||
this.keepAliveManager.stop(peerId);
|
this.keepAliveManager.stop(peerId);
|
||||||
await this.libp2p.hangUp(peerId);
|
await this.libp2p.hangUp(peerId);
|
||||||
|
@ -187,7 +187,11 @@ export class ConnectionManager
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
this.keepAliveManager = new KeepAliveManager(keepAliveOptions, relay);
|
this.keepAliveManager = new KeepAliveManager({
|
||||||
|
relay,
|
||||||
|
libp2p,
|
||||||
|
options: keepAliveOptions
|
||||||
|
});
|
||||||
|
|
||||||
this.run()
|
this.run()
|
||||||
.then(() => log.info(`Connection Manager is now running`))
|
.then(() => log.info(`Connection Manager is now running`))
|
||||||
|
@ -250,6 +254,7 @@ export class ConnectionManager
|
||||||
this.dialAttemptsForPeer.set(peerId.toString(), -1);
|
this.dialAttemptsForPeer.set(peerId.toString(), -1);
|
||||||
|
|
||||||
// Dialing succeeded, break the loop
|
// Dialing succeeded, break the loop
|
||||||
|
this.keepAliveManager.start(peerId);
|
||||||
break;
|
break;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AggregateError) {
|
if (error instanceof AggregateError) {
|
||||||
|
@ -356,7 +361,7 @@ export class ConnectionManager
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async attemptDial(peerId: PeerId): Promise<void> {
|
public async attemptDial(peerId: PeerId): Promise<void> {
|
||||||
if (!(await this.shouldDialPeer(peerId))) return;
|
if (!(await this.shouldDialPeer(peerId))) return;
|
||||||
|
|
||||||
if (this.currentActiveParallelDialCount >= this.options.maxParallelDials) {
|
if (this.currentActiveParallelDialCount >= this.options.maxParallelDials) {
|
||||||
|
@ -364,9 +369,7 @@ export class ConnectionManager
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dialPeer(peerId).catch((err) => {
|
await this.dialPeer(peerId);
|
||||||
log.error(`Error dialing peer ${peerId.toString()} : ${err}`);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onEventHandlers = {
|
private onEventHandlers = {
|
||||||
|
@ -389,11 +392,7 @@ export class ConnectionManager
|
||||||
|
|
||||||
const peerId = evt.detail;
|
const peerId = evt.detail;
|
||||||
|
|
||||||
this.keepAliveManager.start(
|
this.keepAliveManager.start(peerId);
|
||||||
peerId,
|
|
||||||
this.libp2p.services.ping,
|
|
||||||
this.libp2p.peerStore
|
|
||||||
);
|
|
||||||
|
|
||||||
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(
|
const isBootstrap = (await this.getTagNamesForPeer(peerId)).includes(
|
||||||
Tags.BOOTSTRAP
|
Tags.BOOTSTRAP
|
||||||
|
@ -449,38 +448,40 @@ export class ConnectionManager
|
||||||
* @returns true if the peer should be dialed, false otherwise
|
* @returns true if the peer should be dialed, false otherwise
|
||||||
*/
|
*/
|
||||||
private async shouldDialPeer(peerId: PeerId): Promise<boolean> {
|
private async shouldDialPeer(peerId: PeerId): Promise<boolean> {
|
||||||
// if we're already connected to the peer, don't dial
|
|
||||||
const isConnected = this.libp2p.getConnections(peerId).length > 0;
|
const isConnected = this.libp2p.getConnections(peerId).length > 0;
|
||||||
if (isConnected) {
|
if (isConnected) {
|
||||||
log.warn(`Already connected to peer ${peerId.toString()}. Not dialing.`);
|
log.warn(`Already connected to peer ${peerId.toString()}. Not dialing.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the peer is not part of any of the configured pubsub topics, don't dial
|
const isSameShard = await this.isPeerTopicConfigured(peerId);
|
||||||
if (!(await this.isPeerTopicConfigured(peerId))) {
|
if (!isSameShard) {
|
||||||
const shardInfo = await this.getPeerShardInfo(
|
const shardInfo = await this.getPeerShardInfo(
|
||||||
peerId,
|
peerId,
|
||||||
this.libp2p.peerStore
|
this.libp2p.peerStore
|
||||||
);
|
);
|
||||||
|
|
||||||
log.warn(
|
log.warn(
|
||||||
`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${
|
`Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${
|
||||||
this.configuredPubsubTopics
|
this.configuredPubsubTopics
|
||||||
}).
|
}).
|
||||||
Not dialing.`
|
Not dialing.`
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the peer is not dialable based on bootstrap status, don't dial
|
const isPreferredBasedOnBootstrap =
|
||||||
if (!(await this.isPeerDialableBasedOnBootstrapStatus(peerId))) {
|
await this.isPeerDialableBasedOnBootstrapStatus(peerId);
|
||||||
|
if (!isPreferredBasedOnBootstrap) {
|
||||||
log.warn(
|
log.warn(
|
||||||
`Peer ${peerId.toString()} is not dialable based on bootstrap status. Not dialing.`
|
`Peer ${peerId.toString()} is not dialable based on bootstrap status. Not dialing.`
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the peer is already already has an active dial attempt, or has been dialed before, don't dial it
|
const hasBeenDialed = this.dialAttemptsForPeer.has(peerId.toString());
|
||||||
if (this.dialAttemptsForPeer.has(peerId.toString())) {
|
if (hasBeenDialed) {
|
||||||
log.warn(
|
log.warn(
|
||||||
`Peer ${peerId.toString()} has already been attempted dial before, or already has a dial attempt in progress, skipping dial`
|
`Peer ${peerId.toString()} has already been attempted dial before, or already has a dial attempt in progress, skipping dial`
|
||||||
);
|
);
|
||||||
|
@ -502,19 +503,17 @@ export class ConnectionManager
|
||||||
|
|
||||||
const isBootstrap = tagNames.some((tagName) => tagName === Tags.BOOTSTRAP);
|
const isBootstrap = tagNames.some((tagName) => tagName === Tags.BOOTSTRAP);
|
||||||
|
|
||||||
if (isBootstrap) {
|
if (!isBootstrap) {
|
||||||
const currentBootstrapConnections = this.libp2p
|
|
||||||
.getConnections()
|
|
||||||
.filter((conn) => {
|
|
||||||
return conn.tags.find((name) => name === Tags.BOOTSTRAP);
|
|
||||||
}).length;
|
|
||||||
if (currentBootstrapConnections < this.options.maxBootstrapPeersAllowed)
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
const currentBootstrapConnections = this.libp2p
|
||||||
|
.getConnections()
|
||||||
|
.filter((conn) => {
|
||||||
|
return conn.tags.find((name) => name === Tags.BOOTSTRAP);
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
return currentBootstrapConnections < this.options.maxBootstrapPeersAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async dispatchDiscoveryEvent(peerId: PeerId): Promise<void> {
|
private async dispatchDiscoveryEvent(peerId: PeerId): Promise<void> {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { PeerId, PeerStore } from "@libp2p/interface";
|
import type { PeerId } from "@libp2p/interface";
|
||||||
import type { PingService } from "@libp2p/ping";
|
import type { IRelay, Libp2p, PeerIdStr } from "@waku/interfaces";
|
||||||
import type { IRelay, PeerIdStr } from "@waku/interfaces";
|
|
||||||
import type { KeepAliveOptions } from "@waku/interfaces";
|
import type { KeepAliveOptions } from "@waku/interfaces";
|
||||||
import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils";
|
import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils";
|
||||||
import { utf8ToBytes } from "@waku/utils/bytes";
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
||||||
|
@ -10,24 +9,30 @@ import { createEncoder } from "./message/version_0.js";
|
||||||
export const RelayPingContentTopic = "/relay-ping/1/ping/null";
|
export const RelayPingContentTopic = "/relay-ping/1/ping/null";
|
||||||
const log = new Logger("keep-alive");
|
const log = new Logger("keep-alive");
|
||||||
|
|
||||||
export class KeepAliveManager {
|
type CreateKeepAliveManagerOptions = {
|
||||||
private pingKeepAliveTimers: Map<string, ReturnType<typeof setInterval>>;
|
options: KeepAliveOptions;
|
||||||
private relayKeepAliveTimers: Map<PeerId, ReturnType<typeof setInterval>[]>;
|
libp2p: Libp2p;
|
||||||
private options: KeepAliveOptions;
|
relay?: IRelay;
|
||||||
private relay?: IRelay;
|
};
|
||||||
|
|
||||||
constructor(options: KeepAliveOptions, relay?: IRelay) {
|
export class KeepAliveManager {
|
||||||
this.pingKeepAliveTimers = new Map();
|
private readonly relay?: IRelay;
|
||||||
this.relayKeepAliveTimers = new Map();
|
private readonly libp2p: Libp2p;
|
||||||
|
|
||||||
|
private readonly options: KeepAliveOptions;
|
||||||
|
|
||||||
|
private pingKeepAliveTimers: Map<string, ReturnType<typeof setInterval>> =
|
||||||
|
new Map();
|
||||||
|
private relayKeepAliveTimers: Map<PeerId, ReturnType<typeof setInterval>[]> =
|
||||||
|
new Map();
|
||||||
|
|
||||||
|
constructor({ options, relay, libp2p }: CreateKeepAliveManagerOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.relay = relay;
|
this.relay = relay;
|
||||||
|
this.libp2p = libp2p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(
|
public start(peerId: PeerId): void {
|
||||||
peerId: PeerId,
|
|
||||||
libp2pPing: PingService,
|
|
||||||
peerStore: PeerStore
|
|
||||||
): void {
|
|
||||||
// Just in case a timer already exists for this peer
|
// Just in case a timer already exists for this peer
|
||||||
this.stop(peerId);
|
this.stop(peerId);
|
||||||
|
|
||||||
|
@ -46,7 +51,7 @@ export class KeepAliveManager {
|
||||||
// ping the peer for keep alive
|
// ping the peer for keep alive
|
||||||
// also update the peer store with the latency
|
// also update the peer store with the latency
|
||||||
try {
|
try {
|
||||||
ping = await libp2pPing.ping(peerId);
|
ping = await this.libp2p.services.ping.ping(peerId);
|
||||||
log.info(`Ping succeeded (${peerIdStr})`, ping);
|
log.info(`Ping succeeded (${peerIdStr})`, ping);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Ping failed for peer (${peerIdStr}).
|
log.error(`Ping failed for peer (${peerIdStr}).
|
||||||
|
@ -56,7 +61,7 @@ export class KeepAliveManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await peerStore.merge(peerId, {
|
await this.libp2p.peerStore.merge(peerId, {
|
||||||
metadata: {
|
metadata: {
|
||||||
ping: utf8ToBytes(ping.toString())
|
ping: utf8ToBytes(ping.toString())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export { StreamManager } from "./stream_manager.js";
|
|
@ -2,7 +2,8 @@ import type { PeerUpdate, Stream } from "@libp2p/interface";
|
||||||
import type { Peer, PeerId } from "@libp2p/interface";
|
import type { Peer, PeerId } from "@libp2p/interface";
|
||||||
import { Libp2p } from "@waku/interfaces";
|
import { Libp2p } from "@waku/interfaces";
|
||||||
import { Logger } from "@waku/utils";
|
import { Logger } from "@waku/utils";
|
||||||
import { selectConnection } from "@waku/utils/libp2p";
|
|
||||||
|
import { selectConnection } from "./utils.js";
|
||||||
|
|
||||||
const CONNECTION_TIMEOUT = 5_000;
|
const CONNECTION_TIMEOUT = 5_000;
|
||||||
const RETRY_BACKOFF_BASE = 1_000;
|
const RETRY_BACKOFF_BASE = 1_000;
|
|
@ -0,0 +1,22 @@
|
||||||
|
import type { Connection } from "@libp2p/interface";
|
||||||
|
|
||||||
|
export function selectConnection(
|
||||||
|
connections: Connection[]
|
||||||
|
): Connection | undefined {
|
||||||
|
if (!connections.length) return;
|
||||||
|
if (connections.length === 1) return connections[0];
|
||||||
|
|
||||||
|
let latestConnection: Connection | undefined;
|
||||||
|
|
||||||
|
connections.forEach((connection) => {
|
||||||
|
if (connection.status === "open") {
|
||||||
|
if (!latestConnection) {
|
||||||
|
latestConnection = connection;
|
||||||
|
} else if (connection.timeline.open > latestConnection.timeline.open) {
|
||||||
|
latestConnection = connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return latestConnection;
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ interface Options {
|
||||||
maintainPeersInterval?: number;
|
maintainPeersInterval?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RENEW_TIME_LOCK_DURATION = 30 * 1000;
|
||||||
const DEFAULT_NUM_PEERS_TO_USE = 3;
|
const DEFAULT_NUM_PEERS_TO_USE = 3;
|
||||||
const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000;
|
const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000;
|
||||||
|
|
||||||
|
@ -21,6 +22,9 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
log: Logger;
|
log: Logger;
|
||||||
|
|
||||||
private maintainPeersLock = false;
|
private maintainPeersLock = false;
|
||||||
|
private readonly renewPeersLocker = new RenewPeerLocker(
|
||||||
|
RENEW_TIME_LOCK_DURATION
|
||||||
|
);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected core: BaseProtocol,
|
protected core: BaseProtocol,
|
||||||
|
@ -46,11 +50,6 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
*/
|
*/
|
||||||
public async renewPeer(peerToDisconnect: PeerId): Promise<Peer> {
|
public async renewPeer(peerToDisconnect: PeerId): Promise<Peer> {
|
||||||
this.log.info(`Renewing peer ${peerToDisconnect}`);
|
this.log.info(`Renewing peer ${peerToDisconnect}`);
|
||||||
await this.connectionManager.dropConnection(peerToDisconnect);
|
|
||||||
this.peers = this.peers.filter((peer) => peer.id !== peerToDisconnect);
|
|
||||||
this.log.info(
|
|
||||||
`Peer ${peerToDisconnect} disconnected and removed from the peer list`
|
|
||||||
);
|
|
||||||
|
|
||||||
const peer = (await this.findAndAddPeers(1))[0];
|
const peer = (await this.findAndAddPeers(1))[0];
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
|
@ -59,6 +58,14 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.connectionManager.dropConnection(peerToDisconnect);
|
||||||
|
this.peers = this.peers.filter((peer) => !peer.id.equals(peerToDisconnect));
|
||||||
|
this.log.info(
|
||||||
|
`Peer ${peerToDisconnect} disconnected and removed from the peer list`
|
||||||
|
);
|
||||||
|
|
||||||
|
this.renewPeersLocker.lock(peerToDisconnect);
|
||||||
|
|
||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +170,7 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
this.log.info(
|
this.log.info(
|
||||||
`Peer maintenance completed, current count: ${this.peers.length}`
|
`Peer maintenance completed, current count: ${this.peers.length}`
|
||||||
);
|
);
|
||||||
|
this.renewPeersLocker.cleanUnlocked();
|
||||||
} finally {
|
} finally {
|
||||||
this.maintainPeersLock = false;
|
this.maintainPeersLock = false;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +185,12 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
this.log.info(`Finding and adding ${numPeers} new peers`);
|
this.log.info(`Finding and adding ${numPeers} new peers`);
|
||||||
try {
|
try {
|
||||||
const additionalPeers = await this.findAdditionalPeers(numPeers);
|
const additionalPeers = await this.findAdditionalPeers(numPeers);
|
||||||
|
const dials = additionalPeers.map((peer) =>
|
||||||
|
this.connectionManager.attemptDial(peer.id)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(dials);
|
||||||
|
|
||||||
this.peers = [...this.peers, ...additionalPeers];
|
this.peers = [...this.peers, ...additionalPeers];
|
||||||
this.log.info(
|
this.log.info(
|
||||||
`Added ${additionalPeers.length} new peers, total peers: ${this.peers.length}`
|
`Added ${additionalPeers.length} new peers, total peers: ${this.peers.length}`
|
||||||
|
@ -198,22 +212,19 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
private async findAdditionalPeers(numPeers: number): Promise<Peer[]> {
|
private async findAdditionalPeers(numPeers: number): Promise<Peer[]> {
|
||||||
this.log.info(`Finding ${numPeers} additional peers`);
|
this.log.info(`Finding ${numPeers} additional peers`);
|
||||||
try {
|
try {
|
||||||
let newPeers = await this.core.getPeers({
|
let newPeers = await this.core.allPeers();
|
||||||
maxBootstrapPeers: 0,
|
|
||||||
numPeers: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
if (newPeers.length === 0) {
|
if (newPeers.length === 0) {
|
||||||
this.log.warn("No new peers found, trying with bootstrap peers");
|
this.log.warn("No new peers found.");
|
||||||
newPeers = await this.core.getPeers({
|
|
||||||
maxBootstrapPeers: numPeers,
|
|
||||||
numPeers: 0
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newPeers = newPeers
|
newPeers = newPeers
|
||||||
.filter((peer) => this.peers.some((p) => p.id === peer.id) === false)
|
.filter(
|
||||||
|
(peer) => this.peers.some((p) => p.id.equals(peer.id)) === false
|
||||||
|
)
|
||||||
|
.filter((peer) => !this.renewPeersLocker.isLocked(peer.id))
|
||||||
.slice(0, numPeers);
|
.slice(0, numPeers);
|
||||||
|
|
||||||
return newPeers;
|
return newPeers;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.error("Error finding additional peers:", error);
|
this.log.error("Error finding additional peers:", error);
|
||||||
|
@ -221,3 +232,35 @@ export class BaseProtocolSDK implements IBaseProtocolSDK {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RenewPeerLocker {
|
||||||
|
private readonly peers: Map<string, number> = new Map();
|
||||||
|
|
||||||
|
constructor(private lockDuration: number) {}
|
||||||
|
|
||||||
|
public lock(id: PeerId): void {
|
||||||
|
this.peers.set(id.toString(), Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public isLocked(id: PeerId): boolean {
|
||||||
|
const time = this.peers.get(id.toString());
|
||||||
|
|
||||||
|
if (time && !this.isTimeUnlocked(time)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public cleanUnlocked(): void {
|
||||||
|
Object.entries(this.peers).forEach(([id, lock]) => {
|
||||||
|
if (this.isTimeUnlocked(lock)) {
|
||||||
|
this.peers.delete(id.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private isTimeUnlocked(time: number): boolean {
|
||||||
|
return Date.now() - time >= this.lockDuration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,11 +41,11 @@ type SubscriptionCallback<T extends IDecodedMessage> = {
|
||||||
|
|
||||||
const log = new Logger("sdk:filter");
|
const log = new Logger("sdk:filter");
|
||||||
|
|
||||||
const MINUTE = 60 * 1000;
|
|
||||||
const DEFAULT_MAX_PINGS = 3;
|
const DEFAULT_MAX_PINGS = 3;
|
||||||
|
const DEFAULT_KEEP_ALIVE = 30 * 1000;
|
||||||
|
|
||||||
const DEFAULT_SUBSCRIBE_OPTIONS = {
|
const DEFAULT_SUBSCRIBE_OPTIONS = {
|
||||||
keepAlive: MINUTE
|
keepAlive: DEFAULT_KEEP_ALIVE
|
||||||
};
|
};
|
||||||
export class SubscriptionManager implements ISubscriptionSDK {
|
export class SubscriptionManager implements ISubscriptionSDK {
|
||||||
private readonly pubsubTopic: PubsubTopic;
|
private readonly pubsubTopic: PubsubTopic;
|
||||||
|
|
|
@ -105,24 +105,3 @@ export async function getConnectedPeersForProtocolAndShard(
|
||||||
const peersWithNulls = await Promise.all(peerPromises);
|
const peersWithNulls = await Promise.all(peerPromises);
|
||||||
return peersWithNulls.filter((peer): peer is Peer => peer !== null);
|
return peersWithNulls.filter((peer): peer is Peer => peer !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectConnection(
|
|
||||||
connections: Connection[]
|
|
||||||
): Connection | undefined {
|
|
||||||
if (!connections.length) return;
|
|
||||||
if (connections.length === 1) return connections[0];
|
|
||||||
|
|
||||||
let latestConnection: Connection | undefined;
|
|
||||||
|
|
||||||
connections.forEach((connection) => {
|
|
||||||
if (connection.status === "open") {
|
|
||||||
if (!latestConnection) {
|
|
||||||
latestConnection = connection;
|
|
||||||
} else if (connection.timeline.open > latestConnection.timeline.open) {
|
|
||||||
latestConnection = connection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return latestConnection;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue