Files

78 lines
2.8 KiB
PowerShell

param(
[int]$Port = 8797,
[string]$BindAddress = "127.0.0.1"
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$runtime = Join-Path $root "runtime"
$logs = Join-Path $runtime "logs"
$cache = Join-Path $runtime "cache\python"
New-Item -ItemType Directory -Force -Path $logs, $cache | Out-Null
$launcher = Get-Command py -ErrorAction SilentlyContinue
if (-not $launcher) {
$launcher = Get-Command python -ErrorAction Stop
}
# PowerShell 5.1 cannot start a child process when the host supplies both
# Windows' canonical "Path" key and an additional case-variant "PATH" key.
$environmentKeys = @([Environment]::GetEnvironmentVariables().Keys)
if (($environmentKeys -ccontains "Path") -and ($environmentKeys -ccontains "PATH")) {
[Environment]::SetEnvironmentVariable("PATH", $null, [EnvironmentVariableTarget]::Process)
}
$env:PYTHONPYCACHEPREFIX = $cache
$stdout = Join-Path $logs "server-$Port.log"
$stderr = Join-Path $logs "server-$Port.err.log"
function Get-ListeningProcessId {
param([int]$LocalPort)
$pattern = "^\s*TCP\s+\S+:$LocalPort\s+\S+\s+LISTENING\s+(\d+)\s*$"
$match = netstat -ano -p TCP | Select-String -Pattern $pattern | Select-Object -First 1
if ($match) {
return [int]$match.Matches[0].Groups[1].Value
}
return $null
}
$pidFile = Join-Path $runtime "server-$Port.pid"
$serverProcessId = Get-ListeningProcessId -LocalPort $Port
if ($serverProcessId) {
Set-Content -LiteralPath $pidFile -Value $serverProcessId -Encoding ascii
Write-Output "Already running PID ${serverProcessId}: http://${BindAddress}:$Port/"
Write-Output "Logs: $stdout"
exit 0
}
$childCommand = "& '$($launcher.Source.Replace("'", "''"))' -u server.py --host '$($BindAddress.Replace("'", "''"))' --port $Port 1> '$($stdout.Replace("'", "''"))' 2> '$($stderr.Replace("'", "''"))'"
$encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($childCommand))
$process = Start-Process `
-FilePath (Join-Path $PSHOME "powershell.exe") `
-ArgumentList @("-NoProfile", "-ExecutionPolicy", "Bypass", "-EncodedCommand", $encodedCommand) `
-WorkingDirectory $root `
-WindowStyle Hidden `
-PassThru
$serverProcessId = $null
for ($attempt = 0; $attempt -lt 100; $attempt++) {
$listeningProcessId = Get-ListeningProcessId -LocalPort $Port
if ($listeningProcessId) {
$serverProcessId = $listeningProcessId
break
}
if ($process.HasExited) {
break
}
Start-Sleep -Milliseconds 100
}
if (-not $serverProcessId) {
$detail = Get-Content -LiteralPath $stderr -Raw -ErrorAction SilentlyContinue
throw "Server did not listen on port $Port. $detail"
}
Set-Content -LiteralPath $pidFile -Value $serverProcessId -Encoding ascii
Write-Output "Started PID ${serverProcessId}: http://${BindAddress}:$Port/"
Write-Output "Logs: $stdout"