Add events to peer manager
This commit is contained in:
@@ -10,6 +10,13 @@ import { log, logID } from "log";
|
|||||||
// Use a broadcast channel to only have one peer manager for multiple tabs,
|
// 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
|
// then we won't need to have a session ID as all queries for a peerID will be coming from the same peer manager
|
||||||
|
|
||||||
|
type PeerID = string;
|
||||||
|
|
||||||
|
export enum PeerEventTypes {
|
||||||
|
PEER_CONNECTED,
|
||||||
|
PEER_DISCONNECTED,
|
||||||
|
}
|
||||||
|
|
||||||
export class PeerManager {
|
export class PeerManager {
|
||||||
routingTable: Map<string, string>;
|
routingTable: Map<string, string>;
|
||||||
|
|
||||||
@@ -22,7 +29,7 @@ export class PeerManager {
|
|||||||
bootstrapPeerConnection: PeerConnection | null = null;
|
bootstrapPeerConnection: PeerConnection | null = null;
|
||||||
sessionID = generateID();
|
sessionID = generateID();
|
||||||
userID: string;
|
userID: string;
|
||||||
peerID: string;
|
peerID: PeerID;
|
||||||
|
|
||||||
websocket: WebSocket | null = null;
|
websocket: WebSocket | null = null;
|
||||||
bootstrapPeerID: string | null = null;
|
bootstrapPeerID: string | null = null;
|
||||||
@@ -30,6 +37,7 @@ export class PeerManager {
|
|||||||
|
|
||||||
pingPeers: RTCPeerConnection[] = [];
|
pingPeers: RTCPeerConnection[] = [];
|
||||||
watchdogPeriodSeconds: number = 10;
|
watchdogPeriodSeconds: number = 10;
|
||||||
|
eventListeners: Map<PeerEventTypes, Function[]> = new Map();
|
||||||
|
|
||||||
// async watchdog() {
|
// async watchdog() {
|
||||||
// // Check that we're connected to at least N peers. If not, reconnect to the bootstrap server.
|
// // Check that we're connected to at least N peers. If not, reconnect to the bootstrap server.
|
||||||
@@ -261,10 +269,35 @@ export class PeerManager {
|
|||||||
let peerConnection = new PeerConnection(this, remotePeerID, this.websocketSendPeerMessage.bind(this));
|
let peerConnection = new PeerConnection(this, remotePeerID, this.websocketSendPeerMessage.bind(this));
|
||||||
this.peers.set(remotePeerID, peerConnection);
|
this.peers.set(remotePeerID, peerConnection);
|
||||||
await peerConnection.connect();
|
await peerConnection.connect();
|
||||||
|
this.onPeerConnected(this.peerID);
|
||||||
return peerConnection;
|
return peerConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPeerDisconnected(remotePeerID: string) {
|
onPeerConnected(peerID: PeerID) {
|
||||||
|
this.dispatchEvent(PeerEventTypes.PEER_CONNECTED, {peerID:peerID});
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchEvent(event:PeerEventTypes, parameters:any) {
|
||||||
|
let listeners = this.eventListeners.get(event);
|
||||||
|
|
||||||
|
if (!listeners) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let listener of listeners) {
|
||||||
|
listener(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addEventListener(eventName:PeerEventTypes, func:Function) {
|
||||||
|
let listeners = this.eventListeners.get(eventName);
|
||||||
|
if (!listeners) {
|
||||||
|
this.eventListeners.set(eventName, [func]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPeerDisconnected(remotePeerID: PeerID) {
|
||||||
let deleted = this.peers.delete(remotePeerID);
|
let deleted = this.peers.delete(remotePeerID);
|
||||||
|
|
||||||
if (!deleted) {
|
if (!deleted) {
|
||||||
|
|||||||
111
src/main2.ts
111
src/main2.ts
@@ -33,7 +33,7 @@ Restruucture the app around the data. App/WS split is messy. Clean it up.
|
|||||||
// import * as ForceGraph3D from "3d-force-graph";
|
// import * as ForceGraph3D from "3d-force-graph";
|
||||||
import { openDatabase, getData, addData, addDataArray, clearData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "db";
|
import { openDatabase, getData, addData, addDataArray, clearData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "db";
|
||||||
import { generateID } from "IDUtils";
|
import { generateID } from "IDUtils";
|
||||||
import { PeerManager } from "PeerManager";
|
import { PeerManager, PeerEventTypes } from "PeerManager";
|
||||||
|
|
||||||
import { log, logID, renderLog, setLogVisibility } from "log"
|
import { log, logID, renderLog, setLogVisibility } from "log"
|
||||||
|
|
||||||
@@ -244,95 +244,14 @@ interface PeerMessage {
|
|||||||
message: any;
|
message: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
// class Signaler {
|
|
||||||
// websocket: WebSocket | null = null;
|
|
||||||
|
|
||||||
// websocketPingInterval: number = 0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// connect() {
|
|
||||||
// if (this.websocket?.readyState === WebSocket.OPEN) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// window.clearInterval(this.websocketPingInterval);
|
|
||||||
// if (this.websocket) { this.websocket.close() };
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// this.websocket = new WebSocket(`wss://${window.location.hostname}:${window.location.port}/ws`);
|
|
||||||
// } catch (error: any) {
|
|
||||||
// console.log.apply(null, log(error.message);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.websocket.onopen = async (event) => {
|
|
||||||
// console.log.apply(null, log("ws:connected"));;
|
|
||||||
// await this.sendHello();
|
|
||||||
|
|
||||||
// // If we're running as a headless peer, send a hello message every N seconds to refresh the posts we have.
|
|
||||||
// let helloRefreshIntervalPeriod = 120;
|
|
||||||
// if (app.isHeadless) {
|
|
||||||
// console.log.apply(null, log("wsConnection: Setting hello refresh interval to ", helloRefreshIntervalPeriod)
|
|
||||||
// this.helloRefreshInterval = window.setInterval(() => {
|
|
||||||
// console.log.apply(null, log("wsConnection: Hello refresh.")
|
|
||||||
|
|
||||||
// if (!navigator.onLine) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// this.sendHello();
|
|
||||||
// }, helloRefreshIntervalPeriod * 1000);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.websocketPingInterval = window.setInterval(() => {
|
|
||||||
// if (!navigator.onLine) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// this.send({ type: "ping", peer_id: this.peerID, peer_name: app.peername, user_id: app.userID, user_name: app.username });
|
|
||||||
// }, 10_000)
|
|
||||||
// };
|
|
||||||
|
|
||||||
// this.websocket.onclose = (event) => {
|
|
||||||
// console.log.apply(null, log("ws:disconnected"));;
|
|
||||||
// // this.retry *= 2;
|
|
||||||
// console.log.apply(null, log(`Retrying in ${this.retry} seconds`));;
|
|
||||||
// window.setTimeout(() => { this.connect(); }, this.retry * 1000);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// this.websocket.onmessage = (event) => {
|
|
||||||
// // log('ws:<-' + event.data.slice(0, 240));
|
|
||||||
// let data = JSON.parse(event.data);
|
|
||||||
|
|
||||||
// let { type } = data;
|
|
||||||
|
|
||||||
// let handler = this.messageHandlers.get(type);
|
|
||||||
// if (!handler) {
|
|
||||||
// console.warn(`Got a message we can't handle:`, type);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// handler(data);
|
|
||||||
|
|
||||||
// };
|
|
||||||
|
|
||||||
// this.websocket.onerror = (event) => {
|
|
||||||
// console.log.apply(null, log('ws:error: ' + event));;
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// disconnect() {
|
|
||||||
// this.websocket?.close();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// Connect websocket
|
// Connect websocket
|
||||||
// send hello
|
// send hello
|
||||||
// get bootstrap peer ID
|
// get bootstrap peer ID
|
||||||
// WebRTC connect to bootstrap peer
|
// WebRTC connect to bootstrap peer
|
||||||
// ask Bootstrap peer for peers that have users we care about.
|
// Bootstrap peer will send the last N peers it saw.
|
||||||
// for now, bootstrap peer will connect to all peers and will tell us about them, moving all logic from the server to the BSP
|
// Connect to those new peers, tell those peers about users we know about
|
||||||
|
// ask for peers that have users we care about
|
||||||
// WebRTC Connect to peers that might have posts we need
|
// WebRTC Connect to peers that might have posts we need
|
||||||
// query those peers and do existing logic.
|
// query those peers and do existing logic.
|
||||||
|
|
||||||
@@ -341,7 +260,7 @@ class wsConnection {
|
|||||||
sessionID = "";
|
sessionID = "";
|
||||||
userID = "";
|
userID = "";
|
||||||
peerID = "";
|
peerID = "";
|
||||||
rtcPeerDescription: RTCSessionDescription | null = null;
|
// rtcPeerDescription: RTCSessionDescription | null = null;
|
||||||
UserIDsToSync: Set<string>;
|
UserIDsToSync: Set<string>;
|
||||||
websocketPingInterval: number = 0;
|
websocketPingInterval: number = 0;
|
||||||
helloRefreshInterval: number = 0;
|
helloRefreshInterval: number = 0;
|
||||||
@@ -355,7 +274,7 @@ class wsConnection {
|
|||||||
|
|
||||||
|
|
||||||
constructor(userID: string, peerID: string, IDsToSync: Set<string>, rtcPeerDescription: RTCSessionDescription) {
|
constructor(userID: string, peerID: string, IDsToSync: Set<string>, rtcPeerDescription: RTCSessionDescription) {
|
||||||
this.rtcPeerDescription = rtcPeerDescription;
|
// this.rtcPeerDescription = rtcPeerDescription;
|
||||||
this.sessionID = generateID();
|
this.sessionID = generateID();
|
||||||
this.userID = userID;
|
this.userID = userID;
|
||||||
this.peerID = peerID;
|
this.peerID = peerID;
|
||||||
@@ -626,10 +545,18 @@ class wsConnection {
|
|||||||
session_id: this.sessionID,
|
session_id: this.sessionID,
|
||||||
peer_name: app.peername,
|
peer_name: app.peername,
|
||||||
is_bootstrap_peer: app.isBootstrapPeer,
|
is_bootstrap_peer: app.isBootstrapPeer,
|
||||||
peer_description: this.rtcPeerDescription
|
// peer_description: this.rtcPeerDescription
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getKnownUsers() {
|
||||||
|
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
||||||
|
knownUsers = knownUsers
|
||||||
|
.filter(userID => this.shouldSyncUserID(userID))
|
||||||
|
.filter(userID => !this.userBlockList.has(userID))
|
||||||
|
.filter(async userID => (await getAllIds(userID)).length > 0); // TODO:EASYOPT getting all the IDs is unecessary, replace it with a test to get a single ID.
|
||||||
|
}
|
||||||
|
|
||||||
async sendHello() {
|
async sendHello() {
|
||||||
// TODO only get users you're following here. ✅
|
// TODO only get users you're following here. ✅
|
||||||
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
||||||
@@ -816,7 +743,13 @@ class App {
|
|||||||
async connect() {
|
async connect() {
|
||||||
this.peerManager = new PeerManager(this.userID, this.peerID, this.isBootstrapPeer);
|
this.peerManager = new PeerManager(this.userID, this.peerID, this.isBootstrapPeer);
|
||||||
this.registerRPCs();
|
this.registerRPCs();
|
||||||
console.log.apply(null, log("*************** before peerManager.connect"));;
|
|
||||||
|
this.peerManager.addEventListener(PeerEventTypes.PEER_CONNECTED, (event: any) => {
|
||||||
|
console.log.apply(null, log(`[app]: peer connected:${event.peerID}`));
|
||||||
|
// rpc saying what peers we have
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log.apply(null, log("*************** before peerManager.connect"));
|
||||||
|
|
||||||
// We use promises here to only return from this call once we're connected to the boostrap peer
|
// We use promises here to only return from this call once we're connected to the boostrap peer
|
||||||
// and the datachannel is open.
|
// and the datachannel is open.
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Restruucture the app around the data. App/WS split is messy. Clean it up.
|
|||||||
// import * as ForceGraph3D from "3d-force-graph";
|
// import * as ForceGraph3D from "3d-force-graph";
|
||||||
import { openDatabase, getData, addData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "db";
|
import { openDatabase, getData, addData, deleteData, mergeDataArray, getAllData, checkPostIds, getAllIds, getPostsByIds } from "db";
|
||||||
import { generateID } from "IDUtils";
|
import { generateID } from "IDUtils";
|
||||||
import { PeerManager } from "PeerManager";
|
import { PeerManager, PeerEventTypes } from "PeerManager";
|
||||||
import { log, logID, renderLog, setLogVisibility } from "log";
|
import { log, logID, renderLog, setLogVisibility } from "log";
|
||||||
// let posts:any;
|
// let posts:any;
|
||||||
// let keyBase = "dandelion_posts_v1_"
|
// let keyBase = "dandelion_posts_v1_"
|
||||||
@@ -154,75 +154,13 @@ async function compressString(input) {
|
|||||||
// Convert the compressed data to a Uint8Array
|
// Convert the compressed data to a Uint8Array
|
||||||
return new Uint8Array(compressedArray);
|
return new Uint8Array(compressedArray);
|
||||||
}
|
}
|
||||||
// class Signaler {
|
|
||||||
// websocket: WebSocket | null = null;
|
|
||||||
// websocketPingInterval: number = 0;
|
|
||||||
// connect() {
|
|
||||||
// if (this.websocket?.readyState === WebSocket.OPEN) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// window.clearInterval(this.websocketPingInterval);
|
|
||||||
// if (this.websocket) { this.websocket.close() };
|
|
||||||
// try {
|
|
||||||
// this.websocket = new WebSocket(`wss://${window.location.hostname}:${window.location.port}/ws`);
|
|
||||||
// } catch (error: any) {
|
|
||||||
// console.log.apply(null, log(error.message);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// this.websocket.onopen = async (event) => {
|
|
||||||
// console.log.apply(null, log("ws:connected"));;
|
|
||||||
// await this.sendHello();
|
|
||||||
// // If we're running as a headless peer, send a hello message every N seconds to refresh the posts we have.
|
|
||||||
// let helloRefreshIntervalPeriod = 120;
|
|
||||||
// if (app.isHeadless) {
|
|
||||||
// console.log.apply(null, log("wsConnection: Setting hello refresh interval to ", helloRefreshIntervalPeriod)
|
|
||||||
// this.helloRefreshInterval = window.setInterval(() => {
|
|
||||||
// console.log.apply(null, log("wsConnection: Hello refresh.")
|
|
||||||
// if (!navigator.onLine) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// this.sendHello();
|
|
||||||
// }, helloRefreshIntervalPeriod * 1000);
|
|
||||||
// }
|
|
||||||
// this.websocketPingInterval = window.setInterval(() => {
|
|
||||||
// if (!navigator.onLine) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// this.send({ type: "ping", peer_id: this.peerID, peer_name: app.peername, user_id: app.userID, user_name: app.username });
|
|
||||||
// }, 10_000)
|
|
||||||
// };
|
|
||||||
// this.websocket.onclose = (event) => {
|
|
||||||
// console.log.apply(null, log("ws:disconnected"));;
|
|
||||||
// // this.retry *= 2;
|
|
||||||
// console.log.apply(null, log(`Retrying in ${this.retry} seconds`));;
|
|
||||||
// window.setTimeout(() => { this.connect(); }, this.retry * 1000);
|
|
||||||
// };
|
|
||||||
// this.websocket.onmessage = (event) => {
|
|
||||||
// // log('ws:<-' + event.data.slice(0, 240));
|
|
||||||
// let data = JSON.parse(event.data);
|
|
||||||
// let { type } = data;
|
|
||||||
// let handler = this.messageHandlers.get(type);
|
|
||||||
// if (!handler) {
|
|
||||||
// console.warn(`Got a message we can't handle:`, type);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// handler(data);
|
|
||||||
// };
|
|
||||||
// this.websocket.onerror = (event) => {
|
|
||||||
// console.log.apply(null, log('ws:error: ' + event));;
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// disconnect() {
|
|
||||||
// this.websocket?.close();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// Connect websocket
|
// Connect websocket
|
||||||
// send hello
|
// send hello
|
||||||
// get bootstrap peer ID
|
// get bootstrap peer ID
|
||||||
// WebRTC connect to bootstrap peer
|
// WebRTC connect to bootstrap peer
|
||||||
// ask Bootstrap peer for peers that have users we care about.
|
// Bootstrap peer will send the last N peers it saw.
|
||||||
// for now, bootstrap peer will connect to all peers and will tell us about them, moving all logic from the server to the BSP
|
// Connect to those new peers, tell those peers about users we know about
|
||||||
|
// ask for peers that have users we care about
|
||||||
// WebRTC Connect to peers that might have posts we need
|
// WebRTC Connect to peers that might have posts we need
|
||||||
// query those peers and do existing logic.
|
// query those peers and do existing logic.
|
||||||
class wsConnection {
|
class wsConnection {
|
||||||
@@ -231,7 +169,6 @@ class wsConnection {
|
|||||||
this.sessionID = "";
|
this.sessionID = "";
|
||||||
this.userID = "";
|
this.userID = "";
|
||||||
this.peerID = "";
|
this.peerID = "";
|
||||||
this.rtcPeerDescription = null;
|
|
||||||
this.websocketPingInterval = 0;
|
this.websocketPingInterval = 0;
|
||||||
this.helloRefreshInterval = 0;
|
this.helloRefreshInterval = 0;
|
||||||
this.retry = 10;
|
this.retry = 10;
|
||||||
@@ -262,7 +199,7 @@ class wsConnection {
|
|||||||
'5f1b85c4-b14c-454c-8df1-2cacc93f8a77',
|
'5f1b85c4-b14c-454c-8df1-2cacc93f8a77',
|
||||||
// 'bba3ad24-9181-4e22-90c8-c265c80873ea'
|
// 'bba3ad24-9181-4e22-90c8-c265c80873ea'
|
||||||
]);
|
]);
|
||||||
this.rtcPeerDescription = rtcPeerDescription;
|
// this.rtcPeerDescription = rtcPeerDescription;
|
||||||
this.sessionID = generateID();
|
this.sessionID = generateID();
|
||||||
this.userID = userID;
|
this.userID = userID;
|
||||||
this.peerID = peerID;
|
this.peerID = peerID;
|
||||||
@@ -446,9 +383,16 @@ class wsConnection {
|
|||||||
session_id: this.sessionID,
|
session_id: this.sessionID,
|
||||||
peer_name: app.peername,
|
peer_name: app.peername,
|
||||||
is_bootstrap_peer: app.isBootstrapPeer,
|
is_bootstrap_peer: app.isBootstrapPeer,
|
||||||
peer_description: this.rtcPeerDescription
|
// peer_description: this.rtcPeerDescription
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async getKnownUsers() {
|
||||||
|
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
||||||
|
knownUsers = knownUsers
|
||||||
|
.filter(userID => this.shouldSyncUserID(userID))
|
||||||
|
.filter(userID => !this.userBlockList.has(userID))
|
||||||
|
.filter(async (userID) => (await getAllIds(userID)).length > 0); // TODO:EASYOPT getting all the IDs is unecessary, replace it with a test to get a single ID.
|
||||||
|
}
|
||||||
async sendHello() {
|
async sendHello() {
|
||||||
// TODO only get users you're following here. ✅
|
// TODO only get users you're following here. ✅
|
||||||
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
let knownUsers = [...(await indexedDB.databases())].map(db => db.name?.replace('user_', '')).filter(userID => userID !== undefined);
|
||||||
@@ -629,8 +573,11 @@ class App {
|
|||||||
async connect() {
|
async connect() {
|
||||||
this.peerManager = new PeerManager(this.userID, this.peerID, this.isBootstrapPeer);
|
this.peerManager = new PeerManager(this.userID, this.peerID, this.isBootstrapPeer);
|
||||||
this.registerRPCs();
|
this.registerRPCs();
|
||||||
|
this.peerManager.addEventListener(PeerEventTypes.PEER_CONNECTED, (event) => {
|
||||||
|
console.log.apply(null, log(`[app]: peer connected:${event.peerID}`));
|
||||||
|
// rpc saying what peers we have
|
||||||
|
});
|
||||||
console.log.apply(null, log("*************** before peerManager.connect"));
|
console.log.apply(null, log("*************** before peerManager.connect"));
|
||||||
;
|
|
||||||
// We use promises here to only return from this call once we're connected to the boostrap peer
|
// We use promises here to only return from this call once we're connected to the boostrap peer
|
||||||
// and the datachannel is open.
|
// and the datachannel is open.
|
||||||
// Might want to take this a step further and only return once we're connected to an initial set of peers?
|
// Might want to take this a step further and only return once we're connected to an initial set of peers?
|
||||||
|
|||||||
Reference in New Issue
Block a user