systemquery/src/lib/agent/PeerServer.mjs
2021-10-09 18:00:54 +01:00

101 lines
2.5 KiB
JavaScript

"use strict";
import { EventEmitter, once } from 'events';
import net from 'net';
import Connection from '../transport/Connection.mjs';
import Peer from './Peer.mjs';
class PeerServer extends EventEmitter {
constructor(our_id) {
super();
this.our_id = our_id;
this.peers = [];
}
/**
* Starts the PeerServer listening on the given port and bind address.
* @param {Number} [port=5252] The port number to listen on.
* @param {String} [host="::"] The address to bind to.
* @return {Promise<void>} A Promise that resolves when the server setup is complete.
*/
listen(port = 5252, host="::") {
return new Promise((resolve, reject) => {
this.server = net.createServer(async (client) => {
await this.handle_client(client);
});
this.server.once("error", reject);
this.server.on("error", this.handle_error);
this.server.listen({
host,
port,
exclusive: false
}, () => {
this.server.off("error", reject);
resolve();
});
});
}
handle_error(error) {
throw error;
}
async handle_client(client) {
const peer = new Peer(this, await Connection.Wrap(client));
this.peers.push(peer);
peer.on("message", this.handle_message.bind(this, peer));
peer.on("destroy", this.handle_destroy.bind(this, peer));
await once(peer, "connect");
}
async handle_message(peer, message) {
this.emit("message", peer, message);
this.emit(`message-${message.event}`, peer, message.message);
}
async handle_destroy(peer) {
const index = this.peers.indexOf(peer);
if(index > -1)
this.peers.splice(index, 1);
this.emit("disconnect", peer.remote_endpoint);
}
/**
* Returns a list of all currently known peer addresses.
* @return {{address:string,port:number}[]}
*/
peer_addresses() {
return this.peers.map((peer) => peer.remote_endpoint)
.filter(el => typeof el.addr === "string" && typeof el.port === "number");
}
/**
* Shuts the server down.
* This does not disconnect any existing peers!
* @return {Promise} A Promise that resolves once the server has been shutdown.
*/
shutdown_server() {
return new Promise((resolve, _reject) => {
this.server.close(resolve);
});
}
/**
* Stops the PeerServer and gracefully (if possible) disconnects all existing peers.
* @return {Promise} A Promise that resolves once the shutdown process has completed.
*/
async destroy() {
await this.shutdown_server();
await Promise.all(...this.peers.map(peer => peer.destroy()));
}
}
export default PeerServer;