<# .SYNOPSIS Vigilante (watchdog) de OmniRoute: garantiza que el servidor local este SIEMPRE arriba. .DESCRIPTION OmniRoute escucha en http://127.0.0.1:20128 y tarda ~60 s en quedar listo. Este vigilante: - Comprueba el puerto 20128 periodicamente. - Si no hay proceso, arranca el servidor en segundo plano (oculto, desde un directorio neutro para no contaminarse con .env de repositorios). - Si hay proceso pero no responde tras el tiempo de arranque, lo mata y lo relanza. Se lanza al iniciar sesion mediante la tarea programada "OmniRoute Watchdog". .PARAMETER Once Comprueba/arranca una sola vez, espera a que responda y sale (para pruebas). .PARAMETER IntervalSeconds Segundos entre comprobaciones del bucle de vigilancia (por defecto 120). .PARAMETER StartupTimeoutSeconds Segundos maximos de espera a que OmniRoute responda antes de considerarlo colgado. .PARAMETER UseTray Arranca OmniRoute con icono en la bandeja del sistema (por defecto NO, para maxima fiabilidad en el arranque desatendido). .NOTES Repo: biblioteca_negocio_prolongo. Regla 24 no aplica (no toca NET/VB/4GL). #> [CmdletBinding()] param( [switch]$Once, [int]$IntervalSeconds = 120, [int]$StartupTimeoutSeconds = 180, [switch]$UseTray ) $ErrorActionPreference = 'SilentlyContinue' # --- Configuracion --------------------------------------------------------- $OmniHost = '127.0.0.1' $Port = 20128 $NodeExe = 'C:\Program Files\nodejs\node.exe' $OmniRouteMjs = Join-Path $env:APPDATA 'npm\node_modules\omniroute\bin\omniroute.mjs' $WorkDir = $env:USERPROFILE # directorio neutro (sin .env de repos) $LogDir = Join-Path $env:USERPROFILE '.omniroute' $LogFile = Join-Path $LogDir 'watchdog.log' $MaxLogBytes = 1MB # --- Utilidades ------------------------------------------------------------ function Write-Log { param([string]$Message, [string]$Level = 'INFO') $line = '{0} [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir -Force | Out-Null } if ((Test-Path $LogFile) -and ((Get-Item $LogFile).Length -gt $MaxLogBytes)) { Move-Item -LiteralPath $LogFile -Destination "$LogFile.1" -Force } Add-Content -LiteralPath $LogFile -Value $line -Encoding UTF8 } function Resolve-NodeExe { if (Test-Path $NodeExe) { return $NodeExe } $cmd = Get-Command node -ErrorAction SilentlyContinue if ($cmd) { return $cmd.Source } return $NodeExe } function Test-OmniRoutePort { $client = New-Object System.Net.Sockets.TcpClient try { $iar = $client.BeginConnect($OmniHost, $Port, $null, $null) if ($iar.AsyncWaitHandle.WaitOne(2000)) { $client.EndConnect($iar) return $true } return $false } catch { return $false } finally { try { $client.Close() } catch { } } } function Get-OmniRouteProcesses { Get-CimInstance Win32_Process -Filter "Name='node.exe'" -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -and ($_.CommandLine -like '*omniroute*') -and ($_.CommandLine -like '*serve*') } } function Start-OmniRouteServer { $node = Resolve-NodeExe if (-not (Test-Path $OmniRouteMjs)) { Write-Log "No se encuentra omniroute.mjs en $OmniRouteMjs" 'ERROR' return } $argList = @("`"$OmniRouteMjs`"", 'serve', '--no-open') if ($UseTray) { $argList += '--tray' } else { $argList += '--no-tray' } Start-Process -FilePath $node ` -ArgumentList $argList ` -WorkingDirectory $WorkDir ` -WindowStyle Hidden Write-Log "Servidor OmniRoute lanzado (tray=$([bool]$UseTray))." } function Wait-OmniRouteUp { param([int]$TimeoutSeconds) for ($i = 0; $i -lt $TimeoutSeconds; $i += 3) { Start-Sleep -Seconds 3 if (Test-OmniRoutePort) { return $true } } return $false } # --- Bloqueo de instancia unica ------------------------------------------- $mutex = New-Object System.Threading.Mutex($false, 'Local\OmniRouteWatchdog') if (-not $mutex.WaitOne(0)) { Write-Log 'Ya hay otro vigilante en ejecucion. Saliendo.' 'WARN' exit 0 } # --- Modo puntual (-Once) -------------------------------------------------- if ($Once) { if (Test-OmniRoutePort) { Write-Log "Comprobacion puntual: OmniRoute ya responde en $Port." 'OK' exit 0 } $procs = @(Get-OmniRouteProcesses) if ($procs.Count -eq 0) { Write-Log 'Comprobacion puntual: OmniRoute caido. Arrancando...' 'WARN' Start-OmniRouteServer } else { Write-Log "Comprobacion puntual: proceso presente (PID $($procs[0].ProcessId)), esperando puerto..." 'WARN' } if (Wait-OmniRouteUp -TimeoutSeconds $StartupTimeoutSeconds) { Write-Log "Comprobacion puntual: OmniRoute arriba en $Port." 'OK' exit 0 } Write-Log "Comprobacion puntual: OmniRoute NO respondio en $StartupTimeoutSeconds s." 'ERROR' exit 1 } # --- Bucle de vigilancia --------------------------------------------------- Write-Log 'Vigilante de OmniRoute iniciado.' $downSince = $null while ($true) { if (Test-OmniRoutePort) { if ($downSince) { Write-Log "OmniRoute vuelve a responder en $Port." 'OK' } $downSince = $null } else { $procs = @(Get-OmniRouteProcesses) if ($procs.Count -gt 0) { if (-not $downSince) { $downSince = Get-Date Write-Log "Proceso OmniRoute presente (PID $($procs[0].ProcessId)) pero $Port aun no responde; esperando arranque (~60 s)..." } elseif (((Get-Date) - $downSince).TotalSeconds -gt $StartupTimeoutSeconds) { Write-Log "OmniRoute lleva mas de $StartupTimeoutSeconds s sin responder. Matando procesos colgados y relanzando." 'WARN' $procs | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } Start-Sleep -Seconds 3 Start-OmniRouteServer $downSince = Get-Date } } else { Write-Log "OmniRoute CAIDO (puerto $Port cerrado). Arrancando servidor..." 'WARN' Start-OmniRouteServer $downSince = Get-Date } } Start-Sleep -Seconds $IntervalSeconds }