Public/Edit-BATCRelayBotConfig.ps1
|
#Requires -Version 5.1 function Edit-BATCRelayBotConfig { <# .SYNOPSIS Changes one setting in an existing installation without reinstalling. .DESCRIPTION Edits the fields bot.py actually reads: the bot token, the server ID, the voice channel ID and the audio device. Each change is backed up, written atomically, read back and verified; a failed verification rolls the file back to the backup. Disabled since v1.3.10 for good reason - the editor wrote `token` while the installer wrote `bot_token`, so an edited token went into a field nothing read and the bot kept using the old one. That mapping now has a single definition in Get-ConfigFieldMap, and it is covered by tests. .PARAMETER InstallPath Installation directory. Defaults to $env:LOCALAPPDATA\BATCRelayBot. .EXAMPLE Edit-BATCRelayBotConfig .EXAMPLE $result = Edit-BATCRelayBotConfig if ($result.Success) { "Changed: $($result.UpdatedFields.Keys)" } .OUTPUTS Hashtable with Success, BackupPath, UpdatedFields, Errors. #> [CmdletBinding()] [OutputType([hashtable])] param( [string]$InstallPath = (Join-Path $env:LOCALAPPDATA "BATCRelayBot") ) # Initialised up front. Both of these used to be referenced without ever # being created - $errors.Add on the rollback path and $updatedFields[...] # on the success path - so the function threw on whichever branch it took. $errors = [System.Collections.ArrayList]@() $updatedFields = @{} $backup = $null Write-Host "" Write-Host "BATCRelayBot Configuration Editor" -ForegroundColor Cyan Write-Host "" # ---- Phase 1: can we edit at all? ----------------------------------- $prereq = Confirm-ConfigEditorPrerequisites -InstallPath $InstallPath if (-not $prereq.Valid) { foreach ($problem in $prereq.Errors) { Write-Host " $problem" -ForegroundColor Red } Write-Host "" Write-Host " Run Install-BATCRelayBot first." -ForegroundColor Yellow Write-Host "" return @{ Success = $false; BackupPath = $null; UpdatedFields = @{} Errors = @($prereq.Errors) } } if ($prereq.BotRunning) { Write-Host " The bot is running. Changes take effect after a restart:" -ForegroundColor Yellow Write-Host " Stop-BATCRelayBot; Start-BATCRelayBot" -ForegroundColor Gray Write-Host "" } # ---- Phase 2: what should change? ----------------------------------- $menuResult = Show-ConfigEditorMenu -ConfigPath $prereq.ConfigPath if ($null -eq $menuResult) { return @{ Success = $false; BackupPath = $null; UpdatedFields = @{} Errors = @("Cancelled by the user") } } $field = $menuResult.Field $newValue = $menuResult.Value # ---- Phase 3: back up, write, verify, roll back on failure ---------- try { Write-Host "" Write-Host " Applying change..." -ForegroundColor Cyan $backup = Backup-ConfigFile -ConfigPath $prereq.ConfigPath Write-Host " Backup: $(Split-Path $backup -Leaf)" -ForegroundColor Gray $newJson = Update-ConfigJson -ConfigPath $prereq.ConfigPath -Field $field -Value $newValue Write-ConfigFile -ConfigPath $prereq.ConfigPath -JsonContent $newJson | Out-Null # The write drops the file's restriction along with the old file, so # reapply it before anything else can read the token. Protect-BotConfigFile -ConfigPath $prereq.ConfigPath | Out-Null $verify = Verify-ConfigChange -ConfigPath $prereq.ConfigPath -Field $field -ExpectedValue $newValue if (-not $verify.Verified) { Copy-Item $backup $prereq.ConfigPath -Force Protect-BotConfigFile -ConfigPath $prereq.ConfigPath | Out-Null $errors.Add("$($verify.Message). Rolled back to the backup.") | Out-Null Write-Host " FAILED: $($verify.Message)" -ForegroundColor Red Write-Host " Rolled back - config.json is unchanged." -ForegroundColor Yellow Write-Host "" return @{ Success = $false; BackupPath = $backup; UpdatedFields = @{} Errors = @($errors) } } $definition = Get-ConfigFieldDefinition -Field $field $updatedFields[$field] = $newValue Write-Host " Verified." -ForegroundColor Green Write-Host "" Write-Host " $($definition.Label) updated." -ForegroundColor Green if ($prereq.BotRunning) { Write-Host " Restart the bot to apply it: Stop-BATCRelayBot; Start-BATCRelayBot" -ForegroundColor Yellow } Write-Host "" return @{ Success = $true; BackupPath = $backup; UpdatedFields = $updatedFields Errors = @() } } catch { # Sanitised: an exception raised while handling the token can carry it. $message = Remove-SensitiveData -Text $_.Exception.Message $errors.Add("Error while saving: $message") | Out-Null Write-Host " ERROR: $message" -ForegroundColor Red if ($backup -and (Test-Path $backup)) { Copy-Item $backup $prereq.ConfigPath -Force -ErrorAction SilentlyContinue Protect-BotConfigFile -ConfigPath $prereq.ConfigPath | Out-Null Write-Host " Rolled back - config.json is unchanged." -ForegroundColor Yellow } Write-Host "" return @{ Success = $false; BackupPath = $backup; UpdatedFields = @{} Errors = @($errors) } } } Export-ModuleMember -Function Edit-BATCRelayBotConfig |