Some checks failed
Lint & Test / test (push) Failing after 29s
- Add /api/v1/system/shutdown endpoint that triggers clean uvicorn exit - Persist all 15 stores to disk during shutdown via _save_all_stores() - Add force parameter to BaseJsonStore._save() to bypass restore freeze - Restart script now requests graceful shutdown via API (15s timeout), falls back to force-kill only if server doesn't exit in time - Broadcast server_restarting event over WebSocket before shutdown - Frontend shows "Server restarting..." overlay instantly on WS event, replacing the old dynamically-created overlay from settings.ts - Add server_ref module to share uvicorn Server + TrayManager refs - Add i18n keys for restart overlay (en/ru/zh)
108 lines
4.5 KiB
PowerShell
108 lines
4.5 KiB
PowerShell
# Restart the WLED Screen Controller server
|
|
# Uses graceful shutdown first (lets the server persist data to disk),
|
|
# then force-kills as a fallback.
|
|
|
|
$serverRoot = 'c:\Users\Alexei\Documents\wled-screen-controller\server'
|
|
|
|
# Read API key from config for authenticated shutdown request
|
|
$configPath = Join-Path $serverRoot 'config\default_config.yaml'
|
|
$apiKey = $null
|
|
if (Test-Path $configPath) {
|
|
$inKeys = $false
|
|
foreach ($line in Get-Content $configPath) {
|
|
if ($line -match '^\s*api_keys:') { $inKeys = $true; continue }
|
|
if ($inKeys -and $line -match '^\s+\w+:\s*"(.+)"') {
|
|
$apiKey = $Matches[1]; break
|
|
}
|
|
if ($inKeys -and $line -match '^\S') { break } # left the api_keys block
|
|
}
|
|
}
|
|
|
|
# Find running server processes
|
|
$procs = Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
|
|
Where-Object { $_.CommandLine -like '*wled_controller*' -and $_.CommandLine -notlike '*demo*' -and $_.CommandLine -notlike '*vscode*' -and $_.CommandLine -notlike '*isort*' }
|
|
|
|
if ($procs) {
|
|
# Step 1: Request graceful shutdown via API (triggers lifespan shutdown + store save)
|
|
$shutdownOk = $false
|
|
if ($apiKey) {
|
|
Write-Host "Requesting graceful shutdown..."
|
|
try {
|
|
$headers = @{ Authorization = "Bearer $apiKey" }
|
|
Invoke-RestMethod -Uri 'http://localhost:8080/api/v1/system/shutdown' `
|
|
-Method Post -Headers $headers -TimeoutSec 5 -ErrorAction Stop | Out-Null
|
|
$shutdownOk = $true
|
|
} catch {
|
|
Write-Host " API shutdown failed ($($_.Exception.Message)), falling back to process kill"
|
|
}
|
|
}
|
|
|
|
if ($shutdownOk) {
|
|
# Step 2: Wait for the server to exit gracefully (up to 15 seconds)
|
|
# The server needs time to stop processors, disconnect devices, and persist stores.
|
|
Write-Host "Waiting for graceful shutdown..."
|
|
$waited = 0
|
|
while ($waited -lt 15) {
|
|
Start-Sleep -Seconds 1
|
|
$waited++
|
|
$still = Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
|
|
Where-Object { $_.CommandLine -like '*wled_controller*' -and $_.CommandLine -notlike '*demo*' -and $_.CommandLine -notlike '*vscode*' -and $_.CommandLine -notlike '*isort*' }
|
|
if (-not $still) {
|
|
Write-Host " Server exited cleanly after ${waited}s"
|
|
break
|
|
}
|
|
}
|
|
# Step 3: Force-kill stragglers
|
|
$still = Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
|
|
Where-Object { $_.CommandLine -like '*wled_controller*' -and $_.CommandLine -notlike '*demo*' -and $_.CommandLine -notlike '*vscode*' -and $_.CommandLine -notlike '*isort*' }
|
|
if ($still) {
|
|
Write-Host " Force-killing remaining processes..."
|
|
foreach ($p in $still) {
|
|
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
|
|
}
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
} else {
|
|
# No API key or API call failed — force-kill directly
|
|
foreach ($p in $procs) {
|
|
Write-Host "Stopping server (PID $($p.ProcessId))..."
|
|
Stop-Process -Id $p.ProcessId -Force -ErrorAction SilentlyContinue
|
|
}
|
|
Start-Sleep -Seconds 2
|
|
}
|
|
}
|
|
|
|
# Merge registry PATH with current PATH so newly-installed tools (e.g. scrcpy) are visible
|
|
$regUser = [Environment]::GetEnvironmentVariable('PATH', 'User')
|
|
if ($regUser) {
|
|
$currentDirs = $env:PATH -split ';' | ForEach-Object { $_.TrimEnd('\') }
|
|
foreach ($dir in ($regUser -split ';')) {
|
|
if ($dir -and ($currentDirs -notcontains $dir.TrimEnd('\'))) {
|
|
$env:PATH = "$env:PATH;$dir"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Start server detached (set WLED_RESTART=1 to skip browser open)
|
|
Write-Host "Starting server..."
|
|
$env:WLED_RESTART = "1"
|
|
$pythonExe = (Get-Command python -ErrorAction SilentlyContinue).Source
|
|
if (-not $pythonExe) {
|
|
# Fallback to known install location
|
|
$pythonExe = "$env:LOCALAPPDATA\Programs\Python\Python313\python.exe"
|
|
}
|
|
Start-Process -FilePath $pythonExe -ArgumentList '-m', 'wled_controller' `
|
|
-WorkingDirectory $serverRoot `
|
|
-WindowStyle Hidden
|
|
|
|
Start-Sleep -Seconds 3
|
|
|
|
# Verify it's running
|
|
$check = Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
|
|
Where-Object { $_.CommandLine -like '*wled_controller*' -and $_.CommandLine -notlike '*demo*' -and $_.CommandLine -notlike '*vscode*' -and $_.CommandLine -notlike '*isort*' }
|
|
if ($check) {
|
|
Write-Host "Server started (PID $($check[0].ProcessId))"
|
|
} else {
|
|
Write-Host "WARNING: Server does not appear to be running!"
|
|
}
|