add missing files

This commit is contained in:
2025-04-27 10:11:10 -07:00
parent 15c95e5c59
commit 63d7b276db
8 changed files with 3859 additions and 282 deletions

View File

@@ -5,7 +5,7 @@
// how? do "perfect negotiation" with bootstrap peer. All logic here moves to BP.
import { generateID } from "IDUtils";
import { log } from "log";
import { log, logID } from "log";
// Use a broadcast channel to only have one peer manager for multiple tabs,
// then we won't need to have a session ID as all queries for a peerID will be coming from the same peer manager
@@ -29,6 +29,15 @@ export class PeerManager {
connectPromise: { resolve: Function, reject: Function } | null = null;
pingPeers: RTCPeerConnection[] = [];
watchdogPeriodSeconds: number = 10;
// async watchdog() {
// // Check that we're connected to at least N peers. If not, reconnect to the bootstrap server.
// if (this.peers.size === 0) {
// await this.sendHello2();
// }
// }
websocketSend(message: any) {
if (!this.websocket) {
@@ -168,18 +177,55 @@ export class PeerManager {
this.routingTable = new Map();
this.userID = userID;
this.peerID = peerID;
}
disconnect() {
this.websocket?.close();
for (let peer of this.peers.values()) {
peer.disconnect();
}
}
connect() {
// setInterval(this.watchdog.bind(this), this.watchdogPeriodSeconds * 1000);
setInterval(()=>{
if (!this.isBootstrapPeer && this.peers.size === 0) {
console.log.apply(null, log("No peers connected :("));
if (this.websocket?.readyState === WebSocket.OPEN) {
this.sendHello2();
}
}
let output = `local peerID:${logID(this.peerID)}` + "\n";
for (let [peerID, peer] of this.peers) {
output += `${logID(peerID)}: ${peer.rtcPeer?.connectionState}` + "\n";
}
console.log.apply(null, log(output));
}, 5000);
let connectPromise = new Promise((resolve, reject) => {
this.connectPromise = { resolve, reject };
});
try {
this.websocket = new WebSocket(
`wss://${window.location.hostname}:${window.location.port}/ws`,
);
let hostname = globalThis?.location?.hostname ?? 'ddln.app';
let port = globalThis?.location?.port ?? '443';
let wsURL = `wss://${hostname}:${port}/ws`;
console.log(`wsURL: ${wsURL}`);
this.websocket = new WebSocket(wsURL);
} catch (error: any) {
throw new Error(error.message);
}
@@ -237,14 +283,15 @@ export class PeerManager {
}
async disconnect(remotePeerID: string) {
async disconnectFromPeer(remotePeerID: string) {
let peer = this.peers.get(remotePeerID);
if (!peer) {
console.log.apply(null, log(`PeerManager.disconnect: couln't find peer ${remotePeerID}`));
console.log.apply(null, log(`PeerManager.disconnect: couldn't find peer ${remotePeerID}`));
return;
}
console.log.apply(null, log(`PeerManager.disconnect: disconnecting peer ${remotePeerID}`));
await peer.disconnect();
this.peers.delete(remotePeerID);
}
@@ -295,8 +342,6 @@ export class PeerManager {
}
}
interface Message {
type: string;
from_peer: string;
@@ -306,98 +351,6 @@ interface Message {
peer_message: any;
}
// // Initially this wil be the bootstrap peer, We'll keep a connection to it and it will keep a list of all connected peers.
// // Eventually we will replace this with connecting via other peers.
// class Signaler {
// websocket: WebSocket;
// sessionID: string;
// userID: string;
// peerID: string;
// bootstrapPeerID: string = "";
// private isBootstrapPeer: boolean = false;
// private onConnected: Function;
// peerRoutes: Map<string, PeerConnection> = new Map();
// constructor(userID: string, peerID: string, isBootstrapPeer: boolean, onConnected: Function) {
// this.onConnected = onConnected;
// this.isBootstrapPeer = isBootstrapPeer;
// this.sessionID = generateID();
// this.userID = userID;
// this.peerID = peerID;
// try {
// this.websocket = new WebSocket(
// `wss://${window.location.hostname}:${window.location.port}/ws`,
// );
// } catch (error: any) {
// throw new Error(error.message);
// }
// this.websocket.onopen = async (event) => {
// console.log.apply(null, log("signaler:ws:onopen");
// await this.sendHello2();
// };
// this.websocket.onmessage = this.onMessage.bind(this);
// }
// connect() {
// }
// onMessage(event: MessageEvent) {
// let messageJSON = event.data;
// let message: any = null;
// try {
// message = JSON.parse(messageJSON);
// } catch (e) {
// console.log.apply(null, log(e);
// throw new Error();
// }
// console.log.apply(null, log("->signaler:", message);
// if (message.type === "hello2") {
// if (!this.isBootstrapPeer) {
// this.bootstrapPeerID = message.bootstrapPeers[0];
// }
// this.onConnected(this.bootstrapPeerID);
// }
// if (message.type == "peer_message") {
// if (message.message.type = "rtc_connect") {
// }
// let connection = this.peerRoutes.get(message.from_peer);
// if (!connection) {
// console.log.apply(null, log("Can't find peer for peer message:", message);
// return;
// }
// connection.onSignalerMessage(message);
// }
// }
// route(remotePeerID:string, peerConnection:PeerConnection) {
// this.peerRoutes.set(remotePeerID, peerConnection)
// }
// // sendPeerMessage
// }
class PeerConnection {
private remotePeerID: string;
// private signaler: Signaler;
@@ -462,7 +415,7 @@ class PeerConnection {
if (!this.dataChannel) {
throw new Error();
}
console.log.apply(null, log("data channel is open!"));
console.log.apply(null, log("data channel is open to: ", this.remotePeerID, " from: ", this.peerManager.peerID));
this.send({ type: "hello datachannel", from: this.peerManager.peerID, to: this.remotePeerID});
// this.dataChannel?.send(`{typeHello datachannel from: ${this.peerManager.peerID}`);
@@ -480,6 +433,11 @@ class PeerConnection {
console.log.apply(null, log("->datachannel: ", e.data))
this.onMessage(e.data);
}
this.dataChannel.onclose = (e: Event) => {
console.log.apply(null, log(`datachannel from peer ${this.remotePeerID} closed, disconnecting peer.`));
this.peerManager.disconnectFromPeer(this.remotePeerID);
}
}
async connect() {
@@ -494,10 +452,10 @@ class PeerConnection {
}
// When the connection is closed, tell the peer manager that this connection has gone away
if (this.rtcPeer.connectionState === "disconnected") {
if (this.rtcPeer.connectionState === "failed") {
this.peerManager.onPeerDisconnected(this.remotePeerID);
// window.setTimeout(async () => { await this.peerManager.connectToPeer(this.remotePeerID) }, 10_000);
// globalThis.setTimeout(async () => { await this.peerManager.connectToPeer(this.remotePeerID) }, 10_000);
}
if (this.rtcPeer.connectionState === "connected") {
@@ -640,8 +598,9 @@ class PeerConnection {
}
async disconnect() {
disconnect() {
this.rtcPeer?.close();
this.rtcPeer = null;
}
send(message: any) {
@@ -714,167 +673,4 @@ class PeerConnection {
// this.peerManger.onMessage(this.remotePeerID, message);
}
}
// export class PeerConnection2 {
// id: string;
// private makingOffer:boolean = false;
// private ignoreOffer:boolean = false;
// rtcPeer: RTCPeerConnection;
// signaler:WebSocket;
// static config = {
// iceServers: [
// { urls: "stun:stun.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" },
// ],
// };
// constructor(remotePeerID: string, signaler:WebSocket) {
// this.id = remotePeerID;
// this.rtcPeer = new RTCPeerConnection(PeerConnection2.config);
// this.signaler = signaler;;
// this.rtcPeer.onnegotiationneeded = async () => {
// try {
// this.makingOffer = true;
// await this.rtcPeer.setLocalDescription();
// signaler.send(JSON.stringify({ description: this.rtcPeer.localDescription }));
// } catch (err) {
// console.error(err);
// } finally {
// this.makingOffer = false;
// }
// };
// this.rtcPeer.onicecandidate = ({ candidate }) => signaler.send(JSON.stringify({ candidate }));
// this.ignoreOffer = false;
// }
// onSignallerMessage = async ({ data: { description, candidate } }: MessageEvent) => {
// try {
// if (description) {
// // const offerCollision =
// // description.type === "offer" &&
// // (this.makingOffer || this.rtcPeer.signalingState !== "stable");
// // this.ignoreOffer = !polite && offerCollision;
// if (this.ignoreOffer) {
// return;
// }
// await this.rtcPeer.setRemoteDescription(description);
// if (description.type === "offer") {
// await this.rtcPeer.setLocalDescription();
// this.signaler.send(JSON.stringify({ description: this.rtcPeer.localDescription }));
// }
// } else if (candidate) {
// try {
// await this.rtcPeer.addIceCandidate(candidate);
// } catch (err) {
// if (!this.ignoreOffer) {
// throw err;
// }
// }
// }
// } catch (err) {
// console.error(err);
// }
// };
// }
// // const config = {
// // iceServers: [{ urls: "stun:stun.mystunserver.tld" }],
// // };
// // let polite = true;
// // const signaler = new SignalingChannel();
// // const signaler: any = {}
// // const rtcPeer = new RTCPeerConnection(config);
// // // const constraints = { audio: true, video: true };
// // const selfVideo = document.querySelector("video.selfview");
// // const remoteVideo = document.querySelector("video.remoteview");
// // async function start() {
// // try {
// // const stream = await navigator.mediaDevices.getUserMedia(constraints);
// // for (const track of stream.getTracks()) {
// // pc.addTrack(track, stream);
// // }
// // selfVideo.srcObject = stream;
// // } catch (err) {
// // console.error(err);
// // }
// // }
// // rtcPeer.ontrack = ({ track, streams }) => {
// // track.onunmute = () => {
// // if (remoteVideo.srcObject) {
// // return;
// // }
// // remoteVideo.srcObject = streams[0];
// // };
// // };
// // makingOffer = false;
// // rtcPeer.onnegotiationneeded = async () => {
// // try {
// // // makingOffer = true;
// // await rtcPeer.setLocalDescription();
// // signaler.send({ description: rtcPeer.localDescription });
// // } catch (err) {
// // console.error(err);
// // } finally {
// // makingOffer = false;
// // }
// // };
// // rtcPeer.onicecandidate = ({ candidate }) => signaler.send({ candidate });
// // let ignoreOffer = false;
// // signaler.onmessage = async ({ data: { description, candidate } }: MessageEvent) => {
// // try {
// // if (description) {
// // const offerCollision =
// // description.type === "offer" &&
// // // (makingOffer || rtcPeer.signalingState !== "stable");
// // ignoreOffer = !polite && offerCollision;
// // if (ignoreOffer) {
// // return;
// // }
// // await rtcPeer.setRemoteDescription(description);
// // if (description.type === "offer") {
// // await rtcPeer.setLocalDescription();
// // signaler.send({ description: rtcPeer.localDescription });
// // }
// // } else if (candidate) {
// // try {
// // await rtcPeer.addIceCandidate(candidate);
// // } catch (err) {
// // if (!ignoreOffer) {
// // throw err;
// // }
// // }
// // }
// // } catch (err) {
// // console.error(err);
// // }
// // };
}