@@ -11,6 +11,7 @@ import { Socket } from 'net'
11
11
import globals from '../../shared/extensionGlobals'
12
12
import { Result } from '../../shared/utilities/result'
13
13
import { FileSystemCommon } from '../../srcShared/fs'
14
+ import { CancellationError } from '../../shared/utilities/timeoutUtils'
14
15
15
16
export class MissingPortError extends ToolkitError {
16
17
constructor ( ) {
@@ -47,6 +48,12 @@ export class AuthError extends ToolkitError {
47
48
* back to VSCode
48
49
*/
49
50
export class AuthSSOServer {
51
+ // Last initialized instance of the Auth Server
52
+ static #lastInstance: AuthSSOServer | undefined
53
+ public static get lastInstance ( ) {
54
+ return AuthSSOServer . #lastInstance
55
+ }
56
+
50
57
private baseUrl = `http://127.0.0.1`
51
58
private oauthCallback = '/oauth/callback'
52
59
private authenticationFlowTimeoutInMs = 600000
@@ -57,7 +64,9 @@ export class AuthSSOServer {
57
64
private server : http . Server
58
65
private connections : Socket [ ]
59
66
60
- constructor ( private readonly state : string ) {
67
+ private _closed : boolean = false
68
+
69
+ private constructor ( private readonly state : string ) {
61
70
this . authenticationPromise = new Promise < Result < string > > ( resolve => {
62
71
this . deferred = { resolve }
63
72
} )
@@ -99,6 +108,22 @@ export class AuthSSOServer {
99
108
} )
100
109
}
101
110
111
+ public static init ( state : string ) {
112
+ const lastInstance = AuthSSOServer . #lastInstance
113
+ if ( lastInstance !== undefined && ! lastInstance . closed ) {
114
+ lastInstance
115
+ . close ( ) !
116
+ . catch ( err =>
117
+ getLogger ( ) . error ( 'Failed to close already existing auth sever in AuthSSOServer.init(): %s' , err )
118
+ )
119
+ }
120
+
121
+ getLogger ( ) . debug ( 'AuthSSOServer: Initialized new auth server.' )
122
+ const instance = new AuthSSOServer ( state )
123
+ AuthSSOServer . #lastInstance = instance
124
+ return instance
125
+ }
126
+
102
127
start ( ) {
103
128
if ( this . server . listening ) {
104
129
throw new ToolkitError ( 'AuthSSOServer: Server already started' )
@@ -127,10 +152,17 @@ export class AuthSSOServer {
127
152
128
153
close ( ) {
129
154
return new Promise < void > ( ( resolve , reject ) => {
155
+ if ( this . _closed ) {
156
+ resolve ( )
157
+ return
158
+ }
159
+
130
160
if ( ! this . server . listening ) {
131
161
reject ( new ToolkitError ( 'AuthSSOServer: Server not started' ) )
132
162
}
133
163
164
+ getLogger ( ) . debug ( 'AuthSSOServer: Attempting to close server.' )
165
+
134
166
this . connections . forEach ( connection => {
135
167
connection . destroy ( )
136
168
} )
@@ -139,6 +171,8 @@ export class AuthSSOServer {
139
171
if ( err ) {
140
172
reject ( err )
141
173
}
174
+ this . _closed = true
175
+ getLogger ( ) . debug ( 'AuthSSOServer: Server closed successfully.' )
142
176
resolve ( )
143
177
} )
144
178
} )
@@ -152,6 +186,10 @@ export class AuthSSOServer {
152
186
return `${ this . baseUrl } :${ this . getPort ( ) } `
153
187
}
154
188
189
+ public get closed ( ) {
190
+ return this . _closed
191
+ }
192
+
155
193
public getAddress ( ) {
156
194
return this . server . address ( )
157
195
}
@@ -228,6 +266,11 @@ export class AuthSSOServer {
228
266
this . deferred ?. resolve ( Result . err ( error ) )
229
267
}
230
268
269
+ public cancelCurrentFlow ( ) {
270
+ getLogger ( ) . debug ( 'AuthSSOServer: Cancelling current login flow' )
271
+ this . deferred ?. resolve ( Result . err ( new CancellationError ( 'user' ) ) )
272
+ }
273
+
231
274
public waitForAuthorization ( ) : Promise < Result < string > > {
232
275
return Promise . race ( [
233
276
this . authenticationPromise ,
@@ -244,7 +287,7 @@ export class AuthSSOServer {
244
287
getLogger ( ) . warn ( 'AuthSSOServer: Authentication is taking a long time' )
245
288
} , this . authenticationWarningTimeoutInMs )
246
289
247
- void this . authenticationPromise . then ( ( ) => {
290
+ void this . authenticationPromise . finally ( ( ) => {
248
291
clearTimeout ( warningTimeout )
249
292
} )
250
293
} ) ,
0 commit comments