A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go

actually check if the requestCrawl endpoint exists via HEAD

evan.jarrett.net 356f9d52 f90a46e0

verified
+45 -3
+41 -1
pkg/atproto/relays.go
··· 30 30 {Name: "Microcosm France", URL: "https://relay3.fr.hose.cam"}, 31 31 {Name: "Upcloud", URL: "https://relay.upcloud.world"}, 32 32 {Name: "Blacksky", URL: "https://atproto.africa"}, 33 + {Name: "Hayes", URL: "https://relay.hayescmd.net"}, 34 + {Name: "Xero", URL: "https://relay.xero.systems"}, 35 + {Name: "Feeds Blue", URL: "https://relay.feeds.blue"}, 33 36 } 34 37 35 38 // RelayHTTPError indicates the relay responded with a non-200 status code. ··· 62 65 type RelayStatus struct { 63 66 Online bool 64 67 Error string 68 + HasRequestCrawl bool 65 69 HasListReposByCollection bool 66 70 RepoStatus *RepoStatus 67 71 HostStatus *HostStatus ··· 73 77 result := &RelayStatus{} 74 78 var mu sync.Mutex 75 79 var wg sync.WaitGroup 76 - wg.Add(3) 80 + wg.Add(4) 77 81 78 82 // Mark relay as online if any check gets an HTTP response 79 83 markOnline := func() { ··· 82 86 mu.Unlock() 83 87 } 84 88 89 + // Probe requestCrawl 90 + go func() { 91 + defer wg.Done() 92 + supported, online := probeRequestCrawl(relayURL) 93 + if online { 94 + markOnline() 95 + } 96 + if supported { 97 + mu.Lock() 98 + result.HasRequestCrawl = true 99 + mu.Unlock() 100 + } 101 + }() 102 + 85 103 // Check host status 86 104 go func() { 87 105 defer wg.Done() ··· 137 155 } 138 156 139 157 return result 158 + } 159 + 160 + // probeRequestCrawl checks if a relay supports the requestCrawl endpoint using a HEAD request. 161 + // A 4xx response (e.g. 405 Method Not Allowed) means the endpoint exists. 162 + // A 5xx or connection failure means it's broken or unsupported. 163 + func probeRequestCrawl(relayURL string) (supported bool, online bool) { 164 + client := &http.Client{Timeout: 5 * time.Second} 165 + req, err := http.NewRequest("HEAD", relayURL+SyncRequestCrawl, nil) 166 + if err != nil { 167 + return false, false 168 + } 169 + 170 + resp, err := client.Do(req) 171 + if err != nil { 172 + return false, false 173 + } 174 + defer resp.Body.Close() 175 + 176 + // Any HTTP response means the relay is online. 177 + // 4xx (typically 405 Method Not Allowed) = endpoint exists. 178 + // 5xx = endpoint is broken. 179 + return resp.StatusCode >= 400 && resp.StatusCode < 500, true 140 180 } 141 181 142 182 // probeListReposByCollection checks if a relay supports the listReposByCollection endpoint.
+2
pkg/hold/admin/handlers_relays.go
··· 21 21 URL string 22 22 Online bool 23 23 Error string 24 + HasRequestCrawl bool 24 25 HasListReposByCollection bool 25 26 RepoStatus *atproto.RepoStatus 26 27 HostStatus *atproto.HostStatus ··· 75 76 URL: relayURL, 76 77 Online: status.Online, 77 78 Error: status.Error, 79 + HasRequestCrawl: status.HasRequestCrawl, 78 80 HasListReposByCollection: status.HasListReposByCollection, 79 81 RepoStatus: status.RepoStatus, 80 82 HostStatus: status.HostStatus,
+2 -2
pkg/hold/admin/templates/partials/relay_status.html
··· 22 22 <td> 23 23 <div class="flex flex-wrap gap-1"> 24 24 {{if .Online}} 25 - <span class="badge badge-ghost badge-sm">requestCrawl</span> 25 + {{if .HasRequestCrawl}}<span class="badge badge-ghost badge-sm">requestCrawl</span>{{end}} 26 26 {{if .HasListReposByCollection}}<span class="badge badge-ghost badge-sm">listReposByCollection</span>{{end}} 27 27 {{else}} 28 28 <span class="text-base-content/30 text-sm">-</span> ··· 47 47 {{end}} 48 48 </td> 49 49 <td class="text-right"> 50 - {{if .Online}} 50 + {{if and .Online .HasRequestCrawl}} 51 51 <button class="btn btn-ghost btn-sm gap-1" 52 52 hx-post="/admin/relays/crawl?url={{.URL}}&name={{.Name}}" 53 53 hx-target="closest tr"