mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 21:55:59 +00:00
fixed race condition when using SSH tunnel #110
This commit is contained in:
@@ -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 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user