@@ -265,43 +265,62 @@ export class Remote {
265265 agent = matchingAgents [ 0 ]
266266 }
267267
268- let remotePlatforms = this . vscodeProposed . workspace
268+ const hostname = authorityParts [ 1 ]
269+ const remotePlatforms = this . vscodeProposed . workspace
269270 . getConfiguration ( )
270- . get < Record < string , string > > ( "remote.SSH.remotePlatform" )
271- remotePlatforms = {
272- ...remotePlatforms ,
273- [ `${ authorityParts [ 1 ] } ` ] : agent . operating_system ,
274- }
275-
276- // VS Code ignores the connect timeout in the SSH config and uses a default
277- // of 15 seconds, which can be too short in the case where we wait for
278- // startup scripts. For now we hardcode a longer value.
279- // If microsoft/vscode-remote-release#8519 is resolved we can remove this.
280- const connectTimeout = 1800
281-
271+ . get < Record < string , string > > ( "remote.SSH.remotePlatform" , { } )
272+ const connTimeout = this . vscodeProposed . workspace . getConfiguration ( ) . get < number > ( "remote.SSH.connectTimeout" )
273+
274+ // We have to directly munge the settings file with jsonc because trying to
275+ // update properly through the extension API hangs indefinitely. Possibly
276+ // VS Code is trying to update configuration on the remote, which cannot
277+ // connect until we finish here leading to a deadlock. We need to update it
278+ // locally, anyway, and it does not seem possible to force that via API.
282279 let settingsContent = "{}"
283280 try {
284281 settingsContent = await fs . readFile ( this . storage . getUserSettingsPath ( ) , "utf8" )
285282 } catch ( ex ) {
286283 // Ignore! It's probably because the file doesn't exist.
287284 }
288285
289- settingsContent = jsonc . applyEdits (
290- settingsContent ,
291- jsonc . modify ( settingsContent , [ "remote.SSH.remotePlatform" ] , remotePlatforms , { } ) ,
292- )
286+ // Add the remote platform for this host to bypass a step where VS Code asks
287+ // the user for the platform.
288+ let mungedPlatforms = false
289+ if ( ! remotePlatforms [ hostname ] || remotePlatforms [ hostname ] !== agent . operating_system ) {
290+ remotePlatforms [ hostname ] = agent . operating_system
291+ settingsContent = jsonc . applyEdits (
292+ settingsContent ,
293+ jsonc . modify ( settingsContent , [ "remote.SSH.remotePlatform" ] , remotePlatforms , { } ) ,
294+ )
295+ mungedPlatforms = true
296+ }
293297
294- settingsContent = jsonc . applyEdits (
295- settingsContent ,
296- jsonc . modify ( settingsContent , [ "remote.SSH.connectTimeout" ] , connectTimeout , { } ) ,
297- )
298+ // VS Code ignores the connect timeout in the SSH config and uses a default
299+ // of 15 seconds, which can be too short in the case where we wait for
300+ // startup scripts. For now we hardcode a longer value. Because this is
301+ // potentially overwriting user configuration, it feels a bit sketchy. If
302+ // microsoft/vscode-remote-release#8519 is resolved we can remove this but
303+ // for now to mitigate the sketchiness we will reset it after connecting.
304+ const minConnTimeout = 1800
305+ let mungedConnTimeout = false
306+ if ( ! connTimeout || connTimeout < minConnTimeout ) {
307+ settingsContent = jsonc . applyEdits (
308+ settingsContent ,
309+ jsonc . modify ( settingsContent , [ "remote.SSH.connectTimeout" ] , minConnTimeout , { } ) ,
310+ )
311+ mungedConnTimeout = true
312+ }
298313
299- try {
300- await fs . writeFile ( this . storage . getUserSettingsPath ( ) , settingsContent )
301- } catch ( ex ) {
302- // The user will just be prompted instead, which is fine!
303- // If a user's settings.json is read-only, then we can't write to it.
304- // This is the case when using home-manager on NixOS.
314+ if ( mungedPlatforms || mungedConnTimeout ) {
315+ try {
316+ await fs . writeFile ( this . storage . getUserSettingsPath ( ) , settingsContent )
317+ } catch ( ex ) {
318+ // This could be because the user's settings.json is read-only. This is
319+ // the case when using home-manager on NixOS, for example. Failure to
320+ // write here is not necessarily catastrophic since the user will be
321+ // asked for the platform and the default timeout might be sufficient.
322+ mungedPlatforms = mungedConnTimeout = false
323+ }
305324 }
306325
307326 const workspaceUpdate = new vscode . EventEmitter < Workspace > ( )
@@ -445,6 +464,26 @@ export class Remote {
445464 await this . updateSSHConfig ( authorityParts [ 1 ] , hasCoderLogs )
446465
447466 this . findSSHProcessID ( ) . then ( ( pid ) => {
467+ // Once the SSH process has spawned we can reset the timeout.
468+ if ( mungedConnTimeout ) {
469+ // Re-read settings in case they changed.
470+ fs . readFile ( this . storage . getUserSettingsPath ( ) , "utf8" ) . then ( async ( rawSettings ) => {
471+ try {
472+ await fs . writeFile (
473+ this . storage . getUserSettingsPath ( ) ,
474+ jsonc . applyEdits (
475+ rawSettings ,
476+ jsonc . modify ( settingsContent , [ "remote.SSH.connectTimeout" ] , connTimeout , { } ) ,
477+ ) ,
478+ )
479+ } catch ( error ) {
480+ this . storage . writeToCoderOutputChannel (
481+ `Failed to reset remote.SSH.connectTimeout back to ${ connTimeout } : ${ error } ` ,
482+ )
483+ }
484+ } )
485+ }
486+
448487 if ( ! pid ) {
449488 // TODO: Show an error here!
450489 return
0 commit comments