fixed race condition when using SSH tunnel #110

This commit is contained in:
Jan Prochazka
2021-05-03 20:39:41 +02:00
parent 4802c36b54
commit 7d34458553

View File

@@ -4,6 +4,8 @@ const portfinder = require('portfinder');
const stableStringify = require('json-stable-stringify'); const stableStringify = require('json-stable-stringify');
const _ = require('lodash'); const _ = require('lodash');
const platformInfo = require('./platformInfo'); const platformInfo = require('./platformInfo');
const AsyncLock = require('async-lock');
const lock = new AsyncLock();
const sshConnectionCache = {}; const sshConnectionCache = {};
const sshTunnelCache = {}; const sshTunnelCache = {};
@@ -45,36 +47,43 @@ async function getSshConnection(connection) {
} }
async function getSshTunnel(connection) { async function getSshTunnel(connection) {
const sshConn = await getSshConnection(connection);
const tunnelCacheKey = stableStringify(_.pick(connection, TUNNEL_FIELDS)); const tunnelCacheKey = stableStringify(_.pick(connection, TUNNEL_FIELDS));
if (sshTunnelCache[tunnelCacheKey]) return sshTunnelCache[tunnelCacheKey];
const localPort = await portfinder.getPortPromise({ port: 10000, stopPort: 60000 }); return await lock.acquire(tunnelCacheKey, async () => {
// workaround for `getPortPromise` not releasing the port quickly enough const sshConn = await getSshConnection(connection);
await new Promise(resolve => setTimeout(resolve, 500)); if (sshTunnelCache[tunnelCacheKey]) return sshTunnelCache[tunnelCacheKey];
const tunnelConfig = {
fromPort: localPort,
toPort: connection.port,
toHost: connection.server,
};
try {
const tunnel = await sshConn.forward(tunnelConfig);
console.log(
`Created SSH tunnel to ${connection.sshHost}-${connection.server}:${connection.port}, using local port ${localPort}`
);
sshTunnelCache[tunnelCacheKey] = { const localPort = await portfinder.getPortPromise({ port: 10000, stopPort: 60000 });
state: 'ok', // workaround for `getPortPromise` not releasing the port quickly enough
localPort, await new Promise(resolve => setTimeout(resolve, 500));
const tunnelConfig = {
fromPort: localPort,
toPort: connection.port,
toHost: connection.server,
}; };
return sshTunnelCache[tunnelCacheKey]; try {
} catch (err) { console.log(
// error is not cached `Creating SSH tunnel to ${connection.sshHost}-${connection.server}:${connection.port}, using local port ${localPort}`
return { );
state: 'error',
message: err.message, const tunnel = await sshConn.forward(tunnelConfig);
}; console.log(
} `Created SSH tunnel to ${connection.sshHost}-${connection.server}:${connection.port}, using local port ${localPort}`
);
sshTunnelCache[tunnelCacheKey] = {
state: 'ok',
localPort,
};
return sshTunnelCache[tunnelCacheKey];
} catch (err) {
// error is not cached
return {
state: 'error',
message: err.message,
};
}
});
} }
module.exports = { module.exports = {