2
2
type ErrorTrackingModule = typeof import ( '../error-tracking' ) ;
3
3
type IndexTypeModule = typeof import ( '../index' ) ;
4
4
5
+ import * as path from 'path' ;
6
+ import { promises as fs } from 'fs'
7
+ import * as semver from 'semver' ;
8
+ import * as rimraf from 'rimraf' ;
9
+
5
10
import { IS_PROD_BUILD } from '../constants' ;
6
11
7
12
function maybeBundleImport < T > ( moduleName : string ) : T {
@@ -40,6 +45,8 @@ class HttpToolkitServer extends Command {
40
45
async run ( ) {
41
46
const { flags } = this . parse ( HttpToolkitServer ) ;
42
47
48
+ this . cleanupOldServers ( ) ; // Async cleanup old server versions
49
+
43
50
await runHTK ( {
44
51
configPath : flags . config ,
45
52
authToken : flags . token
@@ -48,6 +55,66 @@ class HttpToolkitServer extends Command {
48
55
throw error ;
49
56
} ) ;
50
57
}
58
+
59
+ // On startup, we want to kill any downloaded servers that are not longer necessary
60
+ async cleanupOldServers ( ) {
61
+ const { dataDir, version : currentVersion } = this . config ;
62
+
63
+ const serverUpdatesPath = process . env . OCLIF_CLIENT_HOME ||
64
+ path . join ( dataDir , 'client' ) ;
65
+
66
+ // Be careful - if the server path isn't clearly ours somehow, ignore it.
67
+ if ( ! serverUpdatesPath . split ( path . sep ) . includes ( 'httptoolkit-server' ) ) {
68
+ reportError ( `Unexpected server path (${ serverUpdatesPath } ), ignoring` ) ;
69
+ return ;
70
+ }
71
+
72
+ const serverPaths = await fs . readdir ( serverUpdatesPath )
73
+ . catch ( ( e ) => {
74
+ if ( e . code === 'ENOENT' ) return null ;
75
+ else throw e ;
76
+ } ) ;
77
+ if ( ! serverPaths ) return ; // No server update path means we're all good
78
+
79
+ // Similarly, if the folder contains anything unexpected, be careful and do nothing.
80
+ if ( serverPaths . some ( ( filename ) =>
81
+ ! semver . valid ( filename . replace ( / \. p a r t i a l \. \d + $ / , '' ) ) &&
82
+ filename !== 'bin' &&
83
+ filename !== 'current'
84
+ ) ) {
85
+ console . log ( serverPaths ) ;
86
+ reportError (
87
+ `Server path (${ serverUpdatesPath } ) contains unexpected content, ignoring`
88
+ ) ;
89
+ return ;
90
+ }
91
+
92
+ if ( serverPaths . every ( ( filename ) => {
93
+ const version = semver . valid ( filename . replace ( / \. p a r t i a l \. \d + $ / , '' ) ) ;
94
+ return ! version || semver . lt ( version , currentVersion ) ;
95
+ } ) ) {
96
+ // If everything is outdated, just drop the whole folder. Useful if you start
97
+ // a new server standalone (not just from an update), because otherwise the
98
+ // update dir can end up in a broken state. Better to clear it completely.
99
+ console . log ( "Downloaded server directory is entirely outdated, deleting it" ) ;
100
+ rimraf ( serverUpdatesPath , ( error ) => {
101
+ if ( error ) reportError ( error ) ;
102
+ } ) ;
103
+ } else {
104
+ // Some of the servers are outdated, but not all (maybe it includes us).
105
+ // Async delete all server versions older than this currently running version.
106
+ serverPaths . forEach ( ( filename ) => {
107
+ const version = semver . valid ( filename . replace ( / \. p a r t i a l \. \d + $ / , '' ) ) ;
108
+
109
+ if ( version && semver . lt ( version , currentVersion ) ) {
110
+ console . log ( `Deleting old server ${ filename } ` ) ;
111
+ rimraf ( path . join ( serverUpdatesPath , filename ) , ( error ) => {
112
+ if ( error ) reportError ( error ) ;
113
+ } ) ;
114
+ }
115
+ } ) ;
116
+ }
117
+ }
51
118
}
52
119
53
120
export = HttpToolkitServer ;
0 commit comments