Add support for multiple bootstrap peers

This commit is contained in:
2025-06-04 02:21:19 -07:00
parent b68f0f4b57
commit 70f5b82e02
2 changed files with 82 additions and 42 deletions

View File

@@ -27,13 +27,13 @@ export class PeerManager {
RPC_remote: Map<string, Function> = new Map();
rpc: { [key: string]: Function } = {};
isBootstrapPeer: boolean = false;
bootstrapPeerConnection: PeerConnection | null = null;
bootstrapPeerConnections: Map<string, PeerConnection> | null = null;
sessionID = generateID();
userID: string;
peerID: PeerID;
websocket: WebSocket | null = null;
bootstrapPeerID: string | null = null;
bootstrapPeerIDs: Set<string> | null = null;
connectPromiseCallbacks: { resolve: Function, reject: Function } | null = null;
connectPromise: Promise<null> | null = null;
@@ -42,7 +42,7 @@ export class PeerManager {
eventListeners: Map<PeerEventTypes, Function[]> = new Map();
reconnectPeriod: number = 10;
messageSuperlog = false;
watchdogInterval: ReturnType<typeof setTimeout> |null = null;
watchdogInterval: ReturnType<typeof setTimeout> | null = null;
reconnectTimer: number | null = null;
peerStateSuperlog: boolean = true;
@@ -118,11 +118,11 @@ export class PeerManager {
if (message.type === "hello2") {
if (!this.isBootstrapPeer) {
this.bootstrapPeerID = message.bootstrapPeers[0];
if (!this.isBootstrapPeer && Array.isArray(message?.bootstrapPeers)) {
this.bootstrapPeerIDs = new Set(message.bootstrapPeers);
}
this.onHello2Received(this.bootstrapPeerID as string);
this.onHello2Received(this.bootstrapPeerIDs);
}
if (message.type === "peer_message") {
@@ -175,21 +175,41 @@ export class PeerManager {
return newPeer;
}
async onHello2Received(bootstrapPeerID: string) {
async onHello2Received(bootstrapPeerIDs: Set<string> | null) {
if (this.isBootstrapPeer) {
this.connectPromiseCallbacks?.resolve();
return;
}
if (!bootstrapPeerID) {
console.log.apply(null, log("Didn't get bootstrap peer, waiting 10 seconds..."));
if (!bootstrapPeerIDs) {
console.log.apply(null, log("Didn't get any bootstrap peer, waiting 10 seconds..."));
// let callSendHello2OnTimeout = () => { console.log(this, "jajajajaj");this.sendHello2() };
// setTimeout(callSendHello2OnTimeout, 5_000);
return;
}
this.bootstrapPeerConnection = await this.connectToPeer(bootstrapPeerID);
let bootstrapPeerConnectionPromises = [];
for (let peerID of bootstrapPeerIDs.keys()) {
// this.bootstrapPeerConnection = await this.connectToPeer(peerID);
let bootstrapPeerConnectionPromise = new Promise( async (resolve, reject)=>{
let peerConnection = await this.connectToPeer(peerID);
if (!peerConnection) {
reject(peerConnection);
}
this.bootstrapPeerConnections?.set(peerID, peerConnection);
resolve(peerConnection);
})
bootstrapPeerConnectionPromises.push(bootstrapPeerConnectionPromise);
}
await Promise.race(bootstrapPeerConnectionPromises);
this.connectPromiseCallbacks?.resolve();
}
@@ -321,7 +341,7 @@ export class PeerManager {
let output = `Current status:` + "\n" + `[${logID(this.peerID)}]${this.getPeername(this.peerID)}[local]` + "\n";
for (let [peerID, peer] of this.peers) {
output += `[${logID(peerID)}]${peer.rtcPeer?.connectionState}:${this.getPeername(peerID)}${(peerID === this.bootstrapPeerID) ? "[Bootstrap]" : ""}` + "\n";
output += `[${logID(peerID)}]${peer.rtcPeer?.connectionState}:${this.getPeername(peerID)}${this.bootstrapPeerIDs?.has(peerID) ? "[Bootstrap]" : ""}` + "\n";
}
output += `numActivePeers: ${numActive}` + "\n";
@@ -409,9 +429,9 @@ export class PeerManager {
// We should disconnect from the websocket once we connect to our intial peers.
// If we have no peer connections, try to connect. If connection fails, start a timer to reconnect.
if (peerID === this.bootstrapPeerID) {
this.bootstrapPeerID = null;
this.bootstrapPeerConnection = null;
if (this.bootstrapPeerIDs?.has(peerID)) {
this.bootstrapPeerIDs.delete(peerID);
this.bootstrapPeerConnections?.delete(peerID);
}
this.peerStateSuperlog && console.log.apply(null, log(`PeerManager: disconnected from peer ${peerID}`));
@@ -501,10 +521,11 @@ class PeerConnection {
private ignoreOffer: boolean = false;
private isSettingRemoteAnswerPending: boolean = false;
private polite = true;
private webRTCSuperlog = true;
private webRTCSuperlog = false;
private dataChannelSuperlog = false;
private chunkSize = (16 * 1024) - 100;
messageSuperlog: boolean = false;
sendQueueSuperLog: boolean = false;
rpcSuperlog: boolean = false;
pendingRPCs: Map<
string,
@@ -522,10 +543,10 @@ class PeerConnection {
{ urls: "stun:ddln.app" },
// { urls: "turn:ddln.app", username: "a", credential: "b" },
{ urls: "stun:stun.l.google.com" }, // keeping this for now as my STUN server is not returning ipv6
{ urls: "stun:stun1.l.google.com" },
{ urls: "stun:stun2.l.google.com" },
{ urls: "stun:stun3.l.google.com" },
{ urls: "stun:stun4.l.google.com" },
{ urls: "stun:stun1.l.google.com" },
{ urls: "stun:stun2.l.google.com" },
{ urls: "stun:stun3.l.google.com" },
{ urls: "stun:stun4.l.google.com" },
],
};
// longMessageQueue: string[] = [];
@@ -565,7 +586,7 @@ class PeerConnection {
this.send({ type: "hello datachannel", from: this.peerManager.peerID, to: this.remotePeerID });
// this.dataChannel?.send(`{typeHello datachannel from: ${this.peerManager.peerID}`);
console.log.apply(null, log([...this.peerManager.peers.keys()]));
// console.log.apply(null, log([...this.peerManager.peers.keys()]));
if (this.peerManager.isBootstrapPeer) {
this.send({ type: 'initial_peers', from: this.peerManager.peerID, peers: [...this.peerManager.peers.keys()].filter(entry => entry !== this.remotePeerID) });
@@ -588,7 +609,7 @@ class PeerConnection {
this.peerManager.disconnectFromPeer(this.remotePeerID);
}
this.dataChannel.onerror = (e: RTCErrorEvent) => {
this.dataChannel.onerror = (e: RTCErrorEvent) => {
this.dataChannelSuperlog && console.log.apply(null, log(`datachannel from peer ${this.remotePeerID} error:`, e.error));
}
}
@@ -656,7 +677,7 @@ class PeerConnection {
}
this.rtcPeer.oniceconnectionstatechange = (event:Event) => {
this.rtcPeer.oniceconnectionstatechange = (event: Event) => {
this.webRTCSuperlog && console.log.apply(null, log("oniceconnectionstatechange:", this.rtcPeer?.iceConnectionState));
}
@@ -776,8 +797,11 @@ class PeerConnection {
throw new Error("Send called but datachannel is null");
}
// this.sendQueueSuperLog && console.log.apply(null, log(`[${logID(this.remotePeerID)}]<-datachannel[${logID(this.peerManager.peerID)}]: bufferedAmount ${this.dataChannel.bufferedAmount}`));
while (this.dataChannel.bufferedAmount >= 8 * 1024 * 1024) {
this.sendQueueSuperLog && console.log.apply(null, log(`[${logID(this.remotePeerID)}]<-datachannel[${logID(this.peerManager.peerID)}]: send buffer full, waiting 1 second`));
await new Promise<void>((resolve, reject) => {
setTimeout(() => resolve(), 1000);
})