230 lines
7.6 KiB
JavaScript
230 lines
7.6 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const proxy_js_1 = __importDefault(require("../proxy.js"));
|
|
const tcpSocket_js_1 = __importDefault(require("./multiSocket/tcpSocket.js"));
|
|
const compact_encoding_1 = require("compact-encoding");
|
|
const serialize_error_1 = require("serialize-error");
|
|
const b4a_1 = __importDefault(require("b4a"));
|
|
const util_js_1 = require("../util.js");
|
|
const dummySocket_js_1 = __importDefault(require("./multiSocket/dummySocket.js"));
|
|
const socketEncoding = {
|
|
preencode(state, m) {
|
|
compact_encoding_1.uint.preencode(state, m.id);
|
|
compact_encoding_1.uint.preencode(state, m.remoteId);
|
|
},
|
|
encode(state, m) {
|
|
compact_encoding_1.uint.encode(state, m.id);
|
|
compact_encoding_1.uint.encode(state, m.remoteId);
|
|
},
|
|
decode(state, m) {
|
|
return {
|
|
remoteId: compact_encoding_1.uint.decode(state, m),
|
|
id: compact_encoding_1.uint.decode(state, m),
|
|
};
|
|
},
|
|
};
|
|
const writeSocketEncoding = {
|
|
preencode(state, m) {
|
|
socketEncoding.preencode(state, m);
|
|
compact_encoding_1.raw.preencode(state, m.data);
|
|
},
|
|
encode(state, m) {
|
|
socketEncoding.encode(state, m);
|
|
compact_encoding_1.raw.encode(state, m.data);
|
|
},
|
|
decode(state, m) {
|
|
const socket = socketEncoding.decode(state, m);
|
|
return {
|
|
...socket,
|
|
data: compact_encoding_1.raw.decode(state, m),
|
|
};
|
|
},
|
|
};
|
|
const errorSocketEncoding = {
|
|
decode(state, m) {
|
|
const socket = socketEncoding.decode(state, m);
|
|
return {
|
|
...socket,
|
|
err: (0, serialize_error_1.deserializeError)(compact_encoding_1.json.decode(state, m)),
|
|
};
|
|
},
|
|
};
|
|
const nextSocketId = (0, util_js_1.idFactory)(1);
|
|
class MultiSocketProxy extends proxy_js_1.default {
|
|
socketClass;
|
|
_peers = new Map();
|
|
_nextPeer = (0, util_js_1.roundRobinFactory)(this._peers);
|
|
_server = false;
|
|
_allowedPorts = [];
|
|
constructor(options) {
|
|
super({
|
|
createDefaultMessage: false,
|
|
...options,
|
|
});
|
|
this._socketOptions.onchannel = this.handleNewPeerChannel.bind(this);
|
|
this._socketOptions.onclose = this.handleClosePeer.bind(this);
|
|
this._socketOptions.onopen = this.handlePeer.bind(this);
|
|
if (options.socketClass) {
|
|
this.socketClass = options.socketClass;
|
|
}
|
|
else {
|
|
if (options.server) {
|
|
this.socketClass = tcpSocket_js_1.default;
|
|
}
|
|
else {
|
|
this.socketClass = dummySocket_js_1.default;
|
|
}
|
|
}
|
|
if (options.server) {
|
|
this._server = true;
|
|
}
|
|
}
|
|
_socketMap = new Map();
|
|
get socketMap() {
|
|
return this._socketMap;
|
|
}
|
|
_sockets = new Map();
|
|
get sockets() {
|
|
return this._sockets;
|
|
}
|
|
handleNewPeerChannel(peer, channel) {
|
|
this.update(peer.socket.remotePublicKey, { peer });
|
|
this._registerOpenSocketMessage(peer, channel);
|
|
this._registerWriteSocketMessage(peer, channel);
|
|
this._registerCloseSocketMessage(peer, channel);
|
|
this._registerTimeoutSocketMessage(peer, channel);
|
|
this._registerErrorSocketMessage(peer, channel);
|
|
}
|
|
async handleClosePeer(peer) {
|
|
for (const item of this._sockets) {
|
|
if (item[1].peer.peer === peer) {
|
|
item[1].end();
|
|
}
|
|
}
|
|
const pubkey = this._toString(peer.socket.remotePublicKey);
|
|
if (this._peers.has(pubkey)) {
|
|
this._peers.delete(pubkey);
|
|
}
|
|
}
|
|
get(pubkey) {
|
|
if (this._peers.has(this._toString(pubkey))) {
|
|
return this._peers.get(this._toString(pubkey));
|
|
}
|
|
return undefined;
|
|
}
|
|
update(pubkey, data) {
|
|
const peer = this.get(pubkey) ?? {};
|
|
this._peers.set(this._toString(pubkey), {
|
|
...peer,
|
|
...data,
|
|
...{
|
|
messages: {
|
|
...peer?.messages,
|
|
...data?.messages,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
async createSocket(options) {
|
|
if (!this._peers.size) {
|
|
throw new Error("no peers found");
|
|
}
|
|
const peer = this._nextPeer();
|
|
const socketId = nextSocketId();
|
|
const socket = new this.socketClass(socketId, this, peer, options);
|
|
this._sockets.set(socketId, socket);
|
|
return socket;
|
|
}
|
|
_registerOpenSocketMessage(peer, channel) {
|
|
const self = this;
|
|
const message = channel.addMessage({
|
|
encoding: {
|
|
preencode: compact_encoding_1.json.preencode,
|
|
encode: compact_encoding_1.json.encode,
|
|
decode: this._server ? compact_encoding_1.json.encode : socketEncoding.decode,
|
|
},
|
|
async onmessage(m) {
|
|
if (self._allowedPorts.length &&
|
|
!self._allowedPorts.includes(m.port)) {
|
|
self.get(peer.socket.remotePublicKey).messages.errorSocket.send({
|
|
id: m.id,
|
|
err: new Error(`port ${m.port} not allowed`),
|
|
});
|
|
return;
|
|
}
|
|
m = m;
|
|
if (self._server) {
|
|
new self.socketClass(nextSocketId(), m, self, self.get(peer.socket.remotePublicKey), m).connect();
|
|
return;
|
|
}
|
|
const socket = self._sockets.get(m.id);
|
|
if (socket) {
|
|
socket.remoteId = m.remoteId;
|
|
// @ts-ignore
|
|
socket.emit("connect");
|
|
}
|
|
},
|
|
});
|
|
this.update(peer.socket.remotePublicKey, {
|
|
messages: { openSocket: message },
|
|
});
|
|
}
|
|
_registerWriteSocketMessage(peer, channel) {
|
|
const self = this;
|
|
const message = channel.addMessage({
|
|
encoding: writeSocketEncoding,
|
|
onmessage(m) {
|
|
self._sockets.get(m.id)?.push(m.data);
|
|
},
|
|
});
|
|
this.update(peer.socket.remotePublicKey, {
|
|
messages: { writeSocket: message },
|
|
});
|
|
}
|
|
_registerCloseSocketMessage(peer, channel) {
|
|
const self = this;
|
|
const message = channel.addMessage({
|
|
encoding: socketEncoding,
|
|
onmessage(m) {
|
|
self._sockets.get(m.id)?.end();
|
|
},
|
|
});
|
|
this.update(peer.socket.remotePublicKey, {
|
|
messages: { closeSocket: message },
|
|
});
|
|
}
|
|
_registerTimeoutSocketMessage(peer, channel) {
|
|
const self = this;
|
|
const message = channel.addMessage({
|
|
encoding: socketEncoding,
|
|
onmessage(m) {
|
|
// @ts-ignore
|
|
self._sockets.get(m.id)?.emit("timeout");
|
|
},
|
|
});
|
|
this.update(peer.socket.remotePublicKey, {
|
|
messages: { timeoutSocket: message },
|
|
});
|
|
}
|
|
_registerErrorSocketMessage(peer, channel) {
|
|
const self = this;
|
|
const message = channel.addMessage({
|
|
encoding: errorSocketEncoding,
|
|
onmessage(m) {
|
|
// @ts-ignore
|
|
self._sockets.get(m.id)?.emit("error", m.err);
|
|
},
|
|
});
|
|
this.update(peer.socket.remotePublicKey, {
|
|
messages: { errorSocket: message },
|
|
});
|
|
}
|
|
_toString(pubkey) {
|
|
return b4a_1.default.from(pubkey).toString("hex");
|
|
}
|
|
}
|
|
exports.default = MultiSocketProxy;
|