Handle Discord token rate limits sanely
This commit is contained in:
parent
e6d38b267a
commit
f60a1043a4
2 changed files with 112 additions and 4 deletions
|
|
@ -185,6 +185,82 @@ function Get-Json {
|
|||
return $response | ConvertFrom-Json
|
||||
}
|
||||
|
||||
function Invoke-JsonRequestDetailed {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string] $Url,
|
||||
[string[]] $Headers = @()
|
||||
)
|
||||
|
||||
$headerPath = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
|
||||
|
||||
try {
|
||||
$args = @(
|
||||
"-sS",
|
||||
"--connect-timeout", "5",
|
||||
"--max-time", "20",
|
||||
"-D", $headerPath,
|
||||
$Url
|
||||
)
|
||||
|
||||
foreach ($header in $Headers) {
|
||||
$args = @("-H", $header) + $args
|
||||
}
|
||||
|
||||
$responseBody = & curl.exe @args
|
||||
$exitCode = $LASTEXITCODE
|
||||
$headerLines = if (Test-Path -LiteralPath $headerPath) {
|
||||
Get-Content -LiteralPath $headerPath
|
||||
} else {
|
||||
@()
|
||||
}
|
||||
|
||||
$statusCode = $null
|
||||
$statusLine = @($headerLines | Where-Object { $_ -match "^HTTP/" } | Select-Object -Last 1)
|
||||
if ($statusLine.Count -gt 0 -and $statusLine[0] -match "^HTTP/\S+\s+(\d{3})") {
|
||||
$statusCode = [int]$Matches[1]
|
||||
}
|
||||
|
||||
$parsedHeaders = @{}
|
||||
foreach ($line in $headerLines) {
|
||||
if ([string]::IsNullOrWhiteSpace($line) -or $line -match "^HTTP/") {
|
||||
continue
|
||||
}
|
||||
|
||||
$separatorIndex = $line.IndexOf(":")
|
||||
if ($separatorIndex -lt 1) {
|
||||
continue
|
||||
}
|
||||
|
||||
$name = $line.Substring(0, $separatorIndex).Trim()
|
||||
$value = $line.Substring($separatorIndex + 1).Trim()
|
||||
$parsedHeaders[$name] = $value
|
||||
}
|
||||
|
||||
if ($exitCode -ne 0 -and $null -eq $statusCode) {
|
||||
throw "Request failed for $Url"
|
||||
}
|
||||
|
||||
$json = $null
|
||||
if (-not [string]::IsNullOrWhiteSpace($responseBody)) {
|
||||
try {
|
||||
$json = $responseBody | ConvertFrom-Json
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
return @{
|
||||
statusCode = $statusCode
|
||||
headers = $parsedHeaders
|
||||
body = $responseBody
|
||||
json = $json
|
||||
exitCode = $exitCode
|
||||
}
|
||||
} finally {
|
||||
Remove-Item -LiteralPath $headerPath -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-CommandWithTimeout {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
|
|
@ -963,10 +1039,41 @@ try {
|
|||
if ($config.ContainsKey("DISCORD_BOT_TOKEN") -and -not [string]::IsNullOrWhiteSpace($config["DISCORD_BOT_TOKEN"])) {
|
||||
Set-WatchdogStep -CurrentStep "discord_checks" -Detail "Validating Discord bot credentials."
|
||||
try {
|
||||
$botIdentity = Get-Json -Url "https://discord.com/api/v10/users/@me" -Headers @("Authorization: Bot $($config["DISCORD_BOT_TOKEN"])")
|
||||
Add-Check -Name "discord.bot_token" -Status "passed" -Detail "Discord bot token is valid for $([string]$botIdentity.username)." -Data @{
|
||||
id = [string]$botIdentity.id
|
||||
username = [string]$botIdentity.username
|
||||
$discordIdentityResponse = Invoke-JsonRequestDetailed -Url "https://discord.com/api/v10/users/@me" -Headers @("Authorization: Bot $($config["DISCORD_BOT_TOKEN"])")
|
||||
$statusCode = $discordIdentityResponse.statusCode
|
||||
|
||||
if ($statusCode -eq 200 -and $null -ne $discordIdentityResponse.json) {
|
||||
$botIdentity = $discordIdentityResponse.json
|
||||
Add-Check -Name "discord.bot_token" -Status "passed" -Detail "Discord bot token is valid for $([string]$botIdentity.username)." -Data @{
|
||||
id = [string]$botIdentity.id
|
||||
username = [string]$botIdentity.username
|
||||
}
|
||||
} elseif ($statusCode -eq 429) {
|
||||
$retryAfterSeconds = $null
|
||||
if ($discordIdentityResponse.headers.ContainsKey("Retry-After")) {
|
||||
[double]::TryParse([string]$discordIdentityResponse.headers["Retry-After"], [ref]$retryAfterSeconds) | Out-Null
|
||||
}
|
||||
|
||||
$detail = if ($null -ne $retryAfterSeconds) {
|
||||
"Discord bot token check was rate-limited by Discord (429). Retry after about $retryAfterSeconds second(s); the token is not necessarily bad."
|
||||
} else {
|
||||
"Discord bot token check was rate-limited by Discord (429). The token is not necessarily bad."
|
||||
}
|
||||
|
||||
Add-Check -Name "discord.bot_token" -Status "warning" -Detail $detail -Data @{
|
||||
statusCode = $statusCode
|
||||
retryAfterSeconds = $retryAfterSeconds
|
||||
}
|
||||
} else {
|
||||
$message = if ($null -ne $discordIdentityResponse.json -and $discordIdentityResponse.json.PSObject.Properties.Name -contains "message") {
|
||||
[string]$discordIdentityResponse.json.message
|
||||
} else {
|
||||
"Request failed for https://discord.com/api/v10/users/@me"
|
||||
}
|
||||
|
||||
Add-Check -Name "discord.bot_token" -Status "failed" -Detail "Discord bot token check failed ($statusCode): $message" -Data @{
|
||||
statusCode = $statusCode
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Add-Check -Name "discord.bot_token" -Status "failed" -Detail "Discord bot token check failed: $($_.Exception.Message)"
|
||||
|
|
|
|||
|
|
@ -64,3 +64,4 @@
|
|||
{"ts":"2026-05-08T15:50:57Z","type":"architecture","status":"ok","note":"Moderation novelty now needs two bars, not one: room novelty and self novelty. The memory organ merges repeated seams into existing clusters, raises saturation and refractory pressure, tracks source-coverage pressure across repos/archive terrain, and cools familiar thoughts instead of rewarding repetition with ripeness."}
|
||||
{"ts":"2026-05-08T16:00:51Z","type":"architecture","status":"ok","note":"Manual moderation-state distillation showed the memory surface was overproducing near-duplicate repo-weather thoughts by storing each social flavor of the same seam as a separate semantic card, sweep, and synthesis. Periodic cleanup should merge those variants by conceptual family, rebalance recent source traces, and clear stale resonance/incubation caches so novelty pressure can regrow from a cleaner substrate."}
|
||||
{"ts":"2026-05-08T16:06:43Z","type":"architecture","status":"ok","note":"Quiet-room moderation no longer treats retrieval as compulsory ritual. If incubation already holds a live, grounded, low-saturation thought, Void may deepen it directly; archive dives and repo sweeps are now explicit support for hungry, stale, or oversaturated queues rather than mandatory throat-clearing before every private thought."}
|
||||
{"ts":"2026-05-08T19:39:40Z","type":"implementation","status":"ok","note":"Discord bot token health checks can hit Discord API rate limits even when the token is fine. The watchdog now distinguishes HTTP 429 from actual credential failures, downgrading rate limits to a warning with retry-after data instead of reporting a dead token."}
|
||||
|
|
|
|||
Loading…
Reference in a new issue