@@ -12,6 +12,7 @@ use crate::util::input::prompt_placeholder;
1212use crate :: { debug, info, log, spanf, trace, warning} ;
1313use async_trait:: async_trait;
1414use futures:: TryFutureExt ;
15+ use lazy_static:: lazy_static;
1516use rand:: prelude:: IteratorRandom ;
1617use regex:: Regex ;
1718use reqwest:: StatusCode ;
@@ -121,7 +122,7 @@ impl AccessTokenProvider for LookupAccessTokenProvider {
121122
122123 match tunnel_lookup {
123124 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 " ) ) ,
125126 }
126127 }
127128}
@@ -212,6 +213,14 @@ fn is_valid_name(name: &str) -> Result<(), InvalidTunnelName> {
212213 Ok ( ( ) )
213214}
214215
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+
215224/// Structure optionally passed into `start_existing_tunnel` to forward an existing tunnel.
216225#[ derive( Clone , Debug ) ]
217226pub struct ExistingTunnel {
@@ -260,6 +269,7 @@ impl DevTunnels {
260269 Ok ( ( ) )
261270 }
262271
272+ /// Renames the current tunnel to the new name.
263273 pub async fn rename_tunnel ( & mut self , name : & str ) -> Result < ( ) , AnyError > {
264274 is_valid_name ( name) ?;
265275
@@ -269,7 +279,7 @@ impl DevTunnels {
269279 Some ( t) => t,
270280 None => {
271281 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 ?;
273283 self . launcher_tunnel . save ( Some ( persisted) ) ?;
274284 return Ok ( ( ) ) ;
275285 }
@@ -282,7 +292,7 @@ impl DevTunnels {
282292 self . log. span( "dev-tunnel.tag.get" ) ,
283293 self . client. get_tunnel( & locator, NO_REQUEST_OPTIONS )
284294 )
285- . map_err ( |e| wrap ( e, "failed to lookup tunnel" ) ) ?;
295+ . map_err ( |e| wrap ( e, "failed to lookup original tunnel" ) ) ?;
286296
287297 full_tunnel. tags = vec ! [ name. to_string( ) , VSCODE_CLI_TUNNEL_TAG . to_string( ) ] ;
288298 spanf ! (
@@ -297,6 +307,70 @@ impl DevTunnels {
297307 Ok ( ( ) )
298308 }
299309
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+
300374 /// Starts a new tunnel for the code server on the port. Unlike `start_new_tunnel`,
301375 /// this attempts to reuse or create a tunnel of a preferred name or of a generated friendly tunnel name.
302376 pub async fn start_new_launcher_tunnel (
@@ -308,64 +382,23 @@ impl DevTunnels {
308382 Some ( mut persisted) => {
309383 if let Some ( name) = preferred_name {
310384 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 ?;
334386 }
335387 }
336388
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)
362393 }
363394 None => {
364395 debug ! ( self . log, "No code server tunnel found, creating new one" ) ;
365396 let name = self
366397 . get_name_for_tunnel ( preferred_name, use_random_name)
367398 . 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 ?;
369402 self . launcher_tunnel . save ( Some ( persisted. clone ( ) ) ) ?;
370403 ( full_tunnel, persisted)
371404 }
@@ -419,7 +452,11 @@ impl DevTunnels {
419452 . await
420453 }
421454
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 > {
423460 info ! ( self . log, "Creating tunnel with the name: {}" , name) ;
424461
425462 let mut tried_recycle = false ;
@@ -433,7 +470,7 @@ impl DevTunnels {
433470 let result = spanf ! (
434471 self . log,
435472 self . log. span( "dev-tunnel.create" ) ,
436- self . client. create_tunnel( & new_tunnel, NO_REQUEST_OPTIONS )
473+ self . client. create_tunnel( & new_tunnel, options )
437474 ) ;
438475
439476 match result {
@@ -446,9 +483,9 @@ impl DevTunnels {
446483 }
447484
448485 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+ ) ) ) ;
452489 }
453490 Err ( e) => {
454491 return Err ( AnyError :: from ( TunnelCreationFailed (
0 commit comments