@@ -3,6 +3,8 @@ import * as Docker from 'dockerode';
33import * as semver from 'semver' ;
44import { Mutex } from 'async-mutex' ;
55
6+ import { delay } from '../../util/promise' ;
7+
68import { DOCKER_HOST_HOSTNAME , isImageAvailable } from './docker-commands' ;
79import { isDockerAvailable } from './docker-interception-services' ;
810
@@ -106,8 +108,18 @@ export function ensureDockerTunnelRunning(proxyPort: number) {
106108 await docker . getContainer ( container . Id ) . start ( ) ;
107109 }
108110
109- // Asynchronously, update the Docker port that's in use for this container.
110- portCache [ proxyPort ] = refreshDockerTunnelPortCache ( proxyPort ) ;
111+ const containerPortMappings = container . NetworkSettings . Ports [ '1080/tcp' ] ;
112+ const localTunnelPort = _ . find ( containerPortMappings , ( { HostIp } ) => HostIp === '127.0.0.1' ) ;
113+ if ( ! _ . isObject ( portCache [ proxyPort ] ) && localTunnelPort ?. HostPort !== String ( portCache [ proxyPort ] ) ) {
114+ // If the tunnel port may be outdated (port changed, or missing, or container just started so
115+ // port here is undefined) then schedule an async tunnel port refresh:
116+ portCache [ proxyPort ] = delay ( 10 ) . then ( ( ) => // Leave time for the port to bind
117+ refreshDockerTunnelPortCache ( proxyPort , {
118+ // Force, because otherwise we get into a loop here due to the delay().
119+ force : true
120+ } )
121+ ) ;
122+ }
111123 } ) . finally ( ( ) => {
112124 // Clean up the promise, so that future calls to ensureRunning re-run this check.
113125 ongoingEnsureTunnelRunningChecks [ proxyPort ] = undefined ;
@@ -191,9 +203,9 @@ export async function getDockerTunnelPort(proxyPort: number): Promise<number> {
191203 return portCache [ proxyPort ] ! ;
192204}
193205
194- export async function refreshDockerTunnelPortCache ( proxyPort : number ) : Promise < number > {
206+ export async function refreshDockerTunnelPortCache ( proxyPort : number , { force } = { force : false } ) : Promise < number > {
195207 try {
196- if ( _ . isObject ( portCache [ proxyPort ] ) ) {
208+ if ( ! force && _ . isObject ( portCache [ proxyPort ] ) ) {
197209 // If there's an existing promise refreshing this data, then don't duplicate:
198210 return portCache [ proxyPort ] !
199211 }
@@ -205,8 +217,8 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
205217 . inspect ( ) . catch ( ( ) => undefined ) ;
206218 if ( ! container ) {
207219 // Can't get the container - recreate it (refreshing the port automatically)
208- await ensureDockerTunnelRunning ( proxyPort )
209- return getDockerTunnelPort ( proxyPort ) ;
220+ await ensureDockerTunnelRunning ( proxyPort ) ;
221+ return refreshDockerTunnelPortCache ( proxyPort , { force : true } ) ;
210222 }
211223
212224 const portMappings = container . NetworkSettings . Ports [ '1080/tcp' ] ;
@@ -217,7 +229,7 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
217229 // this can result in the mapping being lots. Kill & restart the container.
218230 await docker . getContainer ( containerName ) . kill ( ) ;
219231 await ensureDockerTunnelRunning ( proxyPort ) ;
220- return getDockerTunnelPort ( proxyPort ) ;
232+ return refreshDockerTunnelPortCache ( proxyPort , { force : true } ) ;
221233 }
222234
223235 const port = parseInt ( localPort . HostPort , 10 ) ;
0 commit comments