@@ -12,6 +12,7 @@ use crate::util::input::prompt_placeholder;
12
12
use crate :: { debug, info, log, spanf, trace, warning} ;
13
13
use async_trait:: async_trait;
14
14
use futures:: TryFutureExt ;
15
+ use lazy_static:: lazy_static;
15
16
use rand:: prelude:: IteratorRandom ;
16
17
use regex:: Regex ;
17
18
use reqwest:: StatusCode ;
@@ -121,7 +122,7 @@ impl AccessTokenProvider for LookupAccessTokenProvider {
121
122
122
123
match tunnel_lookup {
123
124
Ok ( tunnel) => Ok ( get_host_token_from_tunnel ( & tunnel) ) ,
124
- Err ( e) => Err ( wrap ( e, "failed to lookup tunnel" ) ) ,
125
+ Err ( e) => Err ( wrap ( e, "failed to lookup tunnel for host token " ) ) ,
125
126
}
126
127
}
127
128
}
@@ -212,6 +213,14 @@ fn is_valid_name(name: &str) -> Result<(), InvalidTunnelName> {
212
213
Ok ( ( ) )
213
214
}
214
215
216
+ lazy_static ! {
217
+ static ref HOST_TUNNEL_REQUEST_OPTIONS : TunnelRequestOptions = TunnelRequestOptions {
218
+ include_ports: true ,
219
+ token_scopes: vec![ "host" . to_string( ) ] ,
220
+ ..Default :: default ( )
221
+ } ;
222
+ }
223
+
215
224
/// Structure optionally passed into `start_existing_tunnel` to forward an existing tunnel.
216
225
#[ derive( Clone , Debug ) ]
217
226
pub struct ExistingTunnel {
@@ -260,6 +269,7 @@ impl DevTunnels {
260
269
Ok ( ( ) )
261
270
}
262
271
272
+ /// Renames the current tunnel to the new name.
263
273
pub async fn rename_tunnel ( & mut self , name : & str ) -> Result < ( ) , AnyError > {
264
274
is_valid_name ( name) ?;
265
275
@@ -269,7 +279,7 @@ impl DevTunnels {
269
279
Some ( t) => t,
270
280
None => {
271
281
debug ! ( self . log, "No code server tunnel found, creating new one" ) ;
272
- let ( persisted, _) = self . create_tunnel ( name) . await ?;
282
+ let ( persisted, _) = self . create_tunnel ( name, NO_REQUEST_OPTIONS ) . await ?;
273
283
self . launcher_tunnel . save ( Some ( persisted) ) ?;
274
284
return Ok ( ( ) ) ;
275
285
}
@@ -282,7 +292,7 @@ impl DevTunnels {
282
292
self . log. span( "dev-tunnel.tag.get" ) ,
283
293
self . client. get_tunnel( & locator, NO_REQUEST_OPTIONS )
284
294
)
285
- . map_err ( |e| wrap ( e, "failed to lookup tunnel" ) ) ?;
295
+ . map_err ( |e| wrap ( e, "failed to lookup original tunnel" ) ) ?;
286
296
287
297
full_tunnel. tags = vec ! [ name. to_string( ) , VSCODE_CLI_TUNNEL_TAG . to_string( ) ] ;
288
298
spanf ! (
@@ -297,6 +307,70 @@ impl DevTunnels {
297
307
Ok ( ( ) )
298
308
}
299
309
310
+ /// Updates the name of the existing persisted tunnel to the new name.
311
+ /// Gracefully creates a new tunnel if the previous one was deleted.
312
+ async fn update_tunnel_name (
313
+ & mut self ,
314
+ persisted : PersistedTunnel ,
315
+ name : & str ,
316
+ ) -> Result < ( Tunnel , PersistedTunnel ) , AnyError > {
317
+ self . check_is_name_free ( name) . await ?;
318
+
319
+ debug ! ( self . log, "Tunnel name changed, applying updates..." ) ;
320
+
321
+ let ( mut full_tunnel, mut persisted, is_new) = self
322
+ . get_or_create_tunnel ( persisted, Some ( name) , NO_REQUEST_OPTIONS )
323
+ . await ?;
324
+ if is_new {
325
+ return Ok ( ( full_tunnel, persisted) ) ;
326
+ }
327
+
328
+ full_tunnel. tags = vec ! [ name. to_string( ) , VSCODE_CLI_TUNNEL_TAG . to_string( ) ] ;
329
+
330
+ let new_tunnel = spanf ! (
331
+ self . log,
332
+ self . log. span( "dev-tunnel.tag.update" ) ,
333
+ self . client. update_tunnel( & full_tunnel, NO_REQUEST_OPTIONS )
334
+ )
335
+ . map_err ( |e| wrap ( e, "failed to rename tunnel" ) ) ?;
336
+
337
+ persisted. name = name. to_string ( ) ;
338
+ self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
339
+
340
+ Ok ( ( new_tunnel, persisted) )
341
+ }
342
+
343
+ /// Gets the persisted tunnel from the service, or creates a new one.
344
+ /// If `create_with_new_name` is given, the new tunnel has that name
345
+ /// instead of the one previously persisted.
346
+ async fn get_or_create_tunnel (
347
+ & mut self ,
348
+ persisted : PersistedTunnel ,
349
+ create_with_new_name : Option < & str > ,
350
+ options : & TunnelRequestOptions ,
351
+ ) -> Result < ( Tunnel , PersistedTunnel , /* is_new */ bool ) , AnyError > {
352
+ let tunnel_lookup = spanf ! (
353
+ self . log,
354
+ self . log. span( "dev-tunnel.tag.get" ) ,
355
+ self . client. get_tunnel( & persisted. locator( ) , options)
356
+ ) ;
357
+
358
+ match tunnel_lookup {
359
+ Ok ( ft) => Ok ( ( ft, persisted, false ) ) ,
360
+ Err ( HttpError :: ResponseError ( e) )
361
+ if e. status_code == StatusCode :: NOT_FOUND
362
+ || e. status_code == StatusCode :: FORBIDDEN =>
363
+ {
364
+ let ( persisted, tunnel) = self
365
+ . create_tunnel ( create_with_new_name. unwrap_or ( & persisted. name ) , options)
366
+ . await ?;
367
+ self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
368
+ Ok ( ( tunnel, persisted, true ) )
369
+ }
370
+ Err ( e) => Err ( wrap ( e, "failed to lookup tunnel" ) . into ( ) ) ,
371
+ }
372
+ }
373
+
300
374
/// Starts a new tunnel for the code server on the port. Unlike `start_new_tunnel`,
301
375
/// this attempts to reuse or create a tunnel of a preferred name or of a generated friendly tunnel name.
302
376
pub async fn start_new_launcher_tunnel (
@@ -308,64 +382,23 @@ impl DevTunnels {
308
382
Some ( mut persisted) => {
309
383
if let Some ( name) = preferred_name {
310
384
if persisted. name . ne ( & name) {
311
- self . check_is_name_free ( & name) . await ?;
312
- let mut full_tunnel = spanf ! (
313
- self . log,
314
- self . log. span( "dev-tunnel.tag.get" ) ,
315
- self . client
316
- . get_tunnel( & persisted. locator( ) , NO_REQUEST_OPTIONS )
317
- )
318
- . map_err ( |e| wrap ( e, "failed to lookup tunnel" ) ) ?;
319
-
320
- info ! ( self . log, "Updating name of existing tunnel" ) ;
321
-
322
- full_tunnel. tags =
323
- vec ! [ name. to_string( ) , VSCODE_CLI_TUNNEL_TAG . to_string( ) ] ;
324
- if spanf ! (
325
- self . log,
326
- self . log. span( "dev-tunnel.tag.update" ) ,
327
- self . client. update_tunnel( & full_tunnel, NO_REQUEST_OPTIONS )
328
- )
329
- . is_ok ( )
330
- {
331
- persisted. name = name. to_string ( ) ;
332
- self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
333
- }
385
+ ( _, persisted) = self . update_tunnel_name ( persisted, & name) . await ?;
334
386
}
335
387
}
336
388
337
- let tunnel_lookup = spanf ! (
338
- self . log,
339
- self . log. span( "dev-tunnel.tag.get" ) ,
340
- self . client. get_tunnel(
341
- & persisted. locator( ) ,
342
- & TunnelRequestOptions {
343
- include_ports: true ,
344
- token_scopes: vec![ "host" . to_string( ) ] ,
345
- ..Default :: default ( )
346
- }
347
- )
348
- ) ;
349
-
350
- match tunnel_lookup {
351
- Ok ( ft) => ( ft, persisted) ,
352
- Err ( HttpError :: ResponseError ( e) )
353
- if e. status_code == StatusCode :: NOT_FOUND
354
- || e. status_code == StatusCode :: FORBIDDEN =>
355
- {
356
- let ( persisted, tunnel) = self . create_tunnel ( & persisted. name ) . await ?;
357
- self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
358
- ( tunnel, persisted)
359
- }
360
- Err ( e) => return Err ( AnyError :: from ( wrap ( e, "failed to lookup tunnel" ) ) ) ,
361
- }
389
+ let ( tunnel, persisted, _) = self
390
+ . get_or_create_tunnel ( persisted, None , & HOST_TUNNEL_REQUEST_OPTIONS )
391
+ . await ?;
392
+ ( tunnel, persisted)
362
393
}
363
394
None => {
364
395
debug ! ( self . log, "No code server tunnel found, creating new one" ) ;
365
396
let name = self
366
397
. get_name_for_tunnel ( preferred_name, use_random_name)
367
398
. await ?;
368
- let ( persisted, full_tunnel) = self . create_tunnel ( & name) . await ?;
399
+ let ( persisted, full_tunnel) = self
400
+ . create_tunnel ( & name, & HOST_TUNNEL_REQUEST_OPTIONS )
401
+ . await ?;
369
402
self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
370
403
( full_tunnel, persisted)
371
404
}
@@ -419,7 +452,11 @@ impl DevTunnels {
419
452
. await
420
453
}
421
454
422
- async fn create_tunnel ( & mut self , name : & str ) -> Result < ( PersistedTunnel , Tunnel ) , AnyError > {
455
+ async fn create_tunnel (
456
+ & mut self ,
457
+ name : & str ,
458
+ options : & TunnelRequestOptions ,
459
+ ) -> Result < ( PersistedTunnel , Tunnel ) , AnyError > {
423
460
info ! ( self . log, "Creating tunnel with the name: {}" , name) ;
424
461
425
462
let mut tried_recycle = false ;
@@ -433,7 +470,7 @@ impl DevTunnels {
433
470
let result = spanf ! (
434
471
self . log,
435
472
self . log. span( "dev-tunnel.create" ) ,
436
- self . client. create_tunnel( & new_tunnel, NO_REQUEST_OPTIONS )
473
+ self . client. create_tunnel( & new_tunnel, options )
437
474
) ;
438
475
439
476
match result {
@@ -446,9 +483,9 @@ impl DevTunnels {
446
483
}
447
484
448
485
return Err ( AnyError :: from ( TunnelCreationFailed (
449
- name. to_string ( ) ,
450
- "You've exceeded the 10 machine limit for the port fowarding service. Please remove other machines before trying to add this machine." . to_string ( ) ,
451
- ) ) ) ;
486
+ name. to_string ( ) ,
487
+ "You've exceeded the 10 machine limit for the port fowarding service. Please remove other machines before trying to add this machine." . to_string ( ) ,
488
+ ) ) ) ;
452
489
}
453
490
Err ( e) => {
454
491
return Err ( AnyError :: from ( TunnelCreationFailed (
0 commit comments