Files
at-container-registry/cmd/hold/main.go
T

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)
}
}