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

Configure Feed

Select the types of activity you want to include in your feed.

dedupe hold health checks

+132 -27
+1 -1
deploy/docker-compose.prod.yml
··· 133 133 driver: bridge 134 134 ipam: 135 135 config: 136 - - subnet: 172.28.0.0/24 136 + - subnet: 172.29.0.0/24 137 137 138 138 volumes: 139 139 caddy_data:
+2 -2
pkg/appview/db/hold_store.go
··· 8 8 9 9 // HoldCaptainRecord represents a cached captain record from a hold's PDS 10 10 type HoldCaptainRecord struct { 11 - HoldDID string `json:"-"` // Set manually, not from JSON 11 + HoldDID string `json:"-"` // Set manually, not from JSON 12 12 OwnerDID string `json:"owner"` 13 13 Public bool `json:"public"` 14 14 AllowAllCrew bool `json:"allowAllCrew"` 15 15 DeployedAt string `json:"deployedAt"` 16 16 Region string `json:"region"` 17 17 Provider string `json:"provider"` 18 - UpdatedAt time.Time `json:"-"` // Set manually, not from JSON 18 + UpdatedAt time.Time `json:"-"` // Set manually, not from JSON 19 19 } 20 20 21 21 // GetCaptainRecord retrieves a captain record from the cache
+53
pkg/appview/holdhealth/checker_test.go
··· 268 268 t.Errorf("Expected startupDelay=%v, got %v", startupDelay, workerWithDelay.startupDelay) 269 269 } 270 270 } 271 + 272 + func TestNormalizeHoldEndpoint(t *testing.T) { 273 + tests := []struct { 274 + name string 275 + input string 276 + expected string 277 + }{ 278 + { 279 + name: "HTTP URL", 280 + input: "http://hold01.atcr.io", 281 + expected: "did:web:hold01.atcr.io", 282 + }, 283 + { 284 + name: "HTTPS URL", 285 + input: "https://hold01.atcr.io", 286 + expected: "did:web:hold01.atcr.io", 287 + }, 288 + { 289 + name: "HTTP URL with port", 290 + input: "http://172.28.0.3:8080", 291 + expected: "did:web:172.28.0.3:8080", 292 + }, 293 + { 294 + name: "HTTP URL with trailing slash", 295 + input: "http://hold01.atcr.io/", 296 + expected: "did:web:hold01.atcr.io", 297 + }, 298 + { 299 + name: "HTTP URL with path", 300 + input: "http://hold01.atcr.io/some/path", 301 + expected: "did:web:hold01.atcr.io", 302 + }, 303 + { 304 + name: "Already a DID", 305 + input: "did:web:hold01.atcr.io", 306 + expected: "did:web:hold01.atcr.io", 307 + }, 308 + { 309 + name: "DID with port", 310 + input: "did:web:172.28.0.3:8080", 311 + expected: "did:web:172.28.0.3:8080", 312 + }, 313 + } 314 + 315 + for _, tt := range tests { 316 + t.Run(tt.name, func(t *testing.T) { 317 + result := normalizeHoldEndpoint(tt.input) 318 + if result != tt.expected { 319 + t.Errorf("normalizeHoldEndpoint(%q) = %q, want %q", tt.input, result, tt.expected) 320 + } 321 + }) 322 + } 323 + }
+54 -2
pkg/appview/holdhealth/worker.go
··· 5 5 "database/sql" 6 6 "fmt" 7 7 "log" 8 + "strings" 8 9 "sync" 9 10 "time" 10 11 ) ··· 115 116 return 116 117 } 117 118 118 - log.Printf("Hold health worker: Checking %d unique hold endpoints", len(endpoints)) 119 + log.Printf("Hold health worker: Fetched %d hold endpoint entries from database", len(endpoints)) 120 + 121 + // Deduplicate endpoints by normalizing to canonical DID format 122 + // This handles cases where the same hold is stored with different representations: 123 + // - http://172.28.0.3:8080 (internal IP) 124 + // - http://hold01.atcr.io (external hostname) 125 + // - did:web:hold01.atcr.io (DID format) 126 + // All normalize to the same DID: did:web:hold01.atcr.io (or did:web:172.28.0.3:8080) 127 + seen := make(map[string]bool) 128 + uniqueEndpoints := make([]string, 0, len(endpoints)) 129 + 130 + for _, endpoint := range endpoints { 131 + // Normalize to canonical DID format 132 + normalizedDID := normalizeHoldEndpoint(endpoint) 133 + 134 + // Skip if we've already seen this normalized DID 135 + if seen[normalizedDID] { 136 + continue 137 + } 138 + 139 + seen[normalizedDID] = true 140 + // Use the normalized DID for health checks 141 + uniqueEndpoints = append(uniqueEndpoints, normalizedDID) 142 + } 143 + 144 + log.Printf("Hold health worker: Checking %d unique hold endpoints (deduplicated from %d)", len(uniqueEndpoints), len(endpoints)) 119 145 120 146 // Check health concurrently with rate limiting 121 147 // Use a semaphore to limit concurrent requests (max 10 at a time) ··· 126 152 unreachable := 0 127 153 var statsMu sync.Mutex 128 154 129 - for _, endpoint := range endpoints { 155 + for _, endpoint := range uniqueEndpoints { 130 156 wg.Add(1) 131 157 132 158 go func(ep string) { ··· 193 219 194 220 return endpoints, nil 195 221 } 222 + 223 + // normalizeHoldEndpoint converts a hold endpoint (URL or DID) to canonical DID format 224 + // This ensures that different representations of the same hold are deduplicated: 225 + // - http://172.28.0.3:8080 → did:web:172.28.0.3:8080 226 + // - http://hold01.atcr.io → did:web:hold01.atcr.io 227 + // - https://hold01.atcr.io → did:web:hold01.atcr.io 228 + // - did:web:hold01.atcr.io → did:web:hold01.atcr.io (passthrough) 229 + func normalizeHoldEndpoint(endpoint string) string { 230 + // Strip protocol and trailing slashes 231 + normalized := endpoint 232 + normalized = strings.TrimPrefix(normalized, "http://") 233 + normalized = strings.TrimPrefix(normalized, "https://") 234 + normalized = strings.TrimSuffix(normalized, "/") 235 + 236 + // If already a DID, return as-is 237 + if strings.HasPrefix(endpoint, "did:") { 238 + return endpoint 239 + } 240 + 241 + // Extract hostname (remove path if present) 242 + parts := strings.Split(normalized, "/") 243 + hostname := parts[0] 244 + 245 + // Convert to did:web 246 + return "did:web:" + hostname 247 + }
+22 -22
pkg/hold/pds/server.go
··· 128 128 129 129 if !captainExists { 130 130 131 - // Initialize repo if it doesn't exist yet 132 - // Check if repo exists by trying to get the head 133 - head, err := p.carstore.GetUserRepoHead(ctx, p.uid) 134 - if err != nil || !head.Defined() { 135 - // Repo doesn't exist, initialize it 136 - // InitNewActor creates an empty repo with initial commit 137 - err = p.repomgr.InitNewActor(ctx, p.uid, "", p.did, "", "", "") 138 - if err != nil { 139 - return fmt.Errorf("failed to initialize repo: %w", err) 131 + // Initialize repo if it doesn't exist yet 132 + // Check if repo exists by trying to get the head 133 + head, err := p.carstore.GetUserRepoHead(ctx, p.uid) 134 + if err != nil || !head.Defined() { 135 + // Repo doesn't exist, initialize it 136 + // InitNewActor creates an empty repo with initial commit 137 + err = p.repomgr.InitNewActor(ctx, p.uid, "", p.did, "", "", "") 138 + if err != nil { 139 + return fmt.Errorf("failed to initialize repo: %w", err) 140 + } 141 + fmt.Printf("✅ Initialized empty repo\n") 140 142 } 141 - fmt.Printf("✅ Initialized empty repo\n") 142 - } 143 143 144 - // Create captain record (hold ownership and settings) 145 - _, err = p.CreateCaptainRecord(ctx, ownerDID, public, allowAllCrew) 146 - if err != nil { 147 - return fmt.Errorf("failed to create captain record: %w", err) 148 - } 144 + // Create captain record (hold ownership and settings) 145 + _, err = p.CreateCaptainRecord(ctx, ownerDID, public, allowAllCrew) 146 + if err != nil { 147 + return fmt.Errorf("failed to create captain record: %w", err) 148 + } 149 149 150 - fmt.Printf("✅ Created captain record (public=%v, allowAllCrew=%v)\n", public, allowAllCrew) 150 + fmt.Printf("✅ Created captain record (public=%v, allowAllCrew=%v)\n", public, allowAllCrew) 151 151 152 - // Add hold owner as first crew member with admin role 153 - _, err = p.AddCrewMember(ctx, ownerDID, "admin", []string{"blob:read", "blob:write", "crew:admin"}) 154 - if err != nil { 155 - return fmt.Errorf("failed to add owner as crew member: %w", err) 156 - } 152 + // Add hold owner as first crew member with admin role 153 + _, err = p.AddCrewMember(ctx, ownerDID, "admin", []string{"blob:read", "blob:write", "crew:admin"}) 154 + if err != nil { 155 + return fmt.Errorf("failed to add owner as crew member: %w", err) 156 + } 157 157 158 158 fmt.Printf("✅ Added %s as hold admin\n", ownerDID) 159 159 }