Private/Get-GceSshTunnelDirectory.ps1
|
# Private helper functions for managing tunnel files function Get-GceSshTunnelDirectory { <# .SYNOPSIS Gets the directory where tunnel files are stored. .DESCRIPTION Returns the path to the tunnel files directory, creating it if it doesn't exist. #> $tunnelDir = Join-Path $env:TEMP "GcePSSession\Tunnels" if (-not (Test-Path $tunnelDir)) { New-Item -ItemType Directory -Path $tunnelDir -Force | Out-Null } return $tunnelDir } function Get-GceSshTunnelFilePath { <# .SYNOPSIS Gets the file path for a tunnel's JSON file. .PARAMETER TunnelId The tunnel ID (Process ID). #> param( [Parameter(Mandatory=$true)] [int]$TunnelId ) $tunnelDir = Get-GceSshTunnelDirectory return Join-Path $tunnelDir "$TunnelId.json" } function Save-GceSshTunnelFile { <# .SYNOPSIS Saves tunnel metadata to a JSON file. .PARAMETER Tunnel The GceSshTunnel object to save. #> param( [Parameter(Mandatory=$true)] [GceSshTunnel]$Tunnel ) try { $filePath = Get-GceSshTunnelFilePath -TunnelId $Tunnel.Id $tunnelData = @{ Id = $Tunnel.Id InstanceName = $Tunnel.InstanceName Project = $Tunnel.Project Zone = $Tunnel.Zone LocalPort = $Tunnel.LocalPort RemotePort = $Tunnel.RemotePort ProcessId = $Tunnel.TunnelProcess.Id Created = $Tunnel.Created.ToString("o") # ISO 8601 format } $tunnelData | ConvertTo-Json -Compress | Set-Content -Path $filePath -Encoding UTF8 -ErrorAction Stop Write-Verbose "Saved tunnel file: $filePath" } catch { Write-Warning "Failed to save tunnel file for $($Tunnel.Id): $_" } } function Remove-GceSshTunnelFile { <# .SYNOPSIS Removes a tunnel's JSON file. .PARAMETER TunnelId The tunnel ID (Process ID). #> param( [Parameter(Mandatory=$true)] [int]$TunnelId ) try { $filePath = Get-GceSshTunnelFilePath -TunnelId $TunnelId if (Test-Path $filePath) { Remove-Item -Path $filePath -Force -ErrorAction Stop Write-Verbose "Removed tunnel file: $filePath" } } catch { Write-Warning "Failed to remove tunnel file for $TunnelId`: $_" } } function Import-GceSshTunnelFiles { <# .SYNOPSIS Imports all tunnel files from disk and rebuilds the registry. .DESCRIPTION Scans the tunnel directory, loads all JSON files, verifies processes are still running, removes stale files, and returns a hashtable of active tunnels. #> $tunnelDir = Get-GceSshTunnelDirectory $tunnels = @{} if (-not (Test-Path $tunnelDir)) { return $tunnels } $tunnelFiles = Get-ChildItem -Path $tunnelDir -Filter "*.json" -ErrorAction SilentlyContinue foreach ($file in $tunnelFiles) { try { $tunnelData = Get-Content -Path $file.FullName -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop # Verify process still exists $process = Get-Process -Id $tunnelData.ProcessId -ErrorAction SilentlyContinue if (-not $process) { # Process no longer exists, remove stale file Write-Verbose "Removing stale tunnel file: $($file.Name) (process $($tunnelData.ProcessId) no longer exists)" Remove-Item -Path $file.FullName -Force -ErrorAction SilentlyContinue continue } # Use ProcessId as the tunnel ID (Id field in JSON may be old GUID format during migration) $tunnelId = $tunnelData.ProcessId # Recreate tunnel object using ProcessId as the ID $tunnel = [GceSshTunnel]::new( $tunnelId, $tunnelData.InstanceName, $tunnelData.Project, $tunnelData.Zone, $tunnelData.LocalPort, $tunnelData.RemotePort, $process ) # Register process exit handler to clean up file Register-ObjectEvent -InputObject $process -EventName Exited -Action { $tunnelId = $Event.MessageData.TunnelId Remove-GceSshTunnelFile -TunnelId $tunnelId } -MessageData @{ TunnelId = $tunnelId } | Out-Null $tunnels[$tunnelId] = $tunnel Write-Verbose "Loaded tunnel from file: $($file.Name)" } catch { Write-Warning "Failed to load tunnel file $($file.Name): $_" # Remove corrupted file try { Remove-Item -Path $file.FullName -Force -ErrorAction SilentlyContinue } catch { } } } return $tunnels } |