package host import ( "context" "crypto/ed25519" "log" "os" "time" "github.com/carlosframework/platform/internal/release" "github.com/carlosframework/platform/internal/rootstate" ) type rootHistoryMaintenance struct { readback func(context.Context, release.HistoryBinding, func(context.Context) (release.HistoryMigrationStatus, error)) error history *release.RootHistory store release.Store source *proofBindingSource checks rootRestartChecks pub func() (ed25519.PublicKey, error) projection func() (rootstate.Store, error) now func() time.Time } func (m rootHistoryMaintenance) run(ctx context.Context, b release.HistoryBinding) error { resolveContext := func(ctx context.Context, want release.HistoryBinding) (string, error) { _, got, _, err := m.source.unitBinding(ctx, want.Host) if err != nil { return "", err } if got.Route.Account != want.Account || got.Route.App != want.App { return "", os.ErrPermission } return got.Source, nil } resolve := func(want release.HistoryBinding) (string, error) { return resolveContext(ctx, want) } sources := release.HistoryRecoverySources{} defer func() { projection, err := m.projection() if err == nil { err = m.history.ProjectMigrationStatus(projection, b, resolve, sources) projection.Close() } if err != nil { log.Print(err) } if m.readback != nil { err := m.readback(ctx, b, func(readbackCtx context.Context) (release.HistoryMigrationStatus, error) { readbackResolve := func(want release.HistoryBinding) (string, error) { return resolveContext(readbackCtx, want) } return m.history.MigrationStatusWithSources(b, readbackResolve, sources) }) if err != nil { log.Print(err) } } }() unresolved, err := m.checks.copyRecoveryHistory(m.history, b) sources.Known, sources.Unresolved = err == nil, unresolved if err != nil { return err } pub, err := m.pub() if err != nil { return err } now := m.now() if err := m.history.ReceiveReconstruction(ctx, m.store, pub, b, now, resolve); err != nil { return err } if err := m.history.ReceiveRecoveryRetirements(ctx, m.store, pub, b, now, resolve); err != nil { return err } return checkUnresolvedRecoveries(m.history, unresolved) }