diff --git a/src/commands/postgres/tunnel.ts b/src/commands/postgres/tunnel.ts index d9ed3a8..70cdf52 100644 --- a/src/commands/postgres/tunnel.ts +++ b/src/commands/postgres/tunnel.ts @@ -1,7 +1,7 @@ import {Command, Flags} from '@oclif/core' import {getDisco} from '../../config.js' import {request} from '../../auth-request.js' -import {createTunnel} from 'tunnel-ssh'; +import {createTunnel} from 'tunnel-ssh' export default class PostgresTunnel extends Command { static description = 'create a temporary tunnel to access Postgres through localhost' @@ -17,8 +17,8 @@ export default class PostgresTunnel extends Command { public async run(): Promise { const {flags} = await this.parse(PostgresTunnel) const discoConfig = getDisco(flags.disco || null) - - const dbInfoUrl = `https://${discoConfig.host}/api/projects/postgres-addon/cgi/endpoints/tunnels`; + + const dbInfoUrl = `https://${discoConfig.host}/api/projects/postgres-addon/cgi/endpoints/tunnels` const dbInfoResponse = await request({ method: 'POST', url: dbInfoUrl, @@ -29,13 +29,15 @@ export default class PostgresTunnel extends Command { discoConfig, expectedStatuses: [200], }) - const dbInfoRespBody = (await dbInfoResponse.json()) as {dbInfo: {instance: string, database: string, user: string, password: string}} - const {dbInfo} = dbInfoRespBody; + const dbInfoRespBody = (await dbInfoResponse.json()) as { + dbInfo: {instance: string; database: string; user: string; password: string} + } + const {dbInfo} = dbInfoRespBody const url = `https://${discoConfig.host}/api/tunnels` const reqBody = { - project: `postgres-instance-${dbInfo.instance}`, - service: 'postgres', - }; + project: `postgres-instance-${dbInfo.instance}`, + service: 'postgres', + } const res = await request({ method: 'POST', url, @@ -43,43 +45,53 @@ export default class PostgresTunnel extends Command { discoConfig, expectedStatuses: [201], }) - const respBody = (await res.json()) as {tunnel: {host: string, password: string, port: number}} + const respBody = (await res.json()) as {tunnel: {host: string; password: string; port: number}} + const tunnelPort = respBody.tunnel.port const connString = `postgresql://${dbInfo.user}:${dbInfo.password}@localhost/${dbInfo.database}` - const sshOptions = { host: discoConfig.host, port: respBody.tunnel.port, username: 'root', - password: respBody.tunnel.password - }; + password: respBody.tunnel.password, + } - const forwardOptions = { - dstAddr: respBody.tunnel.host, - dstPort: 5432 + dstAddr: respBody.tunnel.host, + dstPort: 5432, } const tunnelOptions = { - autoClose: true + autoClose: true, } - + const serverOptions = { - host: 'localhost', - port: 5432 + host: 'localhost', + port: 5432, } - await createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions); - - - - - - // this.log(`host: ${respBody.tunnel.host}`) - // this.log(`password: ${respBody.tunnel.password}`) - // this.log(`port: ${respBody.tunnel.port}`) - - this.log("Tunnel created. Connection string:") + const [_, tunnelClient] = await createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions) + this.log('Tunnel created. Connection string:') this.log(connString) + const extendInterval = setInterval(async () => { + await request({ + method: 'POST', + url: `https://${discoConfig.host}/api/tunnels/${tunnelPort}`, + discoConfig, + expectedStatuses: [200], + }) + }, 60_000) + process.on('SIGINT', () => { + clearInterval(extendInterval) + tunnelClient.destroy() + request({ + method: 'DELETE', + url: `https://${discoConfig.host}/api/tunnels/${tunnelPort}`, + discoConfig, + expectedStatuses: [200], + }).then(() => { + process.exit(0) // eslint-disable-line n/no-process-exit + }) + }) } }