update

Changed files
+54 -4
internal
+36
internal/api/handlers.go
··· 164 164 resp.json(stats) 165 165 } 166 166 167 + // handleGetRandomEndpoint returns a random endpoint of specified type 168 + func (s *Server) handleGetRandomEndpoint(w http.ResponseWriter, r *http.Request) { 169 + resp := newResponse(w) 170 + 171 + // Get required type parameter 172 + endpointType := r.URL.Query().Get("type") 173 + if endpointType == "" { 174 + resp.error("type parameter is required", http.StatusBadRequest) 175 + return 176 + } 177 + 178 + // Get optional status parameter 179 + status := r.URL.Query().Get("status") 180 + 181 + filter := &storage.EndpointFilter{ 182 + Type: endpointType, 183 + Status: status, 184 + Random: true, 185 + Limit: 1, 186 + Offset: 0, 187 + } 188 + 189 + endpoints, err := s.db.GetEndpoints(r.Context(), filter) 190 + if err != nil { 191 + resp.error(err.Error(), http.StatusInternalServerError) 192 + return 193 + } 194 + 195 + if len(endpoints) == 0 { 196 + resp.error("no endpoints found matching criteria", http.StatusNotFound) 197 + return 198 + } 199 + 200 + resp.json(formatEndpointResponse(endpoints[0])) 201 + } 202 + 167 203 // ===== PDS HANDLERS ===== 168 204 169 205 func (s *Server) handleGetPDSList(w http.ResponseWriter, r *http.Request) {
+1
internal/api/server.go
··· 61 61 // Generic endpoints (keep as-is) 62 62 api.HandleFunc("/endpoints", s.handleGetEndpoints).Methods("GET") 63 63 api.HandleFunc("/endpoints/stats", s.handleGetEndpointStats).Methods("GET") 64 + api.HandleFunc("/endpoints/random", s.handleGetRandomEndpoint).Methods("GET") 64 65 65 66 //PDS-specific endpoints (virtual, created via JOINs) 66 67 api.HandleFunc("/pds", s.handleGetPDSList).Methods("GET")
+14 -2
internal/storage/postgres.go
··· 359 359 } 360 360 } 361 361 362 - // NEW: Order by server_did and discovered_at to get primary endpoints 363 - query += " ORDER BY COALESCE(server_did, id::text), discovered_at ASC" 362 + // NEW: Choose ordering strategy 363 + if filter != nil && filter.Random { 364 + // For random selection, we need to wrap in a subquery 365 + query = fmt.Sprintf(` 366 + WITH filtered_endpoints AS ( 367 + %s 368 + ) 369 + SELECT * FROM filtered_endpoints 370 + ORDER BY RANDOM() 371 + `, query) 372 + } else { 373 + // Original ordering for non-random queries 374 + query += " ORDER BY COALESCE(server_did, id::text), discovered_at ASC" 375 + } 364 376 365 377 if filter != nil && filter.Limit > 0 { 366 378 query += fmt.Sprintf(" LIMIT $%d OFFSET $%d", argIdx, argIdx+1)
+3 -2
internal/storage/types.go
··· 79 79 Type string // "pds", "labeler", etc. 80 80 Status string 81 81 MinUserCount int64 82 - OnlyStale bool // NEW: Only return endpoints that need re-checking 83 - RecheckInterval time.Duration // NEW: How long before an endpoint is considered stale 82 + OnlyStale bool 83 + RecheckInterval time.Duration 84 + Random bool // NEW: Return results in random order 84 85 Limit int 85 86 Offset int 86 87 }