Commit 8a00f7c55c

8a00f7c55cdbcddcd878c01a79f2db7dc3f080ef

parent: 0fdc45a668

Verified · cmc

cmc <hello@cleberg.net> · 2026-07-15 01:22 UTC

fix(api): harden random-art retry loop

Three bugs in Random():

- The retry loop was unbounded. Only the NSFW path incremented attempt,
  so a run of DeviantArt errors span forever, hammering the API and
  risking an egress-IP ban.
- string(rand.Intn(999)) converts a rune, not a number: string(65) is
  "A", not "65". Searches were querying garbage. Use strconv.Itoa.
- rand.Intn panics on 0, so an empty result set crashed the handler.
  Skip empty results.

The exhausted-retries error now fires when the loop ends rather than
falling through to index an empty slice.

Layout: unified · split

app/api.go +15 −7
@@ -3,6 +3,7 @@ package app
33import (
44 "encoding/json"
55 "math/rand"
6 "strconv"
67 "strings"
78
89 "github.com/zerolabsco/devianter"
@@ -58,25 +59,32 @@ func (a API) sendMedia(d *devianter.Deviation) {
5859
5960// TODO: сделать фильтры
6061func (a API) Random() {
61 for attempt := 1; ; {
62 if attempt > 3 {
63 a.Error("Sorry, butt NSFW on this are disabled, and the instance failed to find a random art without NSFW", 500)
64 }
62 // Bounded retries: the loop used to be unbounded, and the DeviantArt-error
63 // path never incremented attempt, so a single request could spin forever
64 // hammering the API (and get this instance's egress IP banned).
65 const maxAttempts = 3
6566
66 s, daErr, err := devianter.PerformSearch(string(rand.Intn(999)), rand.Intn(30), 'a')
67 for attempt := 0; attempt < maxAttempts; attempt++ {
68 // strconv.Itoa, not string(): string(65) is "A", not "65".
69 s, daErr, err := devianter.PerformSearch(strconv.Itoa(rand.Intn(999)), rand.Intn(30), 'a')
6770 try(err)
6871 if daErr.RAW != nil {
6972 continue
7073 }
7174
72 deviation := &s.Results[rand.Intn(len(s.Results))]
75 // rand.Intn panics on 0, so an empty result set must be skipped.
76 if len(s.Results) == 0 {
77 continue
78 }
7379
80 deviation := &s.Results[rand.Intn(len(s.Results))]
7481 if deviation.NSFW && !CFG.Nsfw {
75 attempt++
7682 continue
7783 }
7884
7985 a.sendMedia(deviation)
8086 return
8187 }
88
89 a.Error("Sorry, butt NSFW on this are disabled, and the instance failed to find a random art without NSFW", 500)
8290}