199 lines
8.1 KiB
PowerShell
199 lines
8.1 KiB
PowerShell
# native process mode (called by start.ps1 when Docker is unavailable)
|
||
param(
|
||
[switch]$Rebuild,
|
||
[switch]$NoBrowser,
|
||
[switch]$ShowConsole # show service windows (debug); default: hidden
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
$Root = $PSScriptRoot
|
||
Set-Location -LiteralPath $Root
|
||
$LogDir = Join-Path $Root ".runtime\logs"
|
||
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
|
||
|
||
# Always wipe previous native/docker leftovers before binding ports
|
||
Write-Host "==> Pre-clean before native start" -ForegroundColor DarkGray
|
||
& (Join-Path $Root "scripts\Stop-Stack.ps1") -Quiet
|
||
Start-Sleep -Seconds 1
|
||
|
||
Write-Host "==> Native mode: need Go / Python / Node / PostgreSQL" -ForegroundColor Yellow
|
||
if (-not $ShowConsole) {
|
||
Write-Host " services run hidden; logs -> .runtime\logs\" -ForegroundColor DarkGray
|
||
}
|
||
|
||
function Clear-Port([int]$port) {
|
||
$conns = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
|
||
foreach ($c in $conns) {
|
||
$procId = $c.OwningProcess
|
||
if ($procId -gt 0) {
|
||
Write-Host " free port $port (pid=$procId)"
|
||
& taskkill.exe /F /T /PID $procId 2>$null | Out-Null
|
||
Stop-Process -Id $procId -Force -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
}
|
||
|
||
Write-Host "==> Clearing ports 8888/8001/8180/5173"
|
||
foreach ($p in 8888, 8001, 8180, 5173) { Clear-Port $p }
|
||
Start-Sleep -Seconds 1
|
||
|
||
function Reset-LogFile([string]$path) {
|
||
try {
|
||
if (Test-Path -LiteralPath $path) {
|
||
# 句柄未释放时 Set-Content 会失败:先挪走旧文件
|
||
$prev = "$path.prev"
|
||
Remove-Item -LiteralPath $prev -Force -ErrorAction SilentlyContinue
|
||
Move-Item -LiteralPath $path -Destination $prev -Force -ErrorAction Stop
|
||
}
|
||
Set-Content -LiteralPath $path -Value "" -Encoding UTF8
|
||
return $path
|
||
} catch {
|
||
$alt = ($path -replace '\.log$', ".$(Get-Date -Format 'HHmmss').log")
|
||
Set-Content -LiteralPath $alt -Value "" -Encoding UTF8
|
||
return $alt
|
||
}
|
||
}
|
||
|
||
function Start-Svc($name, $workDir, $filePath, $argumentList) {
|
||
$outLog = Reset-LogFile (Join-Path $LogDir "$name.out.log")
|
||
$errLog = Reset-LogFile (Join-Path $LogDir "$name.err.log")
|
||
$pidFile = Join-Path $LogDir "$name.pid"
|
||
|
||
if ($ShowConsole) {
|
||
$argStr = ""
|
||
if ($argumentList) {
|
||
$parts = @()
|
||
foreach ($a in $argumentList) {
|
||
if ($a -match '\s') { $parts += ('"' + $a + '"') } else { $parts += $a }
|
||
}
|
||
$argStr = $parts -join ' '
|
||
}
|
||
$cmd = "Set-Location -LiteralPath '$workDir'; Write-Host '[$name]' -ForegroundColor Cyan; & '$filePath' $argStr"
|
||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList @(
|
||
"-NoExit", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", $cmd
|
||
) -WorkingDirectory $workDir -PassThru
|
||
} else {
|
||
$p = Start-Process -FilePath $filePath `
|
||
-ArgumentList $argumentList `
|
||
-WorkingDirectory $workDir `
|
||
-WindowStyle Hidden `
|
||
-RedirectStandardOutput $outLog `
|
||
-RedirectStandardError $errLog `
|
||
-PassThru
|
||
}
|
||
if ($p) { Set-Content -LiteralPath $pidFile -Value $p.Id -Encoding ASCII }
|
||
Write-Host " started $name (pid=$($p.Id))" -ForegroundColor DarkGray
|
||
}
|
||
|
||
$plat = Join-Path $Root "platform\platform.exe"
|
||
$gw = Join-Path $Root "gateway\gateway.exe"
|
||
# 默认重编译,避免改 Go 源码后 restart 仍跑旧 exe
|
||
$needPlat = $Rebuild -or -not (Test-Path $plat)
|
||
$needGw = $Rebuild -or -not (Test-Path $gw)
|
||
if (-not $needPlat -and (Test-Path $plat)) {
|
||
$exeTime = (Get-Item $plat).LastWriteTime
|
||
$newer = Get-ChildItem -Path (Join-Path $Root "platform") -Recurse -Include *.go -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.LastWriteTime -gt $exeTime } |
|
||
Select-Object -First 1
|
||
if ($newer) { $needPlat = $true }
|
||
}
|
||
if (-not $needGw -and (Test-Path $gw)) {
|
||
$exeTime = (Get-Item $gw).LastWriteTime
|
||
$newer = Get-ChildItem -Path (Join-Path $Root "gateway") -Recurse -Include *.go -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.LastWriteTime -gt $exeTime } |
|
||
Select-Object -First 1
|
||
if ($newer) { $needGw = $true }
|
||
}
|
||
if ($needPlat) {
|
||
Write-Host " building platform.exe ..." -ForegroundColor DarkGray
|
||
Push-Location (Join-Path $Root "platform")
|
||
go build -o platform.exe .
|
||
Pop-Location
|
||
}
|
||
if ($needGw) {
|
||
Write-Host " building gateway.exe ..." -ForegroundColor DarkGray
|
||
Push-Location (Join-Path $Root "gateway")
|
||
go build -o gateway.exe .
|
||
Pop-Location
|
||
}
|
||
|
||
Write-Host "==> Ensure web frontend (vite /#/preview)" -ForegroundColor DarkGray
|
||
& (Join-Path $Root "scripts\Ensure-Web.ps1")
|
||
# $? 判断 PS 脚本成败;勿单靠 $LASTEXITCODE(会残留 docker/compose 等 native 失败码)
|
||
if (-not $?) { throw "Ensure-Web failed" }
|
||
|
||
$pyCmd = Get-Command python -ErrorAction SilentlyContinue
|
||
if (-not $pyCmd) { $pyCmd = Get-Command py -ErrorAction SilentlyContinue }
|
||
if (-not $pyCmd) { throw "python not found" }
|
||
$py = $pyCmd.Source
|
||
|
||
$npmCmd = Get-Command npm.cmd -ErrorAction SilentlyContinue
|
||
if (-not $npmCmd) { $npmCmd = Get-Command npm -ErrorAction SilentlyContinue }
|
||
if (-not $npmCmd) { throw "npm not found" }
|
||
|
||
# AI 截图直达本机 Vite
|
||
$env:WEB_BASE = "http://127.0.0.1:5173"
|
||
$env:PLATFORM_BASE = "http://127.0.0.1:8888"
|
||
$env:GATEWAY_BASE = "http://127.0.0.1:8180"
|
||
$env:GENERATE_LOG_DIR = Join-Path $Root ".runtime\logs\generate"
|
||
$env:FIDELITY_SHOT_DIR = Join-Path $Root ".runtime\fidelity_shots"
|
||
|
||
Start-Svc "platform" (Join-Path $Root "platform") $plat @("-f", "etc/platform.yaml")
|
||
Start-Sleep -Seconds 2
|
||
Start-Svc "ai-service" (Join-Path $Root "ai-service") $py @("-m", "uvicorn", "app:app", "--host", "127.0.0.1", "--port", "8001", "--reload")
|
||
Start-Sleep -Seconds 1
|
||
Start-Svc "gateway" (Join-Path $Root "gateway") $gw @("-f", "etc/gateway.yaml")
|
||
Start-Sleep -Seconds 1
|
||
Start-Svc "web" (Join-Path $Root "web") $npmCmd.Source @("run", "dev", "--", "--host", "127.0.0.1", "--port", "5173", "--strictPort")
|
||
|
||
Write-Host "==> Waiting for services..."
|
||
$deadline = (Get-Date).AddSeconds(45)
|
||
do {
|
||
$webOk = $false
|
||
$gwOk = $false
|
||
try {
|
||
$r = Invoke-WebRequest -Uri "http://127.0.0.1:5173/" -UseBasicParsing -TimeoutSec 2
|
||
if ($r.StatusCode -lt 500) { $webOk = $true }
|
||
} catch {}
|
||
try {
|
||
$r = Invoke-WebRequest -Uri "http://127.0.0.1:8180/gateway/health" -UseBasicParsing -TimeoutSec 2
|
||
if ($r.StatusCode -lt 500) { $gwOk = $true }
|
||
} catch {}
|
||
if ($webOk -and $gwOk) { break }
|
||
Start-Sleep -Seconds 1
|
||
} while ((Get-Date) -lt $deadline)
|
||
|
||
if ($webOk -and $gwOk) {
|
||
Write-Host "OK Web http://127.0.0.1:5173 Gateway http://127.0.0.1:8180 account demo/demo123" -ForegroundColor Green
|
||
Write-Host " logs $LogDir" -ForegroundColor DarkGray
|
||
} else {
|
||
Write-Host "WARN some services not ready yet. Check logs:" -ForegroundColor Yellow
|
||
Write-Host " $LogDir"
|
||
Write-Host " web=$webOk gateway=$gwOk"
|
||
Write-Host " (debug with visible windows: .\start-host.ps1 -ShowConsole)"
|
||
}
|
||
|
||
# 后台看门狗:ai-service / gateway 挂掉自动拉起
|
||
$watchPidFile = Join-Path $LogDir "watchdog.pid"
|
||
if (Test-Path $watchPidFile) {
|
||
$oldWatch = Get-Content $watchPidFile -ErrorAction SilentlyContinue
|
||
if ($oldWatch) { Stop-Process -Id ([int]$oldWatch) -Force -ErrorAction SilentlyContinue }
|
||
}
|
||
$watchScript = Join-Path $Root "watch-services.ps1"
|
||
$watchOut = Join-Path $LogDir "watchdog.out.log"
|
||
$watchErr = Join-Path $LogDir "watchdog.err.log"
|
||
Set-Content -LiteralPath $watchOut -Value "" -Encoding UTF8
|
||
Set-Content -LiteralPath $watchErr -Value "" -Encoding UTF8
|
||
$wp = Start-Process -FilePath "powershell.exe" `
|
||
-ArgumentList @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $watchScript) `
|
||
-WorkingDirectory $Root `
|
||
-WindowStyle Hidden `
|
||
-RedirectStandardOutput $watchOut `
|
||
-RedirectStandardError $watchErr `
|
||
-PassThru
|
||
if ($wp) {
|
||
Set-Content -LiteralPath $watchPidFile -Value $wp.Id -Encoding ASCII
|
||
Write-Host " started watchdog (pid=$($wp.Id)) - auto-restarts ai-service if down" -ForegroundColor DarkGray
|
||
}
|
||
|
||
if (-not $NoBrowser) { Start-Process "http://127.0.0.1:5173" } |