mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
62 lines
2.1 KiB
TypeScript
62 lines
2.1 KiB
TypeScript
|
import {Server, Socket} from 'net';
|
||
|
import {connect as connectSock, getAvailablePort, listenPromise} from 'app/server/lib/serverUtils';
|
||
|
|
||
|
// We'll test reconnects by making a connection through this TcpForwarder, which we'll use to
|
||
|
// simulate disconnects.
|
||
|
export class TcpForwarder {
|
||
|
public port: number|null = null;
|
||
|
private _connections = new Map<Socket, Socket>();
|
||
|
private _server: Server|null = null;
|
||
|
|
||
|
constructor(private _serverPort: number, private _serverHost?: string) {}
|
||
|
|
||
|
public async pickForwarderPort(): Promise<number> {
|
||
|
this.port = await getAvailablePort(5834);
|
||
|
return this.port;
|
||
|
}
|
||
|
public async connect() {
|
||
|
await this.disconnect();
|
||
|
this._server = new Server((sock) => this._onConnect(sock));
|
||
|
await listenPromise(this._server.listen(this.port));
|
||
|
}
|
||
|
public async disconnectClientSide() {
|
||
|
await Promise.all(Array.from(this._connections.keys(), destroySock));
|
||
|
if (this._server) {
|
||
|
await new Promise((resolve) => this._server!.close(resolve));
|
||
|
this._server = null;
|
||
|
}
|
||
|
this.cleanup();
|
||
|
}
|
||
|
public async disconnectServerSide() {
|
||
|
await Promise.all(Array.from(this._connections.values(), destroySock));
|
||
|
this.cleanup();
|
||
|
}
|
||
|
public async disconnect() {
|
||
|
await this.disconnectClientSide();
|
||
|
await this.disconnectServerSide();
|
||
|
}
|
||
|
public cleanup() {
|
||
|
const pairs = Array.from(this._connections.entries());
|
||
|
for (const [clientSock, serverSock] of pairs) {
|
||
|
if (clientSock.destroyed && serverSock.destroyed) {
|
||
|
this._connections.delete(clientSock);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
private async _onConnect(clientSock: Socket) {
|
||
|
const serverSock = await connectSock(this._serverPort, this._serverHost);
|
||
|
clientSock.pipe(serverSock);
|
||
|
serverSock.pipe(clientSock);
|
||
|
clientSock.on('error', (err) => serverSock.destroy(err));
|
||
|
serverSock.on('error', (err) => clientSock.destroy(err));
|
||
|
this._connections.set(clientSock, serverSock);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function destroySock(sock: Socket): Promise<void> {
|
||
|
if (!sock.destroyed) {
|
||
|
await new Promise((resolve, reject) =>
|
||
|
sock.on('close', resolve).destroy());
|
||
|
}
|
||
|
}
|