Compare commits
No commits in common. "f8b8633287c45425ba17de7feb3e8f05d876e145" and "22023baedc8c126134d96156c9dba492b275d4c6" have entirely different histories.
f8b8633287
...
22023baedc
|
@ -2,10 +2,6 @@ import Proxy from "./proxy.js";
|
||||||
import Socket from "./socket.js";
|
import Socket from "./socket.js";
|
||||||
import Peer, { DataSocketOptions, PeerOptions, PeerOptionsWithProxy, OnOpen, OnSend, OnReceive, OnClose } from "./peer.js";
|
import Peer, { DataSocketOptions, PeerOptions, PeerOptionsWithProxy, OnOpen, OnSend, OnReceive, OnClose } from "./peer.js";
|
||||||
import Server from "./server.js";
|
import Server from "./server.js";
|
||||||
import DummySocket from "./proxies/multiSocket/dummySocket.js";
|
export { Proxy, Socket, Server, Peer, DataSocketOptions, PeerOptions, PeerOptionsWithProxy, OnOpen, OnSend, OnReceive, OnClose, };
|
||||||
import TcpSocket from "./proxies/multiSocket/tcpSocket.js";
|
|
||||||
import BasicProxy from "./proxies/basic.js";
|
|
||||||
import MultiSocketProxy from "./proxies/multiSocket.js";
|
|
||||||
export { Proxy, Socket, Server, Peer, DataSocketOptions, PeerOptions, PeerOptionsWithProxy, OnOpen, OnSend, OnReceive, OnClose, DummySocket, TcpSocket, BasicProxy, MultiSocketProxy, };
|
|
||||||
export declare function createSocket(port: number, host: string): Socket;
|
export declare function createSocket(port: number, host: string): Socket;
|
||||||
export declare function createServer(): Server;
|
export declare function createServer(): Server;
|
||||||
|
|
|
@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.createServer = exports.createSocket = exports.MultiSocketProxy = exports.BasicProxy = exports.TcpSocket = exports.DummySocket = exports.Peer = exports.Server = exports.Socket = exports.Proxy = void 0;
|
exports.createServer = exports.createSocket = exports.Peer = exports.Server = exports.Socket = exports.Proxy = void 0;
|
||||||
const proxy_js_1 = __importDefault(require("./proxy.js"));
|
const proxy_js_1 = __importDefault(require("./proxy.js"));
|
||||||
exports.Proxy = proxy_js_1.default;
|
exports.Proxy = proxy_js_1.default;
|
||||||
const socket_js_1 = __importDefault(require("./socket.js"));
|
const socket_js_1 = __importDefault(require("./socket.js"));
|
||||||
|
@ -12,14 +12,6 @@ const peer_js_1 = __importDefault(require("./peer.js"));
|
||||||
exports.Peer = peer_js_1.default;
|
exports.Peer = peer_js_1.default;
|
||||||
const server_js_1 = __importDefault(require("./server.js"));
|
const server_js_1 = __importDefault(require("./server.js"));
|
||||||
exports.Server = server_js_1.default;
|
exports.Server = server_js_1.default;
|
||||||
const dummySocket_js_1 = __importDefault(require("./proxies/multiSocket/dummySocket.js"));
|
|
||||||
exports.DummySocket = dummySocket_js_1.default;
|
|
||||||
const tcpSocket_js_1 = __importDefault(require("./proxies/multiSocket/tcpSocket.js"));
|
|
||||||
exports.TcpSocket = tcpSocket_js_1.default;
|
|
||||||
const basic_js_1 = __importDefault(require("./proxies/basic.js"));
|
|
||||||
exports.BasicProxy = basic_js_1.default;
|
|
||||||
const multiSocket_js_1 = __importDefault(require("./proxies/multiSocket.js"));
|
|
||||||
exports.MultiSocketProxy = multiSocket_js_1.default;
|
|
||||||
function createSocket(port, host) {
|
function createSocket(port, host) {
|
||||||
return new socket_js_1.default({
|
return new socket_js_1.default({
|
||||||
remotePort: port,
|
remotePort: port,
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import Proxy from "../proxy.js";
|
|
||||||
export default class BasicProxy extends Proxy {
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
"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"));
|
|
||||||
class BasicProxy extends proxy_js_1.default {
|
|
||||||
}
|
|
||||||
exports.default = BasicProxy;
|
|
|
@ -1,33 +0,0 @@
|
||||||
/// <reference types="node" />
|
|
||||||
import Proxy, { ProxyOptions } from "../proxy.js";
|
|
||||||
import type { TcpSocketConnectOpts } from "net";
|
|
||||||
import Peer from "../peer.js";
|
|
||||||
import { PeerEntity } from "./multiSocket/types.js";
|
|
||||||
export interface MultiSocketProxyOptions extends ProxyOptions {
|
|
||||||
socketClass?: any;
|
|
||||||
server: boolean;
|
|
||||||
allowedPorts?: number[];
|
|
||||||
}
|
|
||||||
export default class MultiSocketProxy extends Proxy {
|
|
||||||
private socketClass;
|
|
||||||
private _peers;
|
|
||||||
private _nextPeer;
|
|
||||||
private _server;
|
|
||||||
private _allowedPorts;
|
|
||||||
constructor(options: MultiSocketProxyOptions);
|
|
||||||
private _socketMap;
|
|
||||||
get socketMap(): Map<number, number>;
|
|
||||||
private _sockets;
|
|
||||||
get sockets(): Map<number, any>;
|
|
||||||
handleNewPeerChannel(peer: Peer, channel: any): void;
|
|
||||||
handleClosePeer(peer: Peer): Promise<void>;
|
|
||||||
get(pubkey: Uint8Array): PeerEntity | undefined;
|
|
||||||
update(pubkey: Uint8Array, data: Partial<PeerEntity>): void;
|
|
||||||
createSocket(options: TcpSocketConnectOpts): Promise<typeof this.socketClass>;
|
|
||||||
private _registerOpenSocketMessage;
|
|
||||||
private _registerWriteSocketMessage;
|
|
||||||
private _registerCloseSocketMessage;
|
|
||||||
private _registerTimeoutSocketMessage;
|
|
||||||
private _registerErrorSocketMessage;
|
|
||||||
private _toString;
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
"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,
|
|
||||||
});
|
|
||||||
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;
|
|
|
@ -1,20 +0,0 @@
|
||||||
/// <reference types="node" />
|
|
||||||
import { Callback, Duplex } from "streamx";
|
|
||||||
import { TcpSocketConnectOpts } from "net";
|
|
||||||
import MultiSocketProxy from "../multiSocket.js";
|
|
||||||
import { PeerEntity } from "./types.js";
|
|
||||||
export default class DummySocket extends Duplex {
|
|
||||||
private _options;
|
|
||||||
private _id;
|
|
||||||
private _proxy;
|
|
||||||
private _connectTimeout?;
|
|
||||||
constructor(id: number, manager: MultiSocketProxy, peer: PeerEntity, options: TcpSocketConnectOpts);
|
|
||||||
private _remoteId;
|
|
||||||
set remoteId(value: number);
|
|
||||||
private _peer;
|
|
||||||
get peer(): any;
|
|
||||||
_write(data: any, cb: any): Promise<void>;
|
|
||||||
_destroy(cb: Callback): Promise<void>;
|
|
||||||
connect(): Promise<void>;
|
|
||||||
setTimeout(ms: number, cb: Function): void;
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const streamx_1 = require("streamx");
|
|
||||||
const timers_1 = require("timers");
|
|
||||||
const util_js_1 = require("../../util.js");
|
|
||||||
class DummySocket extends streamx_1.Duplex {
|
|
||||||
_options;
|
|
||||||
_id;
|
|
||||||
_proxy;
|
|
||||||
_connectTimeout;
|
|
||||||
constructor(id, manager, peer, options) {
|
|
||||||
super();
|
|
||||||
this._id = id;
|
|
||||||
this._proxy = manager;
|
|
||||||
this._peer = peer;
|
|
||||||
this._options = options;
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("timeout", () => {
|
|
||||||
if (this._connectTimeout) {
|
|
||||||
(0, timers_1.clearTimeout)(this._connectTimeout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_remoteId = 0;
|
|
||||||
set remoteId(value) {
|
|
||||||
this._remoteId = value;
|
|
||||||
this._proxy.socketMap.set(this._id, value);
|
|
||||||
}
|
|
||||||
_peer;
|
|
||||||
get peer() {
|
|
||||||
return this._peer;
|
|
||||||
}
|
|
||||||
async _write(data, cb) {
|
|
||||||
(await (0, util_js_1.maybeGetAsyncProperty)(this._peer.messages.writeSocket))?.send({
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
async _destroy(cb) {
|
|
||||||
(await (0, util_js_1.maybeGetAsyncProperty)(this._peer.messages.closeSocket))?.send({
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
});
|
|
||||||
this._proxy.socketMap.delete(this._id);
|
|
||||||
this._proxy.sockets.delete(this._id);
|
|
||||||
}
|
|
||||||
async connect() {
|
|
||||||
(await (0, util_js_1.maybeGetAsyncProperty)(this._peer.messages.openSocket))?.send({
|
|
||||||
...this._options,
|
|
||||||
id: this._id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setTimeout(ms, cb) {
|
|
||||||
if (this._connectTimeout) {
|
|
||||||
(0, timers_1.clearTimeout)(this._connectTimeout);
|
|
||||||
}
|
|
||||||
this._connectTimeout = setTimeout(() => {
|
|
||||||
cb && cb();
|
|
||||||
}, ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.default = DummySocket;
|
|
|
@ -1,19 +0,0 @@
|
||||||
/// <reference types="node" />
|
|
||||||
import { Callback, Duplex } from "streamx";
|
|
||||||
import { TcpSocketConnectOpts } from "net";
|
|
||||||
import MultiSocketProxy from "../multiSocket.js";
|
|
||||||
import { PeerEntity } from "./types.js";
|
|
||||||
export default class TcpSocket extends Duplex {
|
|
||||||
private _options;
|
|
||||||
private _id;
|
|
||||||
private _remoteId;
|
|
||||||
private _proxy;
|
|
||||||
private _socket?;
|
|
||||||
constructor(id: number, remoteId: number, manager: MultiSocketProxy, peer: PeerEntity, options: TcpSocketConnectOpts);
|
|
||||||
private _peer;
|
|
||||||
get peer(): any;
|
|
||||||
_write(data: any, cb: any): void;
|
|
||||||
_destroy(cb: Callback): void;
|
|
||||||
connect(): void;
|
|
||||||
private _getSocketRequest;
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
"use strict";
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
const streamx_1 = require("streamx");
|
|
||||||
const net = __importStar(require("net"));
|
|
||||||
class TcpSocket extends streamx_1.Duplex {
|
|
||||||
_options;
|
|
||||||
_id;
|
|
||||||
_remoteId;
|
|
||||||
_proxy;
|
|
||||||
_socket;
|
|
||||||
constructor(id, remoteId, manager, peer, options) {
|
|
||||||
super();
|
|
||||||
this._remoteId = remoteId;
|
|
||||||
this._proxy = manager;
|
|
||||||
this._id = id;
|
|
||||||
this._peer = peer;
|
|
||||||
this._options = options;
|
|
||||||
this._proxy.sockets.set(this._id, this);
|
|
||||||
this._proxy.socketMap.set(this._id, this._remoteId);
|
|
||||||
}
|
|
||||||
_peer;
|
|
||||||
get peer() {
|
|
||||||
return this._peer;
|
|
||||||
}
|
|
||||||
_write(data, cb) {
|
|
||||||
this._peer.messages.writeSocket?.send({
|
|
||||||
...this._getSocketRequest(),
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
_destroy(cb) {
|
|
||||||
this._proxy.sockets.delete(this._id);
|
|
||||||
this._proxy.socketMap.delete(this._id);
|
|
||||||
this._peer.messages.closeSocket?.send(this._getSocketRequest());
|
|
||||||
}
|
|
||||||
connect() {
|
|
||||||
this.on("error", (err) => {
|
|
||||||
this._peer.messages.errorSocket?.send({
|
|
||||||
...this._getSocketRequest(),
|
|
||||||
err,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("timeout", () => {
|
|
||||||
this._peer.messages.timeoutSocket?.send(this._getSocketRequest());
|
|
||||||
});
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("connect", () => {
|
|
||||||
this._peer.messages.openSocket?.send(this._getSocketRequest());
|
|
||||||
});
|
|
||||||
this._socket = net.connect(this._options);
|
|
||||||
["timeout", "error", "connect", "end", "destroy", "close"].forEach((event) => {
|
|
||||||
this._socket?.on(event, (...args) => this.emit(event, ...args));
|
|
||||||
});
|
|
||||||
this._socket.pipe(this);
|
|
||||||
this.pipe(this._socket);
|
|
||||||
}
|
|
||||||
_getSocketRequest() {
|
|
||||||
return {
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.default = TcpSocket;
|
|
|
@ -1,28 +0,0 @@
|
||||||
import Peer from "../../peer.js";
|
|
||||||
export interface SocketRequest {
|
|
||||||
remoteId: number;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
export type CloseSocketRequest = SocketRequest;
|
|
||||||
export interface WriteSocketRequest extends SocketRequest {
|
|
||||||
data: Uint8Array;
|
|
||||||
}
|
|
||||||
export interface ErrorSocketRequest extends SocketRequest {
|
|
||||||
err: Error;
|
|
||||||
}
|
|
||||||
type Message = {
|
|
||||||
send: (pubkey: Uint8Array | any) => void;
|
|
||||||
};
|
|
||||||
export interface PeerEntityMessages {
|
|
||||||
keyExchange: Message;
|
|
||||||
openSocket: Message;
|
|
||||||
writeSocket: Message;
|
|
||||||
closeSocket: Message;
|
|
||||||
timeoutSocket: Message;
|
|
||||||
errorSocket: Message;
|
|
||||||
}
|
|
||||||
export interface PeerEntity {
|
|
||||||
messages: PeerEntityMessages | Partial<PeerEntityMessages>;
|
|
||||||
peer: Peer;
|
|
||||||
}
|
|
||||||
export {};
|
|
|
@ -1,2 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
@ -5,7 +5,7 @@ export interface ProxyOptions extends DataSocketOptions {
|
||||||
listen?: boolean;
|
listen?: boolean;
|
||||||
autostart?: boolean;
|
autostart?: boolean;
|
||||||
}
|
}
|
||||||
export default abstract class Proxy {
|
export default class Proxy {
|
||||||
private _listen;
|
private _listen;
|
||||||
private _socketOptions;
|
private _socketOptions;
|
||||||
private _autostart;
|
private _autostart;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export declare function idFactory(start: number, step?: number, limit?: number): () => number;
|
|
||||||
export declare function roundRobinFactory<T>(list: Map<string, any>): () => T;
|
|
||||||
export declare function maybeGetAsyncProperty(object: any): Promise<any>;
|
|
||||||
export declare function isPromise(obj: Promise<any>): boolean;
|
|
|
@ -1,41 +0,0 @@
|
||||||
"use strict";
|
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
|
||||||
exports.isPromise = exports.maybeGetAsyncProperty = exports.roundRobinFactory = exports.idFactory = void 0;
|
|
||||||
function idFactory(start, step = 1, limit = 2 ** 32) {
|
|
||||||
let id = start;
|
|
||||||
return function nextId() {
|
|
||||||
const nextId = id;
|
|
||||||
id += step;
|
|
||||||
if (id >= limit)
|
|
||||||
id = start;
|
|
||||||
return nextId;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
exports.idFactory = idFactory;
|
|
||||||
function roundRobinFactory(list) {
|
|
||||||
let index = 0;
|
|
||||||
return () => {
|
|
||||||
const keys = [...list.keys()].sort();
|
|
||||||
if (index >= keys.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
return list.get(keys[index++]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
exports.roundRobinFactory = roundRobinFactory;
|
|
||||||
async function maybeGetAsyncProperty(object) {
|
|
||||||
if (typeof object === "function") {
|
|
||||||
object = object();
|
|
||||||
}
|
|
||||||
if (isPromise(object)) {
|
|
||||||
object = await object;
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
exports.maybeGetAsyncProperty = maybeGetAsyncProperty;
|
|
||||||
function isPromise(obj) {
|
|
||||||
return (!!obj &&
|
|
||||||
(typeof obj === "object" || typeof obj === "function") &&
|
|
||||||
typeof obj.then === "function");
|
|
||||||
}
|
|
||||||
exports.isPromise = isPromise;
|
|
|
@ -3,18 +3,15 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/b4a": "^1.6.0",
|
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"@types/streamx": "^2.9.1",
|
"@types/streamx": "^2.9.1",
|
||||||
"prettier": "^2.8.2",
|
"prettier": "^2.8.2",
|
||||||
"typescript": "^4.9.4"
|
"typescript": "^4.9.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"b4a": "^1.6.3",
|
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"compact-encoding": "^2.11.0",
|
"compact-encoding": "^2.11.0",
|
||||||
"protomux": "^3.4.0",
|
"protomux": "^3.4.0",
|
||||||
"serialize-error": "^11.0.0",
|
|
||||||
"streamx": "^2.13.0"
|
"streamx": "^2.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,6 @@ import Peer, {
|
||||||
OnClose,
|
OnClose,
|
||||||
} from "./peer.js";
|
} from "./peer.js";
|
||||||
import Server from "./server.js";
|
import Server from "./server.js";
|
||||||
import DummySocket from "./proxies/multiSocket/dummySocket.js";
|
|
||||||
import TcpSocket from "./proxies/multiSocket/tcpSocket.js";
|
|
||||||
import BasicProxy from "./proxies/basic.js";
|
|
||||||
import MultiSocketProxy from "./proxies/multiSocket.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Proxy,
|
Proxy,
|
||||||
|
@ -27,10 +23,6 @@ export {
|
||||||
OnSend,
|
OnSend,
|
||||||
OnReceive,
|
OnReceive,
|
||||||
OnClose,
|
OnClose,
|
||||||
DummySocket,
|
|
||||||
TcpSocket,
|
|
||||||
BasicProxy,
|
|
||||||
MultiSocketProxy,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createSocket(port: number, host: string): Socket {
|
export function createSocket(port: number, host: string): Socket {
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
import Proxy from "../proxy.js";
|
|
||||||
|
|
||||||
export default class BasicProxy extends Proxy {}
|
|
|
@ -1,276 +0,0 @@
|
||||||
import Proxy, { ProxyOptions } from "../proxy.js";
|
|
||||||
import TcpSocket from "./multiSocket/tcpSocket.js";
|
|
||||||
import { json, raw, uint } from "compact-encoding";
|
|
||||||
import { deserializeError } from "serialize-error";
|
|
||||||
import b4a from "b4a";
|
|
||||||
import type { TcpSocketConnectOpts } from "net";
|
|
||||||
import Peer from "../peer.js";
|
|
||||||
import { roundRobinFactory, idFactory } from "../util.js";
|
|
||||||
import {
|
|
||||||
CloseSocketRequest,
|
|
||||||
ErrorSocketRequest,
|
|
||||||
PeerEntity,
|
|
||||||
SocketRequest,
|
|
||||||
WriteSocketRequest,
|
|
||||||
} from "./multiSocket/types.js";
|
|
||||||
import DummySocket from "./multiSocket/dummySocket.js";
|
|
||||||
|
|
||||||
export interface MultiSocketProxyOptions extends ProxyOptions {
|
|
||||||
socketClass?: any;
|
|
||||||
server: boolean;
|
|
||||||
allowedPorts?: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const socketEncoding = {
|
|
||||||
preencode(state: any, m: SocketRequest) {
|
|
||||||
uint.preencode(state, m.id);
|
|
||||||
uint.preencode(state, m.remoteId);
|
|
||||||
},
|
|
||||||
encode(state: any, m: SocketRequest) {
|
|
||||||
uint.encode(state, m.id);
|
|
||||||
uint.encode(state, m.remoteId);
|
|
||||||
},
|
|
||||||
decode(state: any, m: any): SocketRequest {
|
|
||||||
return {
|
|
||||||
remoteId: uint.decode(state, m),
|
|
||||||
id: uint.decode(state, m),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const writeSocketEncoding = {
|
|
||||||
preencode(state: any, m: WriteSocketRequest) {
|
|
||||||
socketEncoding.preencode(state, m);
|
|
||||||
raw.preencode(state, m.data);
|
|
||||||
},
|
|
||||||
encode(state: any, m: WriteSocketRequest) {
|
|
||||||
socketEncoding.encode(state, m);
|
|
||||||
raw.encode(state, m.data);
|
|
||||||
},
|
|
||||||
decode(state: any, m: any): WriteSocketRequest {
|
|
||||||
const socket = socketEncoding.decode(state, m);
|
|
||||||
return {
|
|
||||||
...socket,
|
|
||||||
data: raw.decode(state, m),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const errorSocketEncoding = {
|
|
||||||
decode(state: any, m: any): ErrorSocketRequest {
|
|
||||||
const socket = socketEncoding.decode(state, m);
|
|
||||||
return {
|
|
||||||
...socket,
|
|
||||||
err: deserializeError(json.decode(state, m)),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const nextSocketId = idFactory(1);
|
|
||||||
|
|
||||||
export default class MultiSocketProxy extends Proxy {
|
|
||||||
private socketClass: any;
|
|
||||||
private _peers: Map<string, PeerEntity> = new Map<string, PeerEntity>();
|
|
||||||
private _nextPeer = roundRobinFactory(this._peers);
|
|
||||||
private _server = false;
|
|
||||||
private _allowedPorts = [];
|
|
||||||
|
|
||||||
constructor(options: MultiSocketProxyOptions) {
|
|
||||||
super({
|
|
||||||
createDefaultMessage: false,
|
|
||||||
...options,
|
|
||||||
});
|
|
||||||
if (options.socketClass) {
|
|
||||||
this.socketClass = options.socketClass;
|
|
||||||
} else {
|
|
||||||
if (options.server) {
|
|
||||||
this.socketClass = TcpSocket;
|
|
||||||
} else {
|
|
||||||
this.socketClass = DummySocket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.server) {
|
|
||||||
this._server = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _socketMap = new Map<number, number>();
|
|
||||||
|
|
||||||
get socketMap(): Map<number, number> {
|
|
||||||
return this._socketMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sockets = new Map<number, typeof this.socketClass>();
|
|
||||||
|
|
||||||
get sockets(): Map<number, any> {
|
|
||||||
return this._sockets;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleNewPeerChannel(peer: Peer, channel: any) {
|
|
||||||
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: 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(pubkey: Uint8Array): PeerEntity | undefined {
|
|
||||||
if (this._peers.has(this._toString(pubkey))) {
|
|
||||||
return this._peers.get(this._toString(pubkey)) as PeerEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(pubkey: Uint8Array, data: Partial<PeerEntity>): void {
|
|
||||||
const peer = this.get(pubkey) ?? ({} as PeerEntity);
|
|
||||||
|
|
||||||
this._peers.set(this._toString(pubkey), {
|
|
||||||
...peer,
|
|
||||||
...data,
|
|
||||||
...{
|
|
||||||
messages: {
|
|
||||||
...peer?.messages,
|
|
||||||
...data?.messages,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as PeerEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async createSocket(
|
|
||||||
options: TcpSocketConnectOpts
|
|
||||||
): Promise<typeof this.socketClass> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerOpenSocketMessage(peer: Peer, channel: any) {
|
|
||||||
const self = this;
|
|
||||||
const message = channel.addMessage({
|
|
||||||
encoding: {
|
|
||||||
preencode: json.preencode,
|
|
||||||
encode: json.encode,
|
|
||||||
decode: this._server ? json.encode : socketEncoding.decode,
|
|
||||||
},
|
|
||||||
async onmessage(m: SocketRequest | TcpSocketConnectOpts) {
|
|
||||||
if (
|
|
||||||
self._allowedPorts.length &&
|
|
||||||
!self._allowedPorts.includes((m as TcpSocketConnectOpts).port)
|
|
||||||
) {
|
|
||||||
self.get(peer.socket.remotePublicKey).messages.errorSocket.send({
|
|
||||||
id: (m as SocketRequest).id,
|
|
||||||
err: new Error(
|
|
||||||
`port ${(m as TcpSocketConnectOpts).port} not allowed`
|
|
||||||
),
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m = m as SocketRequest;
|
|
||||||
|
|
||||||
if (self._server) {
|
|
||||||
new self.socketClass(
|
|
||||||
nextSocketId(),
|
|
||||||
m,
|
|
||||||
self,
|
|
||||||
self.get(peer.socket.remotePublicKey) as PeerEntity,
|
|
||||||
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 },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerWriteSocketMessage(peer: Peer, channel: any) {
|
|
||||||
const self = this;
|
|
||||||
const message = channel.addMessage({
|
|
||||||
encoding: writeSocketEncoding,
|
|
||||||
onmessage(m: WriteSocketRequest) {
|
|
||||||
self._sockets.get(m.id)?.push(m.data);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.update(peer.socket.remotePublicKey, {
|
|
||||||
messages: { writeSocket: message },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerCloseSocketMessage(peer: Peer, channel: any) {
|
|
||||||
const self = this;
|
|
||||||
const message = channel.addMessage({
|
|
||||||
encoding: socketEncoding,
|
|
||||||
onmessage(m: CloseSocketRequest) {
|
|
||||||
self._sockets.get(m.id)?.end();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.update(peer.socket.remotePublicKey, {
|
|
||||||
messages: { closeSocket: message },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerTimeoutSocketMessage(peer: Peer, channel: any) {
|
|
||||||
const self = this;
|
|
||||||
const message = channel.addMessage({
|
|
||||||
encoding: socketEncoding,
|
|
||||||
onmessage(m: SocketRequest) {
|
|
||||||
// @ts-ignore
|
|
||||||
self._sockets.get(m.id)?.emit("timeout");
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.update(peer.socket.remotePublicKey, {
|
|
||||||
messages: { timeoutSocket: message },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _registerErrorSocketMessage(peer: Peer, channel: any) {
|
|
||||||
const self = this;
|
|
||||||
const message = channel.addMessage({
|
|
||||||
encoding: errorSocketEncoding,
|
|
||||||
onmessage(m: ErrorSocketRequest) {
|
|
||||||
// @ts-ignore
|
|
||||||
self._sockets.get(m.id)?.emit("error", m.err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
this.update(peer.socket.remotePublicKey, {
|
|
||||||
messages: { errorSocket: message },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toString(pubkey: Uint8Array) {
|
|
||||||
return b4a.from(pubkey).toString("hex");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
import { Callback, Duplex } from "streamx";
|
|
||||||
import { TcpSocketConnectOpts } from "net";
|
|
||||||
import { clearTimeout } from "timers";
|
|
||||||
import MultiSocketProxy from "../multiSocket.js";
|
|
||||||
import { PeerEntity, SocketRequest, WriteSocketRequest } from "./types.js";
|
|
||||||
import { maybeGetAsyncProperty } from "../../util.js";
|
|
||||||
|
|
||||||
export default class DummySocket extends Duplex {
|
|
||||||
private _options: TcpSocketConnectOpts;
|
|
||||||
private _id: number;
|
|
||||||
private _proxy: MultiSocketProxy;
|
|
||||||
|
|
||||||
private _connectTimeout?: number;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
id: number,
|
|
||||||
manager: MultiSocketProxy,
|
|
||||||
peer: PeerEntity,
|
|
||||||
options: TcpSocketConnectOpts
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this._id = id;
|
|
||||||
this._proxy = manager;
|
|
||||||
this._peer = peer;
|
|
||||||
this._options = options;
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("timeout", () => {
|
|
||||||
if (this._connectTimeout) {
|
|
||||||
clearTimeout(this._connectTimeout);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _remoteId = 0;
|
|
||||||
|
|
||||||
set remoteId(value: number) {
|
|
||||||
this._remoteId = value;
|
|
||||||
this._proxy.socketMap.set(this._id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _peer;
|
|
||||||
|
|
||||||
get peer() {
|
|
||||||
return this._peer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async _write(data: any, cb: any): Promise<void> {
|
|
||||||
(await maybeGetAsyncProperty(this._peer.messages.writeSocket))?.send({
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
data,
|
|
||||||
} as WriteSocketRequest);
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async _destroy(cb: Callback) {
|
|
||||||
(await maybeGetAsyncProperty(this._peer.messages.closeSocket))?.send({
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
} as SocketRequest);
|
|
||||||
this._proxy.socketMap.delete(this._id);
|
|
||||||
this._proxy.sockets.delete(this._id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async connect() {
|
|
||||||
(await maybeGetAsyncProperty(this._peer.messages.openSocket))?.send({
|
|
||||||
...this._options,
|
|
||||||
id: this._id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public setTimeout(ms: number, cb: Function) {
|
|
||||||
if (this._connectTimeout) {
|
|
||||||
clearTimeout(this._connectTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._connectTimeout = setTimeout(() => {
|
|
||||||
cb && cb();
|
|
||||||
}, ms) as any;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
import { Callback, Duplex } from "streamx";
|
|
||||||
import { Socket, TcpSocketConnectOpts } from "net";
|
|
||||||
import MultiSocketProxy from "../multiSocket.js";
|
|
||||||
import { PeerEntity, SocketRequest, WriteSocketRequest } from "./types.js";
|
|
||||||
import * as net from "net";
|
|
||||||
|
|
||||||
export default class TcpSocket extends Duplex {
|
|
||||||
private _options;
|
|
||||||
private _id: number;
|
|
||||||
private _remoteId: number;
|
|
||||||
private _proxy: MultiSocketProxy;
|
|
||||||
|
|
||||||
private _socket?: Socket;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
id: number,
|
|
||||||
remoteId: number,
|
|
||||||
manager: MultiSocketProxy,
|
|
||||||
peer: PeerEntity,
|
|
||||||
options: TcpSocketConnectOpts
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this._remoteId = remoteId;
|
|
||||||
this._proxy = manager;
|
|
||||||
this._id = id;
|
|
||||||
this._peer = peer;
|
|
||||||
this._options = options;
|
|
||||||
|
|
||||||
this._proxy.sockets.set(this._id, this);
|
|
||||||
this._proxy.socketMap.set(this._id, this._remoteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _peer;
|
|
||||||
|
|
||||||
get peer() {
|
|
||||||
return this._peer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public _write(data: any, cb: any): void {
|
|
||||||
this._peer.messages.writeSocket?.send({
|
|
||||||
...this._getSocketRequest(),
|
|
||||||
data,
|
|
||||||
} as WriteSocketRequest);
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
public _destroy(cb: Callback) {
|
|
||||||
this._proxy.sockets.delete(this._id);
|
|
||||||
this._proxy.socketMap.delete(this._id);
|
|
||||||
this._peer.messages.closeSocket?.send(this._getSocketRequest());
|
|
||||||
}
|
|
||||||
|
|
||||||
public connect() {
|
|
||||||
this.on("error", (err: Error) => {
|
|
||||||
this._peer.messages.errorSocket?.send({
|
|
||||||
...this._getSocketRequest(),
|
|
||||||
err,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("timeout", () => {
|
|
||||||
this._peer.messages.timeoutSocket?.send(this._getSocketRequest());
|
|
||||||
});
|
|
||||||
// @ts-ignore
|
|
||||||
this.on("connect", () => {
|
|
||||||
this._peer.messages.openSocket?.send(this._getSocketRequest());
|
|
||||||
});
|
|
||||||
|
|
||||||
this._socket = net.connect(this._options);
|
|
||||||
["timeout", "error", "connect", "end", "destroy", "close"].forEach(
|
|
||||||
(event) => {
|
|
||||||
this._socket?.on(event, (...args: any) =>
|
|
||||||
this.emit(event as any, ...args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
this._socket.pipe(this as any);
|
|
||||||
this.pipe(this._socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getSocketRequest(): SocketRequest {
|
|
||||||
return {
|
|
||||||
id: this._id,
|
|
||||||
remoteId: this._remoteId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
import { ProxyOptions } from "../../proxy.js";
|
|
||||||
import Peer from "../../peer.js";
|
|
||||||
|
|
||||||
export interface SocketRequest {
|
|
||||||
remoteId: number;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CloseSocketRequest = SocketRequest;
|
|
||||||
|
|
||||||
export interface WriteSocketRequest extends SocketRequest {
|
|
||||||
data: Uint8Array;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ErrorSocketRequest extends SocketRequest {
|
|
||||||
err: Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
type Message = {
|
|
||||||
send: (pubkey: Uint8Array | any) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface PeerEntityMessages {
|
|
||||||
keyExchange: Message;
|
|
||||||
openSocket: Message;
|
|
||||||
writeSocket: Message;
|
|
||||||
closeSocket: Message;
|
|
||||||
timeoutSocket: Message;
|
|
||||||
errorSocket: Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PeerEntity {
|
|
||||||
messages: PeerEntityMessages | Partial<PeerEntityMessages>;
|
|
||||||
peer: Peer;
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ export interface ProxyOptions extends DataSocketOptions {
|
||||||
autostart?: boolean;
|
autostart?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default abstract class Proxy {
|
export default class Proxy {
|
||||||
private _listen: any;
|
private _listen: any;
|
||||||
private _socketOptions: DataSocketOptions;
|
private _socketOptions: DataSocketOptions;
|
||||||
private _autostart: boolean;
|
private _autostart: boolean;
|
||||||
|
|
40
src/util.ts
40
src/util.ts
|
@ -1,40 +0,0 @@
|
||||||
export function idFactory(start: number, step = 1, limit = 2 ** 32) {
|
|
||||||
let id = start;
|
|
||||||
|
|
||||||
return function nextId() {
|
|
||||||
const nextId = id;
|
|
||||||
id += step;
|
|
||||||
if (id >= limit) id = start;
|
|
||||||
return nextId;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function roundRobinFactory<T>(list: Map<string, any>) {
|
|
||||||
let index = 0;
|
|
||||||
|
|
||||||
return (): T => {
|
|
||||||
const keys = [...list.keys()].sort();
|
|
||||||
if (index >= keys.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.get(keys[index++]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export async function maybeGetAsyncProperty(object: any) {
|
|
||||||
if (typeof object === "function") {
|
|
||||||
object = object();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPromise(object)) {
|
|
||||||
object = await object;
|
|
||||||
}
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
export function isPromise(obj: Promise<any>) {
|
|
||||||
return (
|
|
||||||
!!obj &&
|
|
||||||
(typeof obj === "object" || typeof obj === "function") &&
|
|
||||||
typeof obj.then === "function"
|
|
||||||
);
|
|
||||||
}
|
|
Loading…
Reference in New Issue