package console import ( "context" "crypto/rand" "encoding/hex" "errors" "log" "time" "github.com/carlosframework/platform/internal/hostactors" "github.com/carlosframework/platform/internal/hostops" ) func claimOperationID() string { var b [16]byte if _, err := rand.Read(b[:]); err != nil { return "" } return hex.EncodeToString(b[:]) } // Called after NewServer, before background workers. It starts no goroutine. func (s *Server) ConfigureClaimBackfill() error { if !s.cfg.HostClaim { return nil } if s.cfg.Releases == nil || s.cfg.Bucket == "" || len(s.cfg.ReleasePub) == 0 { s.cfg.HostClaimOps = nil log.Printf("console: claim recovery: %v", hostops.ErrContract) return nil } if s.cfg.HostClaimOps == nil { d := hostactors.Directory{Store: s.cfg.Releases, PublicKey: s.cfg.ReleasePub, Bucket: s.cfg.Bucket} c := hostops.NewBackfillController(s.cfg.Releases, d, time.Now, claimOperationID) s.cfg.HostClaimOps = &c } return nil } func (s *Server) ReconcileHostClaims(ctx context.Context) error { if !s.cfg.HostClaim { return nil } if s.cfg.HostClaimOps == nil { return hostops.ErrContract } return hostops.ReconcileClaims(ctx, *s.cfg.HostClaimOps, s.adoptHostRecord) } // Exported for the moves console pass; construction and startup remain separate. func (s *Server) RunClaimRecoveryPass(ctx context.Context) error { if !s.cfg.HostClaim { return nil } if a := s.cfg.ClaimAuthority; a != nil && a.Control != nil { return a.Control.RunRecovery(ctx, s.runClaimRecoveryPassBody) } return s.runClaimRecoveryPassBody(ctx) } func (s *Server) runClaimRecoveryPassBody(ctx context.Context) error { var errs []error if err := s.ReconcileHostClaims(ctx); err != nil { errs = append(errs, err) } if s.cfg.HostClaimRecovery != nil { if err := s.cfg.HostClaimRecovery.Pass(ctx); err != nil { errs = append(errs, err) } } if s.cfg.ClaimAuthority != nil { errs = append(errs, s.SweepClaimHolds(ctx)) } return errors.Join(errs...) }