|
' OpenWA VBS — runs OpenWA, restarts if it crashes |
|
' Usage: put openwa.vbs in any dir, open Terminal/cmd/PowerShell in THAT dir, then: |
|
' Clean & create (cmd.exe): |
|
' for /f "tokens=1 delims=," %a in ('schtasks /query /fo csv ^| findstr /i openwa') do @schtasks /delete /tn %a /f >nul 2>&1 |
|
' schtasks /create /tn OpenWA /tr "wscript.exe //NoLogo %CD%\openwa.vbs" /sc onlogon /delay 0000:15 /rl highest /f |
|
' Clean & create (PowerShell): |
|
' schtasks /query /fo csv | ConvertFrom-Csv | ? TaskName -match "openwa" | % { schtasks /delete /tn $_.TaskName /f }; schtasks /create /tn OpenWA /tr "wscript.exe //NoLogo $PWD\openwa.vbs" /sc onlogon /delay 0000:15 /rl highest /f |
|
|
|
Dim OPENWA_DIR, OPENWA_REPO, LOCK_FILE, LOG_FILE, CRASH_LOG_PREFIX |
|
OPENWA_REPO = "rmyndharis/OpenWA" |
|
|
|
' CHANGE THIS: strong unique key (not 'true', not 'dev-admin-key') |
|
Const EV_KEY = "ALLOW_DEV_API_KEY,AUTO_START_SESSIONS,NODE_ENV,MCP_ENABLED,SIMULATE_TYPING,SIMULATE_TYPING_MAX_MS,PUPPETEER_EXECUTABLE_PATH,CORS_ORIGINS" |
|
Const EV_VALUE = "OpenWA-Strong-Key-2024-ChangeMe,true,production,true,true,5000,C:\Program Files\Google\Chrome\Application\chrome.exe,http://localhost:2886" |
|
|
|
Set fso = CreateObject("Scripting.FileSystemObject") |
|
Set sh = CreateObject("WScript.Shell") |
|
|
|
' Resolve all paths relative to THIS script — portable across users/machines |
|
Dim scriptDir : scriptDir = fso.GetParentFolderName(WScript.ScriptFullName) |
|
OPENWA_DIR = fso.BuildPath(scriptDir, "OpenWA") |
|
LOCK_FILE = fso.BuildPath(scriptDir, "openwa.lock") |
|
LOG_FILE = fso.BuildPath(scriptDir, "openwa.log") |
|
CRASH_LOG_PREFIX = fso.BuildPath(OPENWA_DIR, "openwa-crash") |
|
|
|
Function ts |
|
ts = Year(Now) & "-" & Right("0" & Month(Now), 2) & "-" & Right("0" & Day(Now), 2) _ |
|
& " " & Right("0" & Hour(Now), 2) & ":" & Right("0" & Minute(Now), 2) & ":" & Right("0" & Second(Now), 2) |
|
End Function |
|
|
|
Sub Log(msg) |
|
On Error Resume Next |
|
RotateLog |
|
Set f = fso.OpenTextFile(LOG_FILE, 8, True) |
|
f.WriteLine "[" & ts & "] " & msg |
|
f.Close |
|
End Sub |
|
|
|
' === NOTIFICATION STATE (rate limiting) === |
|
Dim notifState : Set notifState = CreateObject("Scripting.Dictionary") |
|
|
|
Sub ShowNotification(issueType, title, message, timeoutSeconds, minIntervalMinutes) |
|
Dim now, lastTime |
|
now = Now |
|
If notifState.Exists(issueType) Then |
|
lastTime = notifState(issueType) |
|
If DateDiff("n", lastTime, now) < minIntervalMinutes Then |
|
Exit Sub |
|
End If |
|
End If |
|
notifState(issueType) = now |
|
|
|
' Try native Windows toast (appears in Action Center, works in scheduled tasks) |
|
On Error Resume Next |
|
Dim psCmd |
|
psCmd = "$xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); " & _ |
|
"$xml.GetElementsByTagName('text')(0).InnerText = '" & EscapeForPS(title) & "'; " & _ |
|
"$xml.GetElementsByTagName('text')(1).InnerText = '" & EscapeForPS(message) & "'; " & _ |
|
"$toast = [Windows.UI.Notifications.ToastNotification]::new($xml); " & _ |
|
"[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('OpenWA').Show($toast)" |
|
sh.Run "powershell.exe -NoProfile -WindowStyle Hidden -Command " & Chr(34) & psCmd & Chr(34), 0, False |
|
|
|
' Fallback: Popup (works when interactive) |
|
If Err.Number <> 0 Then |
|
Err.Clear |
|
sh.Popup message, timeoutSeconds, title, 48 |
|
End If |
|
On Error GoTo 0 |
|
End Sub |
|
|
|
Function EscapeForPS(str) |
|
EscapeForPS = Replace(Replace(str, "'", "''"), Chr(34), "\" & Chr(34)) |
|
End Function |
|
|
|
Function FindNodeJS() |
|
Dim paths, p, candidate |
|
paths = Array() |
|
|
|
' Priority 1: Hardcoded known locations (portable + common install paths) |
|
knownPaths = Array( _ |
|
"C:\Program Files\nodejs", _ |
|
"C:\Program Files (x86)\nodejs", _ |
|
"C:\ProgramData\chocolatey\bin", _ |
|
fso.BuildPath(sh.Environment("PROCESS")("LOCALAPPDATA"), "Microsoft\WindowsApps"), _ |
|
fso.BuildPath(sh.Environment("PROCESS")("USERPROFILE"), "scoop\apps\nodejs\current"), _ |
|
fso.BuildPath(sh.Environment("PROCESS")("USERPROFILE"), ".volta\bin"), _ |
|
fso.BuildPath(sh.Environment("PROCESS")("USERPROFILE"), "AppData\Roaming\nvm"), _ |
|
fso.BuildPath(sh.Environment("PROCESS")("USERPROFILE"), "AppData\Local\fnm") _ |
|
) |
|
|
|
' Priority 2: Registry System PATH |
|
Dim wshShell : Set wshShell = CreateObject("WScript.Shell") |
|
On Error Resume Next |
|
Dim systemPath : systemPath = wshShell.RegRead("HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path") |
|
If Err.Number = 0 Then |
|
For Each p In Split(systemPath, ";"): knownPaths = p & ";" & knownPaths: Next |
|
End If |
|
Err.Clear |
|
|
|
' Priority 3: Registry User PATH |
|
Dim userPath : userPath = wshShell.RegRead("HKCU\Environment\Path") |
|
If Err.Number = 0 Then |
|
For Each p In Split(userPath, ";"): knownPaths = p & ";" & knownPaths: Next |
|
End If |
|
Err.Clear |
|
|
|
' Priority 4: Process PATH (original) |
|
Dim processPath : processPath = wshShell.Environment("PROCESS")("Path") |
|
For Each p In Split(processPath, ";"): knownPaths = p & ";" & knownPaths: Next |
|
On Error GoTo 0 |
|
|
|
' Search all paths |
|
For Each p In knownPaths |
|
p = Trim(p) |
|
If p <> "" Then |
|
candidate = fso.BuildPath(p, "node.exe") |
|
If fso.FileExists(candidate) Then |
|
FindNodeJS = candidate |
|
Exit Function |
|
End If |
|
End If |
|
Next |
|
|
|
FindNodeJS = "" |
|
End Function |
|
|
|
Function ValidateNode(path) |
|
On Error Resume Next |
|
Dim nodeCmd : nodeCmd = Chr(34) & path & Chr(34) & " --version" |
|
Dim code : code = sh.Run(nodeCmd, 0, True) |
|
ValidateNode = (code = 0) |
|
On Error GoTo 0 |
|
End Function |
|
|
|
Sub RotateLog |
|
On Error Resume Next |
|
If Not fso.FileExists(LOG_FILE) Then Exit Sub |
|
Set f = fso.GetFile(LOG_FILE) |
|
If f.Size < 1048576 Then Exit Sub |
|
fso.CopyFile LOG_FILE, LOG_FILE & "." & Replace(Replace(ts, ":", ""), " ", "_") & ".bak" |
|
fso.DeleteFile LOG_FILE, True |
|
End Sub |
|
|
|
Function PidRunning(pid) |
|
On Error Resume Next |
|
Set procs = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT ProcessId FROM Win32_Process WHERE ProcessId=" & pid) |
|
PidRunning = (procs.Count > 0) |
|
End Function |
|
|
|
Sub KillOldInstance |
|
On Error Resume Next |
|
If Not fso.FileExists(LOCK_FILE) Then Exit Sub |
|
Set f = fso.OpenTextFile(LOCK_FILE, 1) : oldPid = f.ReadLine() : f.Close |
|
If oldPid = "" Then Exit Sub |
|
If Not PidRunning(oldPid) Then Exit Sub |
|
Set check = GetObject("winmgmts:\\.\root\cimv2").ExecQuery( _ |
|
"SELECT * FROM Win32_Process WHERE ProcessId=" & oldPid & _ |
|
" AND (Name='wscript.exe' OR Name='cscript.exe')") |
|
If check.Count = 0 Then Exit Sub |
|
Log "Killing stale VBS instance (PID: " & oldPid & ")" |
|
For Each p In check : p.Terminate : Next |
|
WScript.Sleep 1000 |
|
End Sub |
|
|
|
Sub WriteLock |
|
On Error Resume Next |
|
Set procs = GetObject("winmgmts:\\.\root\cimv2").ExecQuery( _ |
|
"SELECT ProcessId FROM Win32_Process WHERE (Name='wscript.exe' OR Name='cscript.exe') " & _ |
|
"AND CommandLine LIKE '%" & Replace(Replace(WScript.ScriptName, ".", "[.]"), "\", "\\") & "%'") |
|
For Each p In procs |
|
Set f = fso.CreateTextFile(LOCK_FILE, True) : f.WriteLine p.ProcessId : f.Close : Exit For |
|
Next |
|
End Sub |
|
|
|
Sub KillNode |
|
On Error Resume Next |
|
' Only kill node processes from our OpenWA directory, not all node.exe on the system |
|
Set procs = GetObject("winmgmts:\\.\root\cimv2").ExecQuery( _ |
|
"SELECT * FROM Win32_Process WHERE Name='node.exe' AND " & _ |
|
"(CommandLine LIKE '%dist\main%' OR CommandLine LIKE '%" & OPENWA_DIR & "%')") |
|
For Each p In procs : p.Terminate : Next |
|
End Sub |
|
|
|
Function CurrentVersion(dir) |
|
On Error Resume Next |
|
pkg = dir & "\package.json" |
|
If Not fso.FileExists(pkg) Then CurrentVersion = "" : Exit Function |
|
Set f = fso.OpenTextFile(pkg, 1) : txt = f.ReadAll() : f.Close |
|
m = InStr(txt, """version""") |
|
If m > 0 Then CurrentVersion = "v" & Left(Mid(txt, m + 12), InStr(Mid(txt, m + 12), """") - 1) |
|
End Function |
|
|
|
Function HttpGet(url) |
|
On Error Resume Next |
|
Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0") |
|
http.Open "GET", url, False |
|
http.SetTimeouts 5000, 5000, 5000, 10000 |
|
http.Send |
|
If Err.Number = 0 And http.Status = 200 Then HttpGet = http.ResponseText Else HttpGet = "" |
|
End Function |
|
|
|
Sub RunLogged(cmd, desc) |
|
On Error Resume Next |
|
code = sh.Run(cmd, 0, True) |
|
If code <> 0 Then Log desc & " exited with code " & code |
|
End Sub |
|
|
|
Function PortFree(port) |
|
On Error Resume Next |
|
Dim tmp : tmp = fso.GetSpecialFolder(2) & "\portchk.tmp" |
|
sh.Run "cmd.exe /c netstat -ano | findstr "":" & port & " "" > """ & tmp & """ 2>nul", 0, True |
|
Dim f : Set f = fso.OpenTextFile(tmp, 1) |
|
Dim txt : txt = f.ReadAll() : f.Close : fso.DeleteFile tmp, True |
|
PortFree = (InStr(txt, "LISTENING") = 0) |
|
End Function |
|
|
|
Sub KillByPort(port) |
|
On Error Resume Next |
|
Dim tmp : tmp = fso.GetSpecialFolder(2) & "\portpid.tmp" |
|
sh.Run "cmd.exe /c netstat -ano | findstr "":" & port & " "" > """ & tmp & """ 2>nul", 0, True |
|
Dim f : Set f = fso.OpenTextFile(tmp, 1) |
|
Dim txt : txt = f.ReadAll() : f.Close : fso.DeleteFile tmp, True |
|
Dim lines : lines = Split(txt, vbCrLf) |
|
Dim line, parts, pid |
|
For Each line In lines |
|
If InStr(line, "LISTENING") > 0 Then |
|
parts = Split(line) |
|
pid = parts(UBound(parts)) |
|
If pid <> "" And IsNumeric(pid) Then |
|
Log "Killing process on port " & port & " (PID: " & pid & ")" |
|
Set procs = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT * FROM Win32_Process WHERE ProcessId=" & pid) |
|
For Each p In procs : p.Terminate : Next |
|
End If |
|
End If |
|
Next |
|
End Sub |
|
|
|
Sub SyncEnv |
|
On Error Resume Next |
|
envFile = fso.BuildPath(OPENWA_DIR, "data\.env.generated") |
|
If Not fso.FolderExists(fso.BuildPath(OPENWA_DIR, "data")) Then fso.CreateFolder fso.BuildPath(OPENWA_DIR, "data") |
|
Set env = CreateObject("Scripting.Dictionary") |
|
If fso.FileExists(envFile) Then |
|
Set f = fso.OpenTextFile(envFile, 1) |
|
Do While Not f.AtEndOfStream |
|
line = Trim(f.ReadLine()) |
|
If line <> "" And Left(line, 1) <> "#" Then |
|
eq = InStr(line, "=") |
|
If eq > 0 Then |
|
on error resume next : env.Add Left(line, eq - 1), Mid(line, eq + 1) |
|
End If |
|
End If |
|
Loop |
|
f.Close |
|
End If |
|
keys = Split(EV_KEY, ",") : vals = Split(EV_VALUE, ",") |
|
For i = 0 To UBound(keys) |
|
If env.Exists(keys(i)) Then env(keys(i)) = vals(i) Else env.Add keys(i), vals(i) |
|
Next |
|
Set f = fso.CreateTextFile(envFile, True) |
|
For Each k In env.Keys : f.WriteLine k & "=" & env(k) : Next |
|
f.Close |
|
End Sub |
|
|
|
' === STARTUP === |
|
Log "Starting OpenWA" |
|
|
|
KillNode |
|
KillOldInstance |
|
WriteLock |
|
|
|
nodePath = FindNodeJS() |
|
If nodePath = "" Then |
|
ShowNotification "node_missing", "OpenWA: Node.js Required", "Node.js not found. Installing automatically...", 10, 5 |
|
Log "Installing Node.js via winget..." |
|
sh.Run "winget install --id OpenJS.NodeJS.LTS -e --silent --accept-package-agreements", 0, True |
|
nodePath = "C:\Program Files\nodejs\node.exe" |
|
If Not fso.FileExists(nodePath) Then |
|
ShowNotification "node_install_failed", "OpenWA: Install Failed", "Automatic Node.js install failed. Please contact IT.", 15, 5 |
|
End If |
|
End If |
|
|
|
chromePaths = Array( _ |
|
fso.BuildPath(sh.Environment("PROCESS")("ProgramFiles"), "Google\Chrome\Application\chrome.exe"), _ |
|
fso.BuildPath(sh.Environment("PROCESS")("ProgramFiles(x86)"), "Google\Chrome\Application\chrome.exe") _ |
|
) |
|
found = False |
|
For Each p In chromePaths |
|
If fso.FileExists(p) Then found = True : Exit For |
|
Next |
|
If Not found Then |
|
Log "Installing Google Chrome via winget..." |
|
sh.Run "winget install --id Google.Chrome -e --silent --accept-package-agreements", 0, True |
|
End If |
|
|
|
If Not fso.FolderExists(OPENWA_DIR) Then |
|
Log "OpenWA directory not found, performing fresh install..." |
|
raw = HttpGet("https://api.github.com/repos/" & OPENWA_REPO & "/releases/latest") |
|
latest = "" |
|
parts = Split(raw, Chr(34)) |
|
For i = 0 To UBound(parts) - 1 |
|
If parts(i) = "tag_name" Then latest = parts(i + 2) : Exit For |
|
Next |
|
If latest = "" Then Log "Failed to fetch latest release tag, quitting" : WScript.Quit 1 |
|
Log "Latest release: " & latest |
|
zipFile = fso.BuildPath(fso.GetSpecialFolder(2), "openwa_" & latest & ".zip") |
|
extractDir = fso.BuildPath(fso.GetSpecialFolder(2), "openwa_" & latest) |
|
sh.Run "curl.exe -L -o """ & zipFile & """ ""https://github.com/" & OPENWA_REPO & "/archive/refs/tags/" & latest & ".zip""", 0, True |
|
If fso.FileExists(zipFile) Then |
|
If fso.FolderExists(extractDir) Then fso.DeleteFolder extractDir, True |
|
fso.CreateFolder extractDir |
|
sh.Run "tar.exe -xf """ & zipFile & """ -C """ & extractDir & """", 0, True |
|
Set extractFolder = fso.GetFolder(extractDir) |
|
For Each fld In extractFolder.SubFolders : srcFolder = fld.Path : Exit For : Next |
|
If srcFolder <> "" Then |
|
fso.CreateFolder OPENWA_DIR |
|
Log "Extracting " & latest & " to " & OPENWA_DIR |
|
sh.Run "robocopy """ & srcFolder & """ """ & OPENWA_DIR & """ /E /NDL /NFL /NJH /NJS", 0, True |
|
fso.DeleteFolder extractDir, True : fso.DeleteFile zipFile, True |
|
Log "Running npm install..." |
|
sh.Environment("PROCESS")("PUPPETEER_SKIP_DOWNLOAD") = "true" |
|
sh.CurrentDirectory = OPENWA_DIR |
|
RunLogged "npm.cmd install", "npm install" |
|
RunLogged "npm.cmd rebuild", "npm rebuild" |
|
Log "Running npm run build:all..." |
|
RunLogged "npm.cmd run build:all", "npm run build:all" |
|
End If |
|
End If |
|
End If |
|
|
|
SyncEnv |
|
|
|
' === MAIN LOOP === |
|
backoff = 5 |
|
maxBackoff = 120 |
|
crashCount = 0 |
|
maxCrashes = 10 |
|
|
|
Do While True |
|
' Re-detect Node.js every iteration (handles PATH changes, reinstalls) |
|
nodePath = FindNodeJS() |
|
If nodePath = "" Then |
|
ShowNotification "node_missing", "OpenWA: Node.js Required", "Node.js not found. Installing automatically...", 10, 5 |
|
Log "Installing Node.js via winget..." |
|
sh.Run "winget install --id OpenJS.NodeJS.LTS -e --silent --accept-package-agreements", 0, True |
|
nodePath = "C:\Program Files\nodejs\node.exe" |
|
End If |
|
|
|
KillNode |
|
KillByPort 2785 |
|
For i = 1 To 30 |
|
If PortFree(2785) Then Exit For |
|
If i = 1 Then Log "Waiting for port 2785 to be free..." |
|
WScript.Sleep 1000 |
|
Next |
|
|
|
current = CurrentVersion(OPENWA_DIR) |
|
Log "Current version: " & current |
|
|
|
raw = HttpGet("https://api.github.com/repos/" & OPENWA_REPO & "/releases/latest") |
|
latest = "" |
|
parts = Split(raw, Chr(34)) |
|
For i = 0 To UBound(parts) - 1 |
|
If parts(i) = "tag_name" Then latest = parts(i + 2) : Exit For |
|
Next |
|
|
|
If latest <> "" And latest <> current Then |
|
ShowNotification "update_available", "OpenWA: Updating", "Updating OpenWA to version " & latest & "...", 8, 5 |
|
Log "Update available: " & current & " -> " & latest |
|
zipFile = fso.BuildPath(fso.GetSpecialFolder(2), "openwa_" & latest & ".zip") |
|
extractDir = fso.BuildPath(fso.GetSpecialFolder(2), "openwa_" & latest) |
|
sh.Run "curl.exe -L -o """ & zipFile & """ ""https://github.com/" & OPENWA_REPO & "/archive/refs/tags/" & latest & ".zip""", 0, True |
|
If fso.FileExists(zipFile) Then |
|
If fso.FolderExists(extractDir) Then fso.DeleteFolder extractDir, True |
|
fso.CreateFolder extractDir |
|
sh.Run "tar.exe -xf """ & zipFile & """ -C """ & extractDir & """", 0, True |
|
Set extractFolder = fso.GetFolder(extractDir) |
|
For Each fld In extractFolder.SubFolders : srcFolder = fld.Path : Exit For : Next |
|
If srcFolder <> "" Then |
|
Log "Updating to " & latest & "..." |
|
sh.Run "robocopy """ & srcFolder & """ """ & OPENWA_DIR & """ /E /XD node_modules dist data .git .github /NDL /NFL /NJH /NJS", 0, True |
|
fso.DeleteFolder extractDir, True : fso.DeleteFile zipFile, True |
|
SyncEnv |
|
Log "Installing dependencies..." |
|
sh.CurrentDirectory = OPENWA_DIR |
|
RunLogged "npm.cmd install", "npm install" |
|
RunLogged "npm.cmd rebuild", "npm rebuild" |
|
Log "Rebuilding after update..." |
|
RunLogged "npm.cmd run build:all", "npm run build:all" |
|
KillNode |
|
End If |
|
End If |
|
End If |
|
|
|
Log "Starting OpenWA..." |
|
sh.Environment("PROCESS")("NODE_ENV") = "production" |
|
sh.Environment("PROCESS")("ALLOW_DEV_API_KEY") = "OpenWA-Strong-Key-2024-ChangeMe" |
|
sh.Environment("PROCESS")("MCP_ENABLED") = "true" |
|
sh.CurrentDirectory = OPENWA_DIR |
|
|
|
' Validate node.exe works (catches missing DLLs) |
|
If Not ValidateNode(nodePath) Then |
|
ShowNotification "native_rebuild", "OpenWA: Updating Components", "Rebuilding native modules for new Node.js version. Please wait...", 10, 3 |
|
Log "Node.js validation failed, reinstalling..." |
|
sh.Run "winget install --id OpenJS.NodeJS.LTS -e --silent --accept-package-agreements --force", 0, True |
|
nodePath = FindNodeJS() |
|
End If |
|
|
|
' Capture stdout/stderr to unique temp file for debugging |
|
Dim nodeOutFile, nodeErrFile, exec, exitCode, errTxt, outTxt |
|
nodeOutFile = fso.BuildPath(fso.GetSpecialFolder(2), fso.GetTempName()) |
|
nodeErrFile = fso.BuildPath(fso.GetSpecialFolder(2), fso.GetTempName()) |
|
Dim cmdLine : cmdLine = "cmd.exe /c cd /d " & Chr(34) & OPENWA_DIR & Chr(34) & " && set ALLOW_DEV_API_KEY=OpenWA-Strong-Key-2024-ChangeMe && set NODE_ENV=production && set MCP_ENABLED=true && " & Chr(34) & nodePath & Chr(34) & " dist\main >" & Chr(34) & nodeOutFile & Chr(34) & " 2>" & Chr(34) & nodeErrFile & Chr(34) |
|
Set exec = sh.Exec(cmdLine) |
|
Dim sessionUp : sessionUp = False |
|
Do While exec.Status = 0 |
|
If Not sessionUp And Not PortFree(2785) Then |
|
sessionUp = True |
|
Log "Session started on http://localhost:2785" |
|
End If |
|
WScript.Sleep 500 |
|
Loop |
|
exitCode = exec.ExitCode |
|
If fso.FileExists(nodeErrFile) Then |
|
Set f = fso.GetFile(nodeErrFile) |
|
If f.Size > 0 Then |
|
Set f = fso.OpenTextFile(nodeErrFile, 1): errTxt = f.ReadAll(): f.Close |
|
End If |
|
fso.DeleteFile nodeErrFile, True |
|
End If |
|
If fso.FileExists(nodeOutFile) Then |
|
Set f = fso.GetFile(nodeOutFile) |
|
If f.Size > 0 Then |
|
Set f = fso.OpenTextFile(nodeOutFile, 1): outTxt = f.ReadAll(): f.Close |
|
End If |
|
fso.DeleteFile nodeOutFile, True |
|
End If |
|
If errTxt <> "" Then Log "Node stderr: " & Left(errTxt, 2000) |
|
If outTxt <> "" Then Log "Node stdout: " & Left(outTxt, 2000) |
|
|
|
Log "OpenWA exited with code " & exitCode |
|
If errTxt <> "" And InStr(errTxt, "Refusing to start") > 0 Then |
|
Log "Fatal: security check failed, refusing to restart" |
|
ShowNotification "security_fail", "OpenWA: Config Error", "ALLOW_DEV_API_KEY is invalid. Update EV_VALUE in openwa.vbs and re-run.", 15, 5 |
|
WScript.Quit 1 |
|
End If |
|
If exitCode = 0 Then |
|
backoff = 5 |
|
crashCount = 0 |
|
Else |
|
|
|
' STATUS_DLL_NOT_FOUND = native module mismatch (Node version change) |
|
If exitCode = -1073741510 Then |
|
ShowNotification "native_rebuild", "OpenWA: Updating Components", "Rebuilding native modules for new Node.js version. Please wait...", 10, 3 |
|
Log "Native module mismatch detected (exit code -1073741510), rebuilding..." |
|
sh.CurrentDirectory = OPENWA_DIR |
|
RunLogged "npm.cmd rebuild", "npm rebuild" |
|
RunLogged "npm.cmd run build:all", "npm run build:all" |
|
crashCount = 0 |
|
backoff = 5 |
|
Else |
|
crashCount = crashCount + 1 |
|
If crashCount >= maxCrashes Then |
|
ShowNotification "crash_threshold", "OpenWA: Stopped", "OpenWA stopped after repeated failures. Check logs.", 15, 5 |
|
Log "Crash threshold (" & maxCrashes & ") reached, giving up" |
|
WScript.Quit 1 |
|
End If |
|
backoff = backoff * 2 |
|
If backoff > maxBackoff Then backoff = maxBackoff |
|
End If |
|
End If |
|
Log "OpenWA exited, restarting in " & backoff & "s" |
|
WScript.Sleep backoff * 1000 |
|
Loop |