[CmdletBinding()] param( [Parameter(Mandatory)][ValidatePattern('^[0-9a-fA-F-]{36}$')][string]$SourceEndpointId, [Parameter(Mandatory)][string]$FromNodeId, [Parameter(Mandatory)][string]$ToNodeId, [Parameter(Mandatory)][string]$ReadyMarker, [Parameter(Mandatory)][string]$StartMarker, [Parameter(Mandatory)][string]$OutputDirectory, [string]$CoordinatorUrl = 'http://127.0.0.1:18100', [string]$CredentialFile = (Join-Path (Split-Path -Parent $PSScriptRoot) 'runtime/cluster.local.properties'), [ValidateRange(1,300)][int]$WaitSeconds = 90, [ValidateRange(1,3600)][int]$DurationSeconds = 25 ) $ErrorActionPreference = 'Stop' $readyPath = [IO.Path]::GetFullPath($ReadyMarker) $startPath = [IO.Path]::GetFullPath($StartMarker) [void][IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($readyPath)) $readyAt = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() $requestId = [Guid]::NewGuid().ToString() # 只保存随机门闩与公开业务标识,文件中没有集群密钥、浏览器会话或图片访问地址。 $ready = [ordered]@{ requestId = $requestId; endpointId = $SourceEndpointId; fromNodeId = $FromNodeId toNodeId = $ToNodeId; readyAtMs = $readyAt } [IO.File]::WriteAllText($readyPath, ($ready | ConvertTo-Json -Compress), [Text.UTF8Encoding]::new($false)) Write-Output '迁移脚本已等待前端采样启动信号,尚未改容量。' $deadline = [DateTimeOffset]::UtcNow.AddSeconds($WaitSeconds) $started = $false while ([DateTimeOffset]::UtcNow -lt $deadline) { if (Test-Path -LiteralPath $startPath) { try { $marker = [IO.File]::ReadAllText($startPath) | ConvertFrom-Json $now = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds() # 匹配本次随机门闩,并要求浏览器采样已开始、时间新鲜,旧文件不能触发迁移。 if ($marker.requestId -eq $requestId -and $marker.endpointId -eq $SourceEndpointId -and [long]$marker.startedAtMs -ge $readyAt -and [long]$marker.startedAtMs -le $now + 1000 -and $now - [long]$marker.startedAtMs -le 5000) { $started = $true; break } } catch { } } Start-Sleep -Milliseconds 100 } if (-not $started) { throw '前端采样启动信号等待超时,未修改容量。' } Write-Output '前端采样启动信号已匹配,开始已授权的原图迁移。' & (Join-Path $PSScriptRoot 'Observe-OriginalImage.ps1') -CoordinatorUrl $CoordinatorUrl -CredentialFile $CredentialFile ` -SourceEndpointId $SourceEndpointId -FromNodeId $FromNodeId -ToNodeId $ToNodeId -Migrate -QuietFrames ` -DurationSeconds $DurationSeconds -PollMilliseconds 200 -OutputDirectory $OutputDirectory