Ctrl K
ComunidadGuías…

scripts/check-local-runtime.ps1

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<#
.SYNOPSIS
Checks the local telesrv runtime state.

.DESCRIPTION
Reports the listening PID/process, git commit, schema version, MTProto port,
Android connection/package status, and recent server log errors. The script is
read-only and is intended to run before/after Android and TDesktop validation.
#>
[CmdletBinding()]
param(
    [int]$Port = 2398,
    [string]$ServerLogPath,
    [string]$AndroidPackage = "org.telegram.messenger.beta",
    [string]$DeviceSerial,
    [string]$PostgresContainer = "telesrv-postgres",
    [string]$Database,
    [string]$DbUser = "telesrv",
    [int]$RecentLogLines = 1200,
    [switch]$SkipAdb
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot ".."))
if (-not $ServerLogPath) {
    $latestLog = Get-ChildItem (Join-Path $RepoRoot "logs") -Filter "telesrv-*.err.log" -ErrorAction SilentlyContinue |
        Sort-Object LastWriteTime -Descending |
        Select-Object -First 1
    if ($latestLog) {
        $ServerLogPath = $latestLog.FullName
    } else {
        $ServerLogPath = Join-Path $RepoRoot "logs\telesrv.err.log"
    }
}

$Failures = New-Object System.Collections.Generic.List[string]

function Write-Step([string]$Message) {
    Write-Host ""
    Write-Host "== $Message =="
}

function Add-Failure([string]$Message) {
    $script:Failures.Add($Message) | Out-Null
    Write-Host "[fail] $Message"
}

function Write-Ok([string]$Message) {
    Write-Host "[ok] $Message"
}

function Invoke-External {
    param(
        [string]$FilePath,
        [string[]]$Arguments,
        [switch]$AllowFailure
    )
    $oldErrorActionPreference = $ErrorActionPreference
    $ErrorActionPreference = "Continue"
    try {
        $output = & $FilePath @Arguments 2>&1
        $exitCode = $LASTEXITCODE
    } finally {
        $ErrorActionPreference = $oldErrorActionPreference
    }
    $text = ($output | ForEach-Object { $_.ToString() }) -join "`n"
    if ($exitCode -ne 0 -and -not $AllowFailure) {
        throw "$FilePath $($Arguments -join ' ') failed with exit code ${exitCode}:`n$text"
    }
    [pscustomobject]@{ ExitCode = $exitCode; Output = $text }
}

function Invoke-PsqlScalar([string]$Sql) {
    $result = Invoke-External "docker" @(
        "exec", $PostgresContainer,
        "psql", "-U", $DbUser, "-d", $Database,
        "-v", "ON_ERROR_STOP=1",
        "-At", "-c", $Sql
    ) -AllowFailure
    if ($result.ExitCode -ne 0) {
        Add-Failure "PostgreSQL query failed: $($result.Output)"
        return ""
    }
    return $result.Output.Trim()
}

function Read-SharedLogLines {
    if (-not (Test-Path -LiteralPath $ServerLogPath)) {
        return @()
    }
    $stream = [System.IO.File]::Open($ServerLogPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
    try {
        $reader = New-Object System.IO.StreamReader($stream)
        try {
            $lines = New-Object System.Collections.Generic.List[string]
            while (-not $reader.EndOfStream) {
                $lines.Add($reader.ReadLine()) | Out-Null
            }
            return $lines
        } finally {
            $reader.Dispose()
        }
    } finally {
        $stream.Dispose()
    }
}

function Get-AdbArgs([string[]]$Arguments) {
    if ($DeviceSerial) {
        return @("-s", $DeviceSerial) + $Arguments
    }
    return $Arguments
}

function Invoke-Adb([string[]]$Arguments, [switch]$AllowFailure) {
    Invoke-External "adb" (Get-AdbArgs $Arguments) -AllowFailure:$AllowFailure
}

function Get-JsonFieldFromLog {
    param([string[]]$Lines, [string]$Field)
    for ($i = $Lines.Count - 1; $i -ge 0; $i--) {
        if ($Lines[$i] -match ('"' + [regex]::Escape($Field) + '"\s*:\s*"?([^",}]+)"?')) {
            return $Matches[1]
        }
    }
    return ""
}

Write-Step "Git"
Push-Location $RepoRoot
try {
    $head = (Invoke-External "git" @("rev-parse", "HEAD") -AllowFailure).Output.Trim()
    $branch = (Invoke-External "git" @("branch", "--show-current") -AllowFailure).Output.Trim()
    $dirty = (Invoke-External "git" @("status", "--porcelain", "--untracked-files=no") -AllowFailure).Output.Trim()
    Write-Host "branch=$branch"
    Write-Host "head=$head"
    if ($dirty) {
        Write-Host "tree_state=dirty"
    } else {
        Write-Host "tree_state=clean"
    }
} finally {
    Pop-Location
}

if ([string]::IsNullOrWhiteSpace($Database)) {
    switch ($branch) {
        "main" { $Database = "telesrv_main" }
        "v2" { $Database = "telesrv_v2" }
        default {
            Add-Failure "branch '$branch' has no implicit local PostgreSQL database; pass -Database"
            $Database = "telesrv"
        }
    }
}
Write-Host "database=$Database"

Write-Step "Process and Port"
$listeners = @(Get-NetTCPConnection -LocalPort $Port -State Listen -ErrorAction SilentlyContinue)
if ($listeners.Count -eq 0) {
    Add-Failure "no process is listening on port $Port"
} else {
    foreach ($ownerPid in @($listeners | Select-Object -ExpandProperty OwningProcess -Unique)) {
        $proc = Get-Process -Id $ownerPid -ErrorAction SilentlyContinue
        if ($proc) {
            $path = $null
            try { $path = $proc.Path } catch { $path = "" }
            Write-Host ("pid={0} name={1} start={2} path={3}" -f $proc.Id, $proc.ProcessName, $proc.StartTime, $path)
        } else {
            Write-Host "pid=$ownerPid"
        }
    }
    Write-Ok "port $Port is listening"
}
$established = @(Get-NetTCPConnection -LocalPort $Port -State Established -ErrorAction SilentlyContinue)
Write-Host "established_connections=$($established.Count)"
foreach ($conn in $established | Select-Object -First 12) {
    Write-Host ("  {0}:{1} -> {2}:{3} pid={4}" -f $conn.LocalAddress, $conn.LocalPort, $conn.RemoteAddress, $conn.RemotePort, $conn.OwningProcess)
}

Write-Step "PostgreSQL Schema"
$schema = Invoke-PsqlScalar "SELECT version::text || '|' || dirty::text FROM schema_migrations ORDER BY version DESC LIMIT 1;"
if ($schema) {
    $parts = $schema -split "\|", 2
    Write-Host "schema_version=$($parts[0])"
    Write-Host "schema_dirty=$($parts[1])"
    $schemaDirty = ""
    if ($parts.Count -gt 1) {
        $schemaDirty = $parts[1].Trim().ToLowerInvariant()
    }
    if ($schemaDirty -in @("f", "false", "0")) {
        Write-Ok "schema is clean"
    } else {
        Add-Failure "schema_migrations is dirty"
    }
}

Write-Step "Server Log"
Write-Host "log=$ServerLogPath"
$lines = @(Read-SharedLogLines)
if ($lines.Count -eq 0) {
    Add-Failure "server log is missing or empty"
} else {
    $readyLines = @($lines | Where-Object { $_ -like "*telesrv server ready*" })
    if ($readyLines.Count -gt 0) {
        $ready = @($readyLines)[-1]
        Write-Host $ready
        $runtimeCommit = Get-JsonFieldFromLog @($ready) "git_commit"
        $runtimeSchema = Get-JsonFieldFromLog @($ready) "schema_version"
        $runtimePID = Get-JsonFieldFromLog @($ready) "pid"
        Write-Host "runtime_git_commit=$runtimeCommit"
        Write-Host "runtime_schema_version=$runtimeSchema"
        Write-Host "runtime_pid=$runtimePID"
        if ($head -and $runtimeCommit -and $runtimeCommit -ne $head) {
            Add-Failure "runtime git_commit $runtimeCommit != HEAD $head"
        } elseif ($runtimeCommit) {
            Write-Ok "runtime commit matches HEAD"
        }
    } else {
        Add-Failure "server log has no 'telesrv server ready' line"
    }
    $recent = @($lines | Select-Object -Last $RecentLogLines)
    $bad = @($recent | Where-Object {
        $_ -cmatch "INTERNAL_SERVER_ERROR|Unhandled RPC|NOT_IMPLEMENTED|bad_msg|panic|\tERROR\t"
    })
    if ($bad.Count -eq 0) {
        Write-Ok "recent log has no internal/unhandled/bad_msg errors"
    } else {
        Add-Failure "recent log has $($bad.Count) suspicious error lines"
        $bad | Select-Object -Last 40 | ForEach-Object { Write-Host $_ }
    }
}

Write-Step "Android"
if ($SkipAdb) {
    Write-Host "adb checks skipped"
} else {
    $adb = Get-Command adb -ErrorAction SilentlyContinue
    if (-not $adb) {
        Add-Failure "adb is not available"
    } else {
        $devices = Invoke-Adb @("devices") -AllowFailure
        $deviceLines = @($devices.Output -split "`r?`n" | Where-Object { $_ -match "\tdevice$" })
        Write-Host "adb_devices=$($deviceLines.Count)"
        if ($deviceLines.Count -lt 1) {
            Add-Failure "no adb device connected"
        } elseif ($deviceLines.Count -gt 1 -and -not $DeviceSerial) {
            Add-Failure "multiple adb devices; pass -DeviceSerial"
        } else {
            $model = (Invoke-Adb @("shell", "getprop", "ro.product.model") -AllowFailure).Output.Trim()
            $sdk = (Invoke-Adb @("shell", "getprop", "ro.build.version.sdk") -AllowFailure).Output.Trim()
            $pkg = Invoke-Adb @("shell", "dumpsys", "package", $AndroidPackage) -AllowFailure
            Write-Host "device_model=$model sdk=$sdk"
            if ($pkg.Output -match "versionName=([^\r\n]+)") {
                Write-Ok "Android package $AndroidPackage installed version=$($Matches[1])"
            } else {
                Add-Failure "Android package $AndroidPackage not found"
            }
        }
    }
}

Write-Host ""
if ($Failures.Count -gt 0) {
    Write-Host "Runtime check failed:"
    foreach ($failure in $Failures) {
        Write-Host " - $failure"
    }
    exit 1
}
Write-Host "Runtime check passed."