Pax8API/Private/Start-Pax8OpenApiUpdateCheck.ps1
|
function Start-Pax8OpenApiUpdateCheck { [CmdletBinding()] param ( [int]$MinimumIntervalHours = 12 ) if ($env:PAX8API_DISABLE_UPDATE_CHECK -match '^(1|true|yes)$') { return } $localManifest = Get-Pax8LocalSpecManifest if (-not $localManifest) { return } $cachePath = Get-Pax8UpdateCheckCachePath if (Test-Path -LiteralPath $cachePath) { try { $cached = Get-Content -LiteralPath $cachePath -Raw | ConvertFrom-Json if ($cached.checkedAt) { $lastChecked = [datetimeoffset]::Parse([string]$cached.checkedAt) if ($lastChecked -gt [datetimeoffset]::UtcNow.AddHours(-1 * $MinimumIntervalHours)) { return } } } catch { Write-Verbose "Ignoring unreadable Pax8 update-check cache: $($_.Exception.Message)" } } $manifestJson = $localManifest | ConvertTo-Json -Depth 20 -Compress $jobScript = { param($LocalManifestJson, $CachePath) try { $localManifest = $LocalManifestJson | ConvertFrom-Json $remoteSpecs = foreach ($spec in @($localManifest.specs)) { $uri = [string]$spec.url $response = Invoke-WebRequest -Uri $uri -UseBasicParsing -TimeoutSec 30 $bytes = [System.Text.Encoding]::UTF8.GetBytes([string]$response.Content) $stream = [System.IO.MemoryStream]::new($bytes) try { $hash = (Get-FileHash -InputStream $stream -Algorithm SHA256).Hash.ToLowerInvariant() } finally { $stream.Dispose() } $json = $response.Content | ConvertFrom-Json [pscustomobject]@{ file = [string]$spec.file url = $uri sha256 = $hash bytes = $bytes.Length title = [string]$json.info.title version = [string]$json.info.version pathCount = ($json.paths.PSObject.Properties | Measure-Object).Count operationCount = (($json.paths.PSObject.Properties.Value | ForEach-Object { $_.PSObject.Properties.Name }) | Where-Object { $_ -in @('get', 'post', 'put', 'patch', 'delete') } | Measure-Object).Count } } $localByFile = @{} foreach ($spec in @($localManifest.specs)) { $localByFile[[string]$spec.file] = $spec } $changed = @() foreach ($remoteSpec in @($remoteSpecs)) { $localSpec = $localByFile[[string]$remoteSpec.file] if (-not $localSpec -or $localSpec.sha256 -ne $remoteSpec.sha256 -or [int]$localSpec.operationCount -ne [int]$remoteSpec.operationCount) { $changed += $remoteSpec.file } } [pscustomobject]@{ checkedAt = [datetimeoffset]::UtcNow.ToString('o') source = 'https://devx.pax8.com/openapi' updateAvailable = [bool]($changed.Count -gt 0) changedSpecs = @($changed) localGeneratedAt = [string]$localManifest.generatedAt generatedOperationCount = [int]$localManifest.generatedOperationCount localOperationCount = [int](($localManifest.specs | Measure-Object -Property operationCount -Sum).Sum) remoteOperationCount = [int](($remoteSpecs | Measure-Object -Property operationCount -Sum).Sum) } | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $CachePath -Encoding utf8NoBOM } catch { [pscustomobject]@{ checkedAt = [datetimeoffset]::UtcNow.ToString('o') source = 'https://devx.pax8.com/openapi' updateAvailable = $false error = $_.Exception.Message } | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $CachePath -Encoding utf8NoBOM } } if (Get-Command Start-ThreadJob -ErrorAction SilentlyContinue) { Start-ThreadJob -Name 'Pax8OpenApiUpdateCheck' -ScriptBlock $jobScript -ArgumentList $manifestJson, $cachePath | Out-Null } elseif (Get-Command Start-Job -ErrorAction SilentlyContinue) { Start-Job -Name 'Pax8OpenApiUpdateCheck' -ScriptBlock $jobScript -ArgumentList $manifestJson, $cachePath | Out-Null } } |