# aijianzhan one-click start (Docker Compose by default; auto-starts Docker Desktop) param( [switch]$Rebuild, [switch]$UseHost, [switch]$NoBrowser, [switch]$ShowConsole, # native mode only: show service console windows [int]$DockerWaitSec = 120 ) $ErrorActionPreference = "Stop" $Root = $PSScriptRoot Set-Location -LiteralPath $Root function Write-Step([string]$msg) { Write-Host ""; Write-Host "==> $msg" -ForegroundColor Cyan } function Write-Ok([string]$msg) { Write-Host " OK $msg" -ForegroundColor Green } function Write-Warn([string]$msg) { Write-Host " !! $msg" -ForegroundColor Yellow } function Test-DockerCli { try { $null = Get-Command docker -ErrorAction Stop return $true } catch { return $false } } function Test-DockerReady { if (-not (Test-DockerCli)) { return $false } try { $old = $ErrorActionPreference $ErrorActionPreference = "Continue" $null = & docker info 2>&1 $ok = ($LASTEXITCODE -eq 0) $ErrorActionPreference = $old return $ok } catch { return $false } } function Get-DockerDesktopPath { $pf86 = [Environment]::GetEnvironmentVariable("ProgramFiles(x86)") $candidates = @( (Join-Path $env:ProgramFiles "Docker\Docker\Docker Desktop.exe"), $(if ($pf86) { Join-Path $pf86 "Docker\Docker\Docker Desktop.exe" } else { $null }), (Join-Path $env:LOCALAPPDATA "Docker\Docker Desktop.exe") ) foreach ($p in $candidates) { if ($p -and (Test-Path -LiteralPath $p)) { return $p } } return $null } function Start-DockerDesktopIfNeeded { if (Test-DockerReady) { return $true } if (-not (Test-DockerCli)) { Write-Warn "docker CLI not found; install Docker Desktop first" return $false } $exe = Get-DockerDesktopPath $proc = Get-Process -Name "Docker Desktop","com.docker.backend","com.docker.service" -ErrorAction SilentlyContinue if (-not $proc) { if (-not $exe) { Write-Warn "Docker Desktop.exe not found" return $false } Write-Step "Starting Docker Desktop" Start-Process -FilePath $exe | Out-Null Write-Ok "Docker Desktop launched; waiting for engine..." } else { Write-Step "Docker Desktop process found; waiting for engine..." } $started = Get-Date $deadline = $started.AddSeconds([Math]::Max(30, $DockerWaitSec)) $n = 0 while ((Get-Date) -lt $deadline) { if (Test-DockerReady) { Write-Ok "Docker engine ready" return $true } $n++ if ($n % 5 -eq 0) { $elapsed = [int]((Get-Date) - $started).TotalSeconds Write-Host (" ...waiting Docker ({0}s / {1}s)" -f $elapsed, $DockerWaitSec) -ForegroundColor DarkGray } Start-Sleep -Seconds 2 } Write-Warn ("Docker wait timeout ({0}s)" -f $DockerWaitSec) return $false } function Start-NativeFallback([string]$reason) { Write-Warn $reason Write-Step "Fallback to native mode (start-host.ps1)" & (Join-Path $Root "start-host.ps1") -Rebuild:$Rebuild -NoBrowser:$NoBrowser -ShowConsole:$ShowConsole exit $LASTEXITCODE } if ($UseHost) { Start-NativeFallback "UseHost specified" } $dockerReady = Start-DockerDesktopIfNeeded if (-not $dockerReady) { Start-NativeFallback "Docker not ready; fallback native. Fix Docker then rerun .\start.ps1" } Write-Step "Apply China Docker registry mirrors" & (Join-Path $Root "scripts\Apply-DockerMirrors.ps1") -NoRestartHint New-Item -ItemType Directory -Force -Path (Join-Path $Root ".runtime\pgdata") | Out-Null New-Item -ItemType Directory -Force -Path (Join-Path $Root ".runtime\uploads") | Out-Null New-Item -ItemType Directory -Force -Path (Join-Path $Root ".runtime\logs") | Out-Null # Wipe native leftovers so Docker and host never fight over the same ports Write-Step "Pre-clean ports / native leftovers" & (Join-Path $Root "scripts\Stop-Stack.ps1") -Quiet Write-Step "Build web dist (auto, includes /#/preview)" & (Join-Path $Root "scripts\Ensure-Web.ps1") -BuildDist if (-not $?) { Start-NativeFallback "web dist build failed; fallback native (vite)." } # Prefer DaoCloud-prefixed library images (see docker-compose.yml / Dockerfiles) if (-not $env:DOCKER_BASE_REGISTRY) { $env:DOCKER_BASE_REGISTRY = "docker.m.daocloud.io/library" } Write-Step "Docker Compose up (data -> .runtime)" # Prefer reuse of local images; --build only when -Rebuild (Hub often fails in CN) $composeArgs = @("compose", "up", "-d") if ($Rebuild) { $composeArgs += "--build" } & docker @composeArgs if ($LASTEXITCODE -ne 0) { Write-Warn "compose up failed; retry once with --build" & docker compose up -d --build } if ($LASTEXITCODE -ne 0) { # Hub / network failures are common in CN; keep the stack usable via native mode Start-NativeFallback "docker compose failed (Docker Hub/network). Auto fallback to native mode." } Write-Step "Waiting for gateway / web" $ok = $false for ($i = 0; $i -lt 60; $i++) { try { $h = Invoke-WebRequest -Uri "http://127.0.0.1:8180/gateway/health" -UseBasicParsing -TimeoutSec 2 $w = Invoke-WebRequest -Uri "http://127.0.0.1:5173/" -UseBasicParsing -TimeoutSec 2 if ($h.StatusCode -lt 500 -and $w.StatusCode -lt 500) { $ok = $true; break } } catch { # retry } Start-Sleep -Seconds 2 } if ($ok) { Write-Ok "services ready" } else { Write-Warn "health check timeout, see: docker compose logs" } $sql = 'ALTER USER platform CREATEDB;' & docker compose exec -T postgres psql -U platform -d platform -c $sql 2>&1 | Out-Null Write-Host "" Write-Host "========================================" -ForegroundColor Green Write-Host " Web http://127.0.0.1:5173" Write-Host " Gateway http://127.0.0.1:8180" Write-Host " Account demo / demo123" Write-Host " Data $Root\.runtime" Write-Host " Stop .\stop.ps1" Write-Host "========================================" -ForegroundColor Green if (-not $NoBrowser) { Start-Process "http://127.0.0.1:5173" }