mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-31 13:17:09 +00:00
111 lines
3.3 KiB
Go
111 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
|
|
"atcr.io/pkg/hold"
|
|
"atcr.io/pkg/hold/pds"
|
|
|
|
// Import storage drivers
|
|
_ "github.com/distribution/distribution/v3/registry/storage/driver/filesystem"
|
|
_ "github.com/distribution/distribution/v3/registry/storage/driver/s3-aws"
|
|
)
|
|
|
|
func main() {
|
|
// Load configuration from environment variables
|
|
cfg, err := hold.LoadConfigFromEnv()
|
|
if err != nil {
|
|
log.Fatalf("Failed to load config: %v", err)
|
|
}
|
|
|
|
// Initialize embedded PDS if database path is configured
|
|
// This must happen before creating HoldService since service needs PDS for authorization
|
|
var holdPDS *pds.HoldPDS
|
|
var xrpcHandler *pds.XRPCHandler
|
|
var broadcaster *pds.EventBroadcaster
|
|
if cfg.Database.Path != "" {
|
|
// Generate did:web from public URL
|
|
holdDID := pds.GenerateDIDFromURL(cfg.Server.PublicURL)
|
|
log.Printf("Initializing embedded PDS with DID: %s", holdDID)
|
|
|
|
// Initialize PDS with carstore and keys
|
|
ctx := context.Background()
|
|
holdPDS, err = pds.NewHoldPDS(ctx, holdDID, cfg.Server.PublicURL, cfg.Database.Path, cfg.Database.KeyPath)
|
|
if err != nil {
|
|
log.Fatalf("Failed to initialize embedded PDS: %v", err)
|
|
}
|
|
|
|
// Bootstrap PDS with captain record and hold owner as first crew member
|
|
if err := holdPDS.Bootstrap(ctx, cfg.Registration.OwnerDID, cfg.Server.Public, cfg.Registration.AllowAllCrew); err != nil {
|
|
log.Fatalf("Failed to bootstrap PDS: %v", err)
|
|
}
|
|
|
|
// Create event broadcaster for subscribeRepos firehose
|
|
broadcaster = pds.NewEventBroadcaster(holdDID, 100) // Keep 100 events for backfill
|
|
|
|
// Wire up repo event handler to broadcaster
|
|
holdPDS.RepomgrRef().SetEventHandler(broadcaster.SetRepoEventHandler(), true)
|
|
|
|
log.Printf("Embedded PDS initialized successfully with firehose enabled")
|
|
} else {
|
|
log.Fatalf("Database path is required for embedded PDS authorization")
|
|
}
|
|
|
|
// Create hold service with PDS
|
|
service, err := hold.NewHoldService(cfg, holdPDS)
|
|
if err != nil {
|
|
log.Fatalf("Failed to create hold service: %v", err)
|
|
}
|
|
|
|
// Create blob store adapter and XRPC handler
|
|
if holdPDS != nil {
|
|
holdDID := holdPDS.DID()
|
|
blobStore := hold.NewHoldServiceBlobStore(service, holdDID)
|
|
xrpcHandler = pds.NewXRPCHandler(holdPDS, cfg.Server.PublicURL, blobStore, broadcaster, nil)
|
|
}
|
|
|
|
// Setup HTTP routes
|
|
mux := http.NewServeMux()
|
|
|
|
// Root page
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path == "/" {
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
fmt.Fprintf(w, "This is a hold server. More info at https://atcr.io")
|
|
return
|
|
}
|
|
http.NotFound(w, r)
|
|
})
|
|
|
|
// Register XRPC/ATProto PDS endpoints if PDS is initialized
|
|
if xrpcHandler != nil {
|
|
log.Printf("Registering ATProto PDS endpoints")
|
|
xrpcHandler.RegisterHandlers(mux)
|
|
}
|
|
|
|
// Create server
|
|
server := &http.Server{
|
|
Addr: cfg.Server.Addr,
|
|
Handler: mux,
|
|
ReadTimeout: cfg.Server.ReadTimeout,
|
|
WriteTimeout: cfg.Server.WriteTimeout,
|
|
}
|
|
|
|
// Start server in goroutine so we can do auto-registration after it's running
|
|
serverErr := make(chan error, 1)
|
|
go func() {
|
|
log.Printf("Starting hold service on %s", cfg.Server.Addr)
|
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
serverErr <- err
|
|
}
|
|
}()
|
|
|
|
// Wait for server error or shutdown
|
|
if err := <-serverErr; err != nil {
|
|
log.Fatalf("Server failed: %v", err)
|
|
}
|
|
}
|