@@ -19,13 +19,13 @@ import updateCommand from '@oclif/plugin-update/lib/commands/update';
19
19
import { HttpToolkitServerApi } from './api/api-server' ;
20
20
import { checkBrowserConfig } from './browsers' ;
21
21
import { logError } from './error-tracking' ;
22
- import { MOCKTTP_ALLOWED_ORIGINS } from './constants' ;
22
+ import { IS_PROD_BUILD , MOCKTTP_ALLOWED_ORIGINS } from './constants' ;
23
23
24
24
import { delay } from './util/promise' ;
25
25
import { isErrorLike } from './util/error' ;
26
26
import { readFile , checkAccess , writeFile , ensureDirectoryExists } from './util/fs' ;
27
27
28
- import { registerShutdownHandler } from './shutdown' ;
28
+ import { registerShutdownHandler , shutdown } from './shutdown' ;
29
29
import { getTimeToCertExpiry , parseCert } from './certificates' ;
30
30
31
31
import {
@@ -77,14 +77,24 @@ function checkCertExpiry(certContents: string): void {
77
77
}
78
78
}
79
79
80
+ let shutdownTimer : NodeJS . Timeout | undefined ;
81
+
80
82
function manageBackgroundServices (
81
83
standalone : PluggableAdmin . AdminServer < {
82
84
http : MockttpAdminPlugin ,
83
85
webrtc : MockRTCAdminPlugin
84
86
} > ,
85
87
httpsConfig : { certPath : string , certContent : string }
86
88
) {
89
+ let activeSessions = 0 ;
90
+
87
91
standalone . on ( 'mock-session-started' , async ( { http, webrtc } , sessionId ) => {
92
+ activeSessions += 1 ;
93
+ if ( shutdownTimer ) {
94
+ clearTimeout ( shutdownTimer ) ;
95
+ shutdownTimer = undefined ;
96
+ }
97
+
88
98
const httpProxyPort = http . getMockServer ( ) . port ;
89
99
90
100
console . log ( `Mock session started, http on port ${
@@ -105,6 +115,7 @@ function manageBackgroundServices(
105
115
} ) ;
106
116
107
117
standalone . on ( 'mock-session-stopping' , ( { http } ) => {
118
+ activeSessions -= 1 ;
108
119
const httpProxyPort = http . getMockServer ( ) . port ;
109
120
110
121
stopDockerInterceptionServices ( httpProxyPort , ruleParameters )
@@ -113,6 +124,23 @@ function manageBackgroundServices(
113
124
} ) ;
114
125
115
126
clearWebExtensionConfig ( httpProxyPort ) ;
127
+
128
+ // In some odd cases, the server can end up running even though all UIs & desktop have exited
129
+ // completely. This can be problematic, as it leaves the server holding ports that HTTP Toolkit
130
+ // needs, and blocks future startups. To avoid this, if no Mock sessions are running at all
131
+ // for 10 minutes, the server shuts down automatically. Skipped for dev, where that might be OK.
132
+ // This should catch even hard desktop shell crashes, as sessions shut down automatically if the
133
+ // client websocket becomes non-responsive.
134
+ if ( activeSessions <= 0 && IS_PROD_BUILD ) {
135
+ if ( shutdownTimer ) {
136
+ clearTimeout ( shutdownTimer ) ;
137
+ shutdownTimer = undefined ;
138
+ }
139
+
140
+ shutdownTimer = setTimeout ( ( ) => {
141
+ if ( activeSessions === 0 ) shutdown ( '10 minutes inactive' ) ;
142
+ } , 1000 * 60 * 10 ) . unref ( ) ;
143
+ }
116
144
} ) ;
117
145
}
118
146
0 commit comments