@applitools/execution-grid-tunnel
Version:
Allows user to run tests with exection-grid and navigate to private hosts and ips
160 lines (130 loc) • 4.34 kB
JavaScript
const path = require('path')
const {createFrpcTunnelController, createTcpTunnelController} = require('./tunnel-controller.js')
const TUNNEL_STATUS = require('./tunnel-status')
class TunnelProcessManager {
constructor({
logFileDirectory,
tunnelConfigFileDirectory,
runTunnelBinPath,
socks5Proxies,
portRange,
tcpTunnelOptions
}) {
this._tunnelsMap = new Map()
this._logFileDirectory = logFileDirectory
this._tunnelConfigFileDirectory = tunnelConfigFileDirectory
this._runTunnelBinPath = runTunnelBinPath
this._portRange = portRange
this._socks5Proxies = socks5Proxies
this._tcpTunnelOptions = tcpTunnelOptions
// Define proposal-class-properties (because eslint throw error)
this._shouldRunTunnel = async (tunnelId) => {
const {isStopTunnelCalled} = this._tunnelsMap.get(tunnelId) || {}
return !!isStopTunnelCalled
}
this._updateTunnelMap = (tunnelId, fields) => {
const tunnel = this._tunnelsMap.get(tunnelId) || {}
this._tunnelsMap.set(tunnelId, {...tunnel, ...fields})
}
this._getTunnelByStatus = (states) => Array.from(this._tunnelsMap.keys()).filter((id) => {
const {processController} = this._tunnelsMap.get(id)
return processController && states.includes(processController.status)
})
this.getActiveTunnels = () => this._getTunnelByStatus([TUNNEL_STATUS.RUNNING, TUNNEL_STATUS.RECONNECT])
this.getRunningTunnels = () => this._getTunnelByStatus([TUNNEL_STATUS.RUNNING])
}
async start({ tunnelId, type, config }) {
try {
const logFilePath = path.resolve(this._logFileDirectory, `${tunnelId}.log`)
if (!this._shouldRunTunnel(tunnelId)) {
return null
}
this._updateTunnelMap(tunnelId, {type ,config})
let tunnelController
if (type === 'tcp'){
const localProxyOptions = {
host: '127.0.0.1',
port: this._socks5Proxies[0].address().port
}
tunnelController = createTcpTunnelController({
tunnelId,
tunnelConfig: {...config, ...this._tcpTunnelOptions, localProxyOptions},
loggerOptions: this._tcpTunnelOptions.loggerOptions,
})
}else{
tunnelController = createFrpcTunnelController({
tunnelId,
tunnelConfig: config,
configFileRootPath: this._tunnelConfigFileDirectory,
logFilePath,
binPath: this._runTunnelBinPath,
socks5Proxy: this._socks5Proxies[0],
portRange: this._portRange,
})
}
await tunnelController.start()
this._updateTunnelMap(tunnelId, {processController: tunnelController})
if (!this._shouldRunTunnel(tunnelId)) {
await this.stop(tunnelId)
return null
}
return tunnelId
} catch (error) {
this._updateTunnelMap(tunnelId, {error})
throw error
}
}
async stop(tunnelId) {
if (!this._tunnelsMap.has(tunnelId)) {
return
}
// Update that user want to stop the tunnel
this._updateTunnelMap(tunnelId, {isStopTunnelCalled: true})
const {processController} = this._tunnelsMap.get(tunnelId)
if (!processController) {
return
}
await processController.stop()
this._tunnelsMap.delete(tunnelId)
}
async stopAll() {
const promises = Object.entries(this.getTunnels())
.filter(([_tunnelId, {isStopTunnelCalled}]) => !isStopTunnelCalled)
.map(([tunnelId]) => this.stop(tunnelId))
const _result = await Promise.allSettled(promises)
//TODO: add log if there is an error
return
}
getTunnels() {
return Array.from(this._tunnelsMap.entries()).reduce(
(pv, [key, value]) => ({...pv, [key]: value}),
{},
)
}
getStatus(tunnelId) {
const process = this._tunnelsMap.get(tunnelId)
if (!process || !process.processController) {
return null
}
return process.processController.status
}
}
module.exports = function createTunnelProcessManager({
logFileDirectory,
tunnelConfigFileDirectory,
runTunnelBinPath,
egTunnelManager,
socks5Proxies,
portRange,
tcpTunnelOptions
}) {
return new TunnelProcessManager({
logFileDirectory,
tunnelConfigFileDirectory,
runTunnelBinPath,
egTunnelManager,
socks5Proxies,
portRange,
tcpTunnelOptions
})
}