diff --git a/pc/start_streamdeck.ps1 b/pc/start_streamdeck.ps1 index 1ef22ef..64d3750 100644 --- a/pc/start_streamdeck.ps1 +++ b/pc/start_streamdeck.ps1 @@ -8,6 +8,7 @@ $repoRoot = Split-Path -Parent $PSScriptRoot $overlayDir = Join-Path $repoRoot "overlay" $dataDir = Join-Path $repoRoot "data" $launcherLog = Join-Path $dataDir "startup-launcher.log" +$backendUrl = "http://127.0.0.1:8000/api/state" if (-not (Test-Path $dataDir)) { New-Item -ItemType Directory -Path $dataDir | Out-Null @@ -21,16 +22,11 @@ function Write-LauncherLog { function Resolve-PythonPath { $venvPython = Join-Path $repoRoot ".venv\Scripts\python.exe" - if (Test-Path $venvPython) { - return $venvPython + if (-not (Test-Path $venvPython)) { + throw "Project Python environment not found: $venvPython. Run: py -3.14 -m venv .venv" } - $pythonCmd = Get-Command python -ErrorAction SilentlyContinue - if ($null -ne $pythonCmd) { - return $pythonCmd.Source - } - - throw "Could not find Python. Install Python or create .venv first." + return (Resolve-Path $venvPython).Path } function Resolve-NpmPath { @@ -42,6 +38,18 @@ function Resolve-NpmPath { throw "Could not find npm.cmd. Install Node.js/npm first." } +function Test-PythonRuntime { + param([string]$PythonPath) + + $output = & $PythonPath -c "import uvicorn, backend.main; print('backend imports OK')" 2>&1 + if ($LASTEXITCODE -ne 0) { + $details = ($output | Out-String).Trim() + throw "Backend Python runtime validation failed: $details" + } + + Write-LauncherLog "Python runtime verified: $PythonPath" +} + function Start-HiddenProcess { param( [string]$Name, @@ -54,18 +62,54 @@ function Start-HiddenProcess { if ($DryRun) { Write-LauncherLog "DRY RUN -> $Name | $FilePath $($Arguments -join ' ')" - return + return $null } - Start-Process ` + $process = Start-Process ` -FilePath $FilePath ` -ArgumentList $Arguments ` -WorkingDirectory $WorkingDirectory ` -WindowStyle Hidden ` -RedirectStandardOutput $StdOutPath ` - -RedirectStandardError $StdErrPath | Out-Null + -RedirectStandardError $StdErrPath ` + -PassThru - Write-LauncherLog "Started $Name." + Write-LauncherLog "Started $Name process (PID $($process.Id))." + return $process +} + +function Test-BackendReady { + try { + $response = Invoke-WebRequest -UseBasicParsing -Uri $backendUrl -Method Get -TimeoutSec 2 -ErrorAction Stop + return $response.StatusCode -eq 200 + } catch { + return $false + } +} + +function Wait-ForBackendReady { + param( + [System.Diagnostics.Process]$Process, + [int]$TimeoutSeconds = 30 + ) + + $deadline = (Get-Date).AddSeconds($TimeoutSeconds) + do { + if (Test-BackendReady) { + return $true + } + + if ($null -ne $Process) { + $Process.Refresh() + if ($Process.HasExited) { + return $false + } + } + + Start-Sleep -Milliseconds 500 + } while ((Get-Date) -lt $deadline) + + return $false } function Is-BackendRunning { @@ -90,23 +134,51 @@ function Is-OverlayRunning { try { $pythonPath = Resolve-PythonPath $npmPath = Resolve-NpmPath + Write-LauncherLog "Launcher using Python: $pythonPath" + + if (-not $DryRun) { + Test-PythonRuntime $pythonPath + } if (-not (Test-Path (Join-Path $repoRoot "frontend\dist\index.html"))) { Write-LauncherLog "Warning: frontend/dist is missing. Build frontend for production view." } - if (Is-BackendRunning) { - Write-LauncherLog "Backend already running. Skipping backend launch." + $backendReady = Test-BackendReady + if ($backendReady) { + Write-LauncherLog "Backend already ready at $backendUrl. Skipping backend launch." + } elseif (Is-BackendRunning) { + Write-LauncherLog "Backend process exists but is not ready. Waiting for $backendUrl." + if (-not $DryRun -and -not (Wait-ForBackendReady -TimeoutSeconds 30)) { + throw "Existing backend process did not become ready at $backendUrl. See data/backend.stderr.log." + } + $backendReady = $true + Write-LauncherLog "Backend ready at $backendUrl." } else { $backendOut = Join-Path $dataDir "backend.stdout.log" $backendErr = Join-Path $dataDir "backend.stderr.log" - Start-HiddenProcess ` + $backendProcess = Start-HiddenProcess ` -Name "backend" ` -FilePath $pythonPath ` -Arguments @("-m", "uvicorn", "backend.main:app", "--host", "127.0.0.1", "--port", "8000") ` -WorkingDirectory $repoRoot ` -StdOutPath $backendOut ` -StdErrPath $backendErr + + if (-not $DryRun -and -not (Wait-ForBackendReady -Process $backendProcess -TimeoutSeconds 30)) { + $stderrTail = if (Test-Path $backendErr) { (Get-Content $backendErr -Tail 10 | Out-String).Trim() } else { "No backend stderr log was created." } + Write-LauncherLog "Backend failed readiness check. stderr tail: $stderrTail" + throw "Backend did not become ready at $backendUrl." + } + + $backendReady = $true + if (-not $DryRun) { + Write-LauncherLog "Backend ready at $backendUrl." + } + } + + if (-not $backendReady -and -not $DryRun) { + throw "Overlay launch skipped because the backend is not ready." } if (Is-OverlayRunning) {