mirror of
https://github.com/waku-org/js-waku.git
synced 2025-02-05 09:04:19 +00:00
fix: peer renewal connection drop & stream management (#2145)
* fix: peer renewal connection drop * fix stream manager * fix over iteration during stream creation * remove timeout and use only open peers * add logs * refactor code, add tests * debug test * up debug * remove debug, supress check for timestamps * remove only * add more debug * remove debug * remove check for timestamps
This commit is contained in:
parent
3e821591c9
commit
b93134a517
@ -26,6 +26,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"@typescript-eslint/explicit-member-accessibility": "error",
|
"@typescript-eslint/explicit-member-accessibility": "error",
|
||||||
|
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||||
"prettier/prettier": [
|
"prettier/prettier": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
3
package-lock.json
generated
3
package-lock.json
generated
@ -39111,7 +39111,8 @@
|
|||||||
"mocha": "^10.3.0",
|
"mocha": "^10.3.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"rollup": "^4.12.0"
|
"rollup": "^4.12.0",
|
||||||
|
"sinon": "^18.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=20"
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@waku/build-utils": "*",
|
"@waku/build-utils": "*",
|
||||||
"chai": "^4.3.10",
|
"chai": "^4.3.10",
|
||||||
|
"sinon": "^18.0.0",
|
||||||
"cspell": "^8.6.1",
|
"cspell": "^8.6.1",
|
||||||
"fast-check": "^3.19.0",
|
"fast-check": "^3.19.0",
|
||||||
"ignore-loader": "^0.1.2",
|
"ignore-loader": "^0.1.2",
|
||||||
|
161
packages/core/src/lib/stream_manager/stream_manager.spec.ts
Normal file
161
packages/core/src/lib/stream_manager/stream_manager.spec.ts
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import { Connection, Peer, PeerId, Stream } from "@libp2p/interface";
|
||||||
|
import { expect } from "chai";
|
||||||
|
import sinon from "sinon";
|
||||||
|
|
||||||
|
import { StreamManager } from "./stream_manager.js";
|
||||||
|
|
||||||
|
const MULTICODEC = "/test";
|
||||||
|
|
||||||
|
describe("StreamManager", () => {
|
||||||
|
let eventTarget: EventTarget;
|
||||||
|
let streamManager: StreamManager;
|
||||||
|
|
||||||
|
const mockPeer: Peer = {
|
||||||
|
id: {
|
||||||
|
toString() {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as unknown as Peer;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
eventTarget = new EventTarget();
|
||||||
|
streamManager = new StreamManager(
|
||||||
|
MULTICODEC,
|
||||||
|
() => [],
|
||||||
|
eventTarget.addEventListener.bind(eventTarget)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return usable stream attached to connection", async () => {
|
||||||
|
for (const writeStatus of ["ready", "writing"]) {
|
||||||
|
const con1 = createMockConnection();
|
||||||
|
con1.streams = [
|
||||||
|
createMockStream({ id: "1", protocol: MULTICODEC, writeStatus })
|
||||||
|
];
|
||||||
|
|
||||||
|
streamManager["getConnections"] = (_peerId: PeerId | undefined) => [con1];
|
||||||
|
|
||||||
|
const stream = await streamManager.getStream(mockPeer);
|
||||||
|
|
||||||
|
expect(stream).not.to.be.undefined;
|
||||||
|
expect(stream?.id).to.be.eq("1");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw if no connection provided", async () => {
|
||||||
|
streamManager["getConnections"] = (_peerId: PeerId | undefined) => [];
|
||||||
|
|
||||||
|
let error: Error | undefined;
|
||||||
|
try {
|
||||||
|
await streamManager.getStream(mockPeer);
|
||||||
|
} catch (e) {
|
||||||
|
error = e as Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error).not.to.be.undefined;
|
||||||
|
expect(error?.message).to.include(mockPeer.id.toString());
|
||||||
|
expect(error?.message).to.include(MULTICODEC);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a new stream if no existing for protocol found", async () => {
|
||||||
|
for (const writeStatus of ["done", "closed", "closing"]) {
|
||||||
|
const con1 = createMockConnection();
|
||||||
|
con1.streams = [
|
||||||
|
createMockStream({ id: "1", protocol: MULTICODEC, writeStatus })
|
||||||
|
];
|
||||||
|
|
||||||
|
const newStreamSpy = sinon.spy(async (_protocol, _options) =>
|
||||||
|
createMockStream({
|
||||||
|
id: "2",
|
||||||
|
protocol: MULTICODEC,
|
||||||
|
writeStatus: "writable"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
con1.newStream = newStreamSpy;
|
||||||
|
streamManager["getConnections"] = (_peerId: PeerId | undefined) => [con1];
|
||||||
|
|
||||||
|
const stream = await streamManager.getStream(mockPeer);
|
||||||
|
|
||||||
|
expect(stream).not.to.be.undefined;
|
||||||
|
expect(stream?.id).to.be.eq("2");
|
||||||
|
|
||||||
|
expect(newStreamSpy.calledOnce).to.be.true;
|
||||||
|
expect(newStreamSpy.calledWith(MULTICODEC)).to.be.true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("peer:update - should do nothing if another protocol hit", async () => {
|
||||||
|
const scheduleNewStreamSpy = sinon.spy();
|
||||||
|
streamManager["scheduleNewStream"] = scheduleNewStreamSpy;
|
||||||
|
eventTarget.dispatchEvent(
|
||||||
|
new CustomEvent("peer:update", { detail: { peer: { protocols: [] } } })
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(scheduleNewStreamSpy.calledOnce).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("peer:update - should schedule stream creation IF protocol hit AND no stream found on connection", async () => {
|
||||||
|
const scheduleNewStreamSpy = sinon.spy();
|
||||||
|
streamManager["scheduleNewStream"] = scheduleNewStreamSpy;
|
||||||
|
eventTarget.dispatchEvent(
|
||||||
|
new CustomEvent("peer:update", {
|
||||||
|
detail: { peer: { protocols: [MULTICODEC] } }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(scheduleNewStreamSpy.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("peer:update - should not schedule stream creation IF protocol hit AND stream found on connection", async () => {
|
||||||
|
const con1 = createMockConnection();
|
||||||
|
con1.streams = [
|
||||||
|
createMockStream({
|
||||||
|
id: "1",
|
||||||
|
protocol: MULTICODEC,
|
||||||
|
writeStatus: "writable"
|
||||||
|
})
|
||||||
|
];
|
||||||
|
streamManager["getConnections"] = (_id) => [con1];
|
||||||
|
|
||||||
|
const scheduleNewStreamSpy = sinon.spy();
|
||||||
|
streamManager["scheduleNewStream"] = scheduleNewStreamSpy;
|
||||||
|
|
||||||
|
eventTarget.dispatchEvent(
|
||||||
|
new CustomEvent("peer:update", {
|
||||||
|
detail: { peer: { protocols: [MULTICODEC] } }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(scheduleNewStreamSpy.calledOnce).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
type MockConnectionOptions = {
|
||||||
|
status?: string;
|
||||||
|
open?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createMockConnection(options: MockConnectionOptions = {}): Connection {
|
||||||
|
return {
|
||||||
|
status: options.status || "open",
|
||||||
|
timeline: {
|
||||||
|
open: options.open || 1
|
||||||
|
}
|
||||||
|
} as Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockStreamOptions = {
|
||||||
|
id?: string;
|
||||||
|
protocol?: string;
|
||||||
|
writeStatus?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createMockStream(options: MockStreamOptions): Stream {
|
||||||
|
return {
|
||||||
|
id: options.id,
|
||||||
|
protocol: options.protocol,
|
||||||
|
writeStatus: options.writeStatus || "ready"
|
||||||
|
} as Stream;
|
||||||
|
}
|
@ -1,47 +1,41 @@
|
|||||||
import type { PeerUpdate, Stream } from "@libp2p/interface";
|
import type { Peer, PeerId, PeerUpdate, Stream } from "@libp2p/interface";
|
||||||
import type { Peer, PeerId } from "@libp2p/interface";
|
import type { Libp2p } from "@waku/interfaces";
|
||||||
import { Libp2p } from "@waku/interfaces";
|
|
||||||
import { Logger } from "@waku/utils";
|
import { Logger } from "@waku/utils";
|
||||||
|
|
||||||
import { selectConnection } from "./utils.js";
|
import { selectOpenConnection } from "./utils.js";
|
||||||
|
|
||||||
const CONNECTION_TIMEOUT = 5_000;
|
|
||||||
const RETRY_BACKOFF_BASE = 1_000;
|
|
||||||
const MAX_RETRIES = 3;
|
|
||||||
|
|
||||||
export class StreamManager {
|
export class StreamManager {
|
||||||
private readonly streamPool: Map<string, Promise<Stream | void>>;
|
|
||||||
private readonly log: Logger;
|
private readonly log: Logger;
|
||||||
|
|
||||||
|
private ongoingCreation: Set<string> = new Set();
|
||||||
|
private streamPool: Map<string, Promise<void>> = new Map();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
public multicodec: string,
|
private multicodec: string,
|
||||||
public getConnections: Libp2p["getConnections"],
|
private getConnections: Libp2p["getConnections"],
|
||||||
public addEventListener: Libp2p["addEventListener"]
|
private addEventListener: Libp2p["addEventListener"]
|
||||||
) {
|
) {
|
||||||
this.log = new Logger(`stream-manager:${multicodec}`);
|
this.log = new Logger(`stream-manager:${multicodec}`);
|
||||||
this.streamPool = new Map();
|
|
||||||
this.addEventListener("peer:update", this.handlePeerUpdateStreamPool);
|
this.addEventListener("peer:update", this.handlePeerUpdateStreamPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getStream(peer: Peer): Promise<Stream> {
|
public async getStream(peer: Peer): Promise<Stream> {
|
||||||
const peerIdStr = peer.id.toString();
|
const peerId = peer.id.toString();
|
||||||
const streamPromise = this.streamPool.get(peerIdStr);
|
|
||||||
|
|
||||||
if (!streamPromise) {
|
const scheduledStream = this.streamPool.get(peerId);
|
||||||
return this.createStream(peer);
|
|
||||||
|
if (scheduledStream) {
|
||||||
|
this.streamPool.delete(peerId);
|
||||||
|
await scheduledStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.streamPool.delete(peerIdStr);
|
const stream = this.getOpenStreamForCodec(peer.id);
|
||||||
this.prepareStream(peer);
|
|
||||||
|
|
||||||
try {
|
if (stream) {
|
||||||
const stream = await streamPromise;
|
this.log.info(
|
||||||
if (stream && stream.status !== "closed") {
|
`Found existing stream peerId=${peer.id.toString()} multicodec=${this.multicodec}`
|
||||||
return stream;
|
);
|
||||||
}
|
return stream;
|
||||||
} catch (error) {
|
|
||||||
this.log.warn(`Failed to get stream for ${peerIdStr} -- `, error);
|
|
||||||
this.log.warn("Attempting to create a new stream for the peer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.createStream(peer);
|
return this.createStream(peer);
|
||||||
@ -49,67 +43,112 @@ export class StreamManager {
|
|||||||
|
|
||||||
private async createStream(peer: Peer, retries = 0): Promise<Stream> {
|
private async createStream(peer: Peer, retries = 0): Promise<Stream> {
|
||||||
const connections = this.getConnections(peer.id);
|
const connections = this.getConnections(peer.id);
|
||||||
const connection = selectConnection(connections);
|
const connection = selectOpenConnection(connections);
|
||||||
|
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
throw new Error("Failed to get a connection to the peer");
|
throw new Error(
|
||||||
|
`Failed to get a connection to the peer peerId=${peer.id.toString()} multicodec=${this.multicodec}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastError: unknown;
|
||||||
|
let stream: Stream | undefined;
|
||||||
|
|
||||||
|
for (let i = 0; i < retries + 1; i++) {
|
||||||
|
try {
|
||||||
|
this.log.info(
|
||||||
|
`Attempting to create a stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`
|
||||||
|
);
|
||||||
|
stream = await connection.newStream(this.multicodec);
|
||||||
|
this.log.info(
|
||||||
|
`Created stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to create a new stream for ${peer.id.toString()} -- ` +
|
||||||
|
lastError
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createStreamWithLock(peer: Peer): Promise<void> {
|
||||||
|
const peerId = peer.id.toString();
|
||||||
|
|
||||||
|
if (this.ongoingCreation.has(peerId)) {
|
||||||
|
this.log.info(
|
||||||
|
`Skipping creation of a stream due to lock for peerId=${peerId} multicodec=${this.multicodec}`
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await connection.newStream(this.multicodec);
|
this.ongoingCreation.add(peerId);
|
||||||
|
await this.createStream(peer);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (retries < MAX_RETRIES) {
|
this.log.error(`Failed to createStreamWithLock:`, error);
|
||||||
const backoff = RETRY_BACKOFF_BASE * Math.pow(2, retries);
|
} finally {
|
||||||
await new Promise((resolve) => setTimeout(resolve, backoff));
|
this.ongoingCreation.delete(peerId);
|
||||||
return this.createStream(peer, retries + 1);
|
|
||||||
}
|
|
||||||
throw new Error(
|
|
||||||
`Failed to create a new stream for ${peer.id.toString()} -- ` + error
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private prepareStream(peer: Peer): void {
|
return;
|
||||||
const timeoutPromise = new Promise<void>((resolve) =>
|
|
||||||
setTimeout(resolve, CONNECTION_TIMEOUT)
|
|
||||||
);
|
|
||||||
|
|
||||||
const streamPromise = Promise.race([
|
|
||||||
this.createStream(peer),
|
|
||||||
timeoutPromise.then(() => {
|
|
||||||
throw new Error("Connection timeout");
|
|
||||||
})
|
|
||||||
]).catch((error) => {
|
|
||||||
this.log.error(
|
|
||||||
`Failed to prepare a new stream for ${peer.id.toString()} -- `,
|
|
||||||
error
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.streamPool.set(peer.id.toString(), streamPromise);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handlePeerUpdateStreamPool = (evt: CustomEvent<PeerUpdate>): void => {
|
private handlePeerUpdateStreamPool = (evt: CustomEvent<PeerUpdate>): void => {
|
||||||
const { peer } = evt.detail;
|
const { peer } = evt.detail;
|
||||||
|
|
||||||
if (peer.protocols.includes(this.multicodec)) {
|
if (!peer.protocols.includes(this.multicodec)) {
|
||||||
const isConnected = this.isConnectedTo(peer.id);
|
return;
|
||||||
|
|
||||||
if (isConnected) {
|
|
||||||
this.log.info(`Preemptively opening a stream to ${peer.id.toString()}`);
|
|
||||||
this.prepareStream(peer);
|
|
||||||
} else {
|
|
||||||
const peerIdStr = peer.id.toString();
|
|
||||||
this.streamPool.delete(peerIdStr);
|
|
||||||
this.log.info(
|
|
||||||
`Removed pending stream for disconnected peer ${peerIdStr}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stream = this.getOpenStreamForCodec(peer.id);
|
||||||
|
|
||||||
|
if (stream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scheduleNewStream(peer);
|
||||||
};
|
};
|
||||||
|
|
||||||
private isConnectedTo(peerId: PeerId): boolean {
|
private scheduleNewStream(peer: Peer): void {
|
||||||
|
this.log.info(
|
||||||
|
`Scheduling creation of a stream for peerId=${peer.id.toString()} multicodec=${this.multicodec}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// abandon previous attempt
|
||||||
|
if (this.streamPool.has(peer.id.toString())) {
|
||||||
|
this.streamPool.delete(peer.id.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.streamPool.set(peer.id.toString(), this.createStreamWithLock(peer));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getOpenStreamForCodec(peerId: PeerId): Stream | undefined {
|
||||||
const connections = this.getConnections(peerId);
|
const connections = this.getConnections(peerId);
|
||||||
return connections.some((connection) => connection.status === "open");
|
const connection = selectOpenConnection(connections);
|
||||||
|
|
||||||
|
if (!connection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stream = connection.streams.find(
|
||||||
|
(s) => s.protocol === this.multicodec
|
||||||
|
);
|
||||||
|
|
||||||
|
const isStreamUnusable = ["done", "closed", "closing"].includes(
|
||||||
|
stream?.writeStatus || ""
|
||||||
|
);
|
||||||
|
if (isStreamUnusable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
packages/core/src/lib/stream_manager/utils.spec.ts
Normal file
65
packages/core/src/lib/stream_manager/utils.spec.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { Connection } from "@libp2p/interface";
|
||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { selectOpenConnection } from "./utils.js";
|
||||||
|
|
||||||
|
describe("selectOpenConnection", () => {
|
||||||
|
it("returns nothing if no connections present", () => {
|
||||||
|
const connection = selectOpenConnection([]);
|
||||||
|
|
||||||
|
expect(connection).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns only open connection if one present", () => {
|
||||||
|
let expectedCon = createMockConnection({ id: "1", status: "closed" });
|
||||||
|
let actualCon = selectOpenConnection([expectedCon]);
|
||||||
|
|
||||||
|
expect(actualCon).to.be.undefined;
|
||||||
|
|
||||||
|
expectedCon = createMockConnection({ id: "1", status: "open" });
|
||||||
|
actualCon = selectOpenConnection([expectedCon]);
|
||||||
|
|
||||||
|
expect(actualCon).not.to.be.undefined;
|
||||||
|
expect(actualCon?.id).to.be.eq("1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return no connections if no open connection provided", () => {
|
||||||
|
const closedCon1 = createMockConnection({ status: "closed" });
|
||||||
|
const closedCon2 = createMockConnection({ status: "closed" });
|
||||||
|
const actualCon = selectOpenConnection([closedCon1, closedCon2]);
|
||||||
|
|
||||||
|
expect(actualCon).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should select older connection if present", () => {
|
||||||
|
const con1 = createMockConnection({
|
||||||
|
status: "open",
|
||||||
|
open: 10
|
||||||
|
});
|
||||||
|
const con2 = createMockConnection({
|
||||||
|
status: "open",
|
||||||
|
open: 15
|
||||||
|
});
|
||||||
|
|
||||||
|
const actualCon = selectOpenConnection([con1, con2]);
|
||||||
|
|
||||||
|
expect(actualCon).not.to.be.undefined;
|
||||||
|
expect(actualCon?.timeline.open).to.be.eq(15);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
type MockConnectionOptions = {
|
||||||
|
id?: string;
|
||||||
|
status?: string;
|
||||||
|
open?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function createMockConnection(options: MockConnectionOptions = {}): Connection {
|
||||||
|
return {
|
||||||
|
id: options.id,
|
||||||
|
status: options.status,
|
||||||
|
timeline: {
|
||||||
|
open: options.open
|
||||||
|
}
|
||||||
|
} as Connection;
|
||||||
|
}
|
@ -1,22 +1,10 @@
|
|||||||
import type { Connection } from "@libp2p/interface";
|
import type { Connection } from "@libp2p/interface";
|
||||||
|
|
||||||
export function selectConnection(
|
export function selectOpenConnection(
|
||||||
connections: Connection[]
|
connections: Connection[]
|
||||||
): Connection | undefined {
|
): Connection | undefined {
|
||||||
if (!connections.length) return;
|
return connections
|
||||||
if (connections.length === 1) return connections[0];
|
.filter((c) => c.status === "open")
|
||||||
|
.sort((left, right) => right.timeline.open - left.timeline.open)
|
||||||
let latestConnection: Connection | undefined;
|
.at(0);
|
||||||
|
|
||||||
connections.forEach((connection) => {
|
|
||||||
if (connection.status === "open") {
|
|
||||||
if (!latestConnection) {
|
|
||||||
latestConnection = connection;
|
|
||||||
} else if (connection.timeline.open > latestConnection.timeline.open) {
|
|
||||||
latestConnection = connection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return latestConnection;
|
|
||||||
}
|
}
|
||||||
|
@ -59,19 +59,16 @@ 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);
|
|
||||||
|
|
||||||
const peer = (await this.findAndAddPeers(1))[0];
|
const peer = (await this.findAndAddPeers(1))[0];
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
this.log.error(
|
throw Error("Failed to find a new peer to replace the disconnected one.");
|
||||||
"Failed to find a new peer to replace the disconnected one."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedPeers = this.peers.filter(
|
const updatedPeers = this.peers.filter(
|
||||||
(peer) => !peer.id.equals(peerToDisconnect)
|
(peer) => !peer.id.equals(peerToDisconnect)
|
||||||
);
|
);
|
||||||
this.updatePeers(updatedPeers);
|
this.updatePeers(updatedPeers);
|
||||||
|
await this.connectionManager.dropConnection(peerToDisconnect);
|
||||||
|
|
||||||
this.log.info(
|
this.log.info(
|
||||||
`Peer ${peerToDisconnect} disconnected and removed from the peer list`
|
`Peer ${peerToDisconnect} disconnected and removed from the peer list`
|
||||||
|
@ -291,7 +291,8 @@ describe("Waku Filter V2: Subscribe: Single Service Node", function () {
|
|||||||
messageCollector.verifyReceivedMessage(index, {
|
messageCollector.verifyReceivedMessage(index, {
|
||||||
expectedContentTopic: topic,
|
expectedContentTopic: topic,
|
||||||
expectedMessageText: `Message for Topic ${index + 1}`,
|
expectedMessageText: `Message for Topic ${index + 1}`,
|
||||||
expectedPubsubTopic: TestPubsubTopic
|
expectedPubsubTopic: TestPubsubTopic,
|
||||||
|
checkTimestamp: false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user