UNPKG

@applitools/execution-grid-tunnel

Version:

Allows user to run tests with exection-grid and navigate to private hosts and ips

124 lines (106 loc) 3.64 kB
const tls = require('tls') const net = require('net') const {KeepaliveMessageFilter} = require('./keepalive-filter-message') const ATTACHING_REQUEST = 'attaching-request' const CLOSING_CONNECTION = 'closing-connection' class TunnelConnection { constructor({keepAliveMessage, connectedMessage, logger, connectionId}) { this._logger = logger this._filter = new KeepaliveMessageFilter({keepAliveMessage}) this._connectedMessage = connectedMessage this._filter.on('error', (error) => logger.warn({action: 'filter-error', error: error.stack || error.message}), ) this._connectionId = connectionId } connect({tunnelId, host, port, token, protocol = 'tcp', localProxyOptions}) { return new Promise((resolve, reject) => { let isResolved = false this._logger.debug({ action: 'connection-info', connectionId: this._connectionId, port, host, token, protocol, }) const remoteConnection = protocol == 'tcp' ? net.connect(port, host) : tls.connect(port, host) this._remoteConnection = remoteConnection remoteConnection.once('connect', () => { this._localConnection = net.connect(localProxyOptions) this._localConnection.on('error', (e) => { this._logger.warn({ action: 'local-connection-error', connectionId: this._connectionId, error: e.stack || e.message, }) }) this._localConnection.once('connect', () => { this._localConnection.on('end', () => { this._logger.debug({ action: 'local-connection-end', connectionId: this._connectionId, tunnelId, }) remoteConnection.end() }) remoteConnection.write(JSON.stringify({tunnelId, token})) remoteConnection.once('data', (chunk) => { const result = chunk.toString() if (result !== this._connectedMessage) { this._logger.warn({ action: 'connection-refused', connectionId: this._connectionId, error: result, }) const error = new Error(`Server Error: ${result}`) this._localConnection.end() return reject(error) } remoteConnection.pipe(this._filter).pipe(this._localConnection).pipe(remoteConnection) isResolved = true resolve() }) }) }) remoteConnection.on('error', (e) => { this._logger.warn({ action: 'remote-connection-error', connectionId: this._connectionId, error: e.stack || e.message, }) if (!isResolved) { reject(new Error(`Connection Closed: ${e.message || 'Unexpected'}`)) } remoteConnection.end() }) }) } waitForAttachingRequest() { return this._filter.waitForChunk().then(() => ATTACHING_REQUEST) } waitForRemoteConnectionClosing() { return new Promise((resolve) => { this._remoteConnection.once('end', () => { resolve(CLOSING_CONNECTION) }) }) } end() { if (!this._localConnection?.closed) { this._localConnection.end() } if (!this._remoteConnection.closed) { this._remoteConnection.end() } } destroy() { if (!this._localConnection?.destroyed) { this._localConnection.destroy() } if (!this._remoteConnection.destroyed) { this._remoteConnection.destroy() } } } module.exports = {TunnelConnection, ATTACHING_REQUEST, CLOSING_CONNECTION}