Odin/scripts/restart-starfire-muninn.ps1
2026-07-12 21:53:52 +01:00

174 lines
6.2 KiB
PowerShell

param(
[string] $MuninnExe = "C:\Meta\Odin\Muninn\muninn-d4d0616.exe",
[string] $StorePath = "C:\Meta\Odin\state\starfire.muninn.telemetry.cc",
[string] $LogRoot = "C:\Meta\Odin\logs\starfire-muninn",
[string] $QuestSerial = "1WMHHB68PG1515",
[string] $MoveBluetoothHost = "",
[string[]] $MoveState = @(),
[switch] $EnableUsbMoveState,
[string] $IdunnRudpHealth = $env:IDUNN_RUDP_HEALTH,
[string] $IdunnDaemon = "starfire-muninn",
[string] $IdunnHealthContract = "muninn.cultnet-rudp-local-telemetry-and-quest-access",
[string] $OdinCultMeshUri = $(if ($env:ODIN_CULTMESH_URI) { $env:ODIN_CULTMESH_URI } else { "cultmesh://odin/rendezvous/provider-catalog" }),
[string] $OdinCultMeshRudpEndpoint = $(if ($env:CULTMESH_URI_ODIN_RUDP) { $env:CULTMESH_URI_ODIN_RUDP } else { "127.0.0.1:17871" }),
[string] $HidControllerRudpBind = "",
[string] $HidControllerRudpAdvertise = ""
)
$ErrorActionPreference = "Stop"
$restartMutex = [System.Threading.Mutex]::new($false, "Global\GameCult-Starfire-Muninn-Restart")
if (-not $restartMutex.WaitOne([TimeSpan]::FromMinutes(2))) {
throw "Timed out waiting for the Starfire Muninn restart actuator mutex."
}
if ($env:IDUNN_ACTUATOR -ne "1" -or $env:IDUNN_COMMAND_AUTHORITY -ne "idunn-daemon") {
throw "restart-starfire-muninn.ps1 is an Idunn actuator body. Redeploy by poking Idunn; direct service restart is not an owned path."
}
if (-not (Test-Path -LiteralPath $MuninnExe)) {
throw "Muninn executable not found at $MuninnExe"
}
if ([string]::IsNullOrWhiteSpace($IdunnRudpHealth)) {
throw "Idunn RUDP health endpoint must be supplied by -IdunnRudpHealth or IDUNN_RUDP_HEALTH; no Starfire LAN default is allowed."
}
if (-not [string]::IsNullOrWhiteSpace($HidControllerRudpBind) -and [string]::IsNullOrWhiteSpace($HidControllerRudpAdvertise)) {
throw "HID controller RUDP advertise endpoint must be supplied by -HidControllerRudpAdvertise or MUNINN_HID_CONTROLLER_RUDP_ADVERTISE when HID RUDP bind is enabled; no Starfire LAN default is allowed."
}
Get-CimInstance Win32_Process |
Where-Object {
$_.Name -like "muninn*.exe" -and
$_.CommandLine -like "*serve*" -and
$_.CommandLine -like "*--host*starfire*"
} |
ForEach-Object {
& taskkill.exe /PID $_.ProcessId /T /F | Out-Null
}
New-Item -ItemType Directory -Force -Path $LogRoot | Out-Null
$storeParent = Split-Path -Parent $StorePath
if (-not [string]::IsNullOrWhiteSpace($storeParent)) {
New-Item -ItemType Directory -Force -Path $storeParent | Out-Null
}
if (-not [string]::IsNullOrWhiteSpace($MoveBluetoothHost)) {
& $MuninnExe claim-move-host --move-host $MoveBluetoothHost
}
$arguments = @(
"serve",
"--store", $StorePath,
"--log-root", $LogRoot,
"--host", "starfire",
"--interval-seconds", "15",
"--quest-adb",
"--quest-serial", $QuestSerial,
"--idunn-rudp-health", $IdunnRudpHealth,
"--idunn-daemon", $IdunnDaemon,
"--idunn-health-contract", $IdunnHealthContract
)
if (-not [string]::IsNullOrWhiteSpace($OdinCultMeshUri)) {
$arguments += @("--odin-cultmesh-uri", $OdinCultMeshUri)
}
if (-not [string]::IsNullOrWhiteSpace($HidControllerRudpBind)) {
$arguments += @("--hid-controller-rudp-bind", $HidControllerRudpBind)
}
if (-not [string]::IsNullOrWhiteSpace($HidControllerRudpAdvertise)) {
$arguments += @("--hid-controller-rudp-advertise", $HidControllerRudpAdvertise)
}
if (-not [string]::IsNullOrWhiteSpace($MoveBluetoothHost)) {
$arguments += @("--move-host", $MoveBluetoothHost)
}
foreach ($source in $MoveState) {
if (-not [string]::IsNullOrWhiteSpace($source)) {
$arguments += @("--move-state", $source)
}
}
if ($EnableUsbMoveState) {
$arguments += @("--move-state", "move-starfire-usb=windows-psmove")
}
$serveOutLog = Join-Path $LogRoot "muninn-serve.out.log"
$serveErrLog = Join-Path $LogRoot "muninn-serve.err.log"
$pidPath = Join-Path $LogRoot "muninn-serve.pid"
$lockPath = "$StorePath.lock"
function Start-MuninnServeProcess {
param([string[]] $ArgumentList)
$previousOdinEndpoint = $env:CULTMESH_URI_ODIN_RUDP
try {
$env:CULTMESH_URI_ODIN_RUDP = $OdinCultMeshRudpEndpoint
$process = Start-Process `
-FilePath $MuninnExe `
-ArgumentList $ArgumentList `
-WindowStyle Hidden `
-PassThru `
-RedirectStandardOutput $serveOutLog `
-RedirectStandardError $serveErrLog
} finally {
$env:CULTMESH_URI_ODIN_RUDP = $previousOdinEndpoint
}
$process.Id | Set-Content -Encoding ASCII -LiteralPath $pidPath
return $process
}
function Get-StarfireMuninnServeProcess {
return Get-CimInstance Win32_Process |
Where-Object {
$_.Name -like "muninn*.exe" -and
$_.CommandLine -like "*serve*" -and
$_.CommandLine -like "*--host*starfire*"
} |
Select-Object -First 1
}
function Reset-CorruptMuninnStore {
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
if (Test-Path -LiteralPath $StorePath) {
Move-Item -LiteralPath $StorePath -Destination "$StorePath.corrupt-$timestamp" -Force
}
Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue
$storeLeaf = Split-Path -Leaf $StorePath
Get-ChildItem -LiteralPath $storeParent -ErrorAction SilentlyContinue | Where-Object {
$_.Name -like "$storeLeaf.*.tmp"
} | ForEach-Object {
Remove-Item -LiteralPath $_.FullName -Force -ErrorAction SilentlyContinue
}
}
Remove-Item -LiteralPath $lockPath -Force -ErrorAction SilentlyContinue
$null = Start-MuninnServeProcess -ArgumentList $arguments
Start-Sleep -Seconds 2
$processCheck = Get-StarfireMuninnServeProcess
if ($null -eq $processCheck) {
$serveError = if (Test-Path -LiteralPath $serveErrLog) {
Get-Content -LiteralPath $serveErrLog -Raw
} else {
""
}
if ($serveError -like "*failed to decode MessagePack*") {
Reset-CorruptMuninnStore
$null = Start-MuninnServeProcess -ArgumentList $arguments
Start-Sleep -Seconds 2
$processCheck = Get-StarfireMuninnServeProcess
}
}
if ($null -eq $processCheck) {
throw "Starfire Muninn serve process is not running after restart"
}
foreach ($pattern in @(
"--idunn-rudp-health",
$IdunnRudpHealth,
"--idunn-daemon",
$IdunnDaemon,
"--idunn-health-contract",
$IdunnHealthContract
)) {
if ($processCheck.CommandLine -notlike "*$pattern*") {
throw "Starfire Muninn serve command line is missing ${pattern}: $($processCheck.CommandLine)"
}
}