~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
104 lines · 4.0 KB Raw History
package bidder

import (
	"context"
	"errors"
	"time"

	"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/atproto/market"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/policyengine/trust"
)

const AssociationExpiryGrace = 10 * time.Minute

func (b *Bidder) associationExpiry(ctx context.Context, requesterDID, acceptedAt string) string {
	if b.records == nil || requesterDID == "" {
		return ""
	}
	skip := func(reason string, args ...any) string {
		b.log.Info("bidder_association_expiry_skipped", append([]any{"requester", requesterDID, "reason", reason}, args...)...)
		return ""
	}
	refuse := func(reason string, args ...any) string {
		b.log.Warn("bidder_association_expiry_refused", append([]any{"requester", requesterDID, "reason", reason}, args...)...)
		return ""
	}
	mirror, err := b.records.GetRecord(ctx, requesterDID, trust.BadgeBlueKeysNSID, trust.MirrorRKey)
	if errors.Is(err, market.ErrNotFound) {
		return skip("the requester has no keys mirror")
	}
	if err != nil {
		return refuse("the keys mirror is unread", "err", err.Error())
	}
	proof, _ := mirror.Value["proof"].(map[string]any)
	uri, _ := proof["uri"].(string)
	cid, _ := proof["cid"].(string)
	if uri == "" && cid == "" {
		return skip("the keys mirror names no proof")
	}
	if uri == "" || cid == "" || market.NSIDFromURI(uri) != market.AssociationNSID {
		return refuse("the keys mirror proof is no association strongRef", "proof", uri)
	}
	authority := market.ATURIAuthority(uri)
	if authority == "" || authority == requesterDID {
		return refuse("the proof is not in an authority's repo", "proof", uri)
	}
	record, err := b.records.Resolve(ctx, market.RecordRef{URI: uri, CID: cid})
	if err != nil {
		return refuse("the proof is unread", "proof", uri, "err", err.Error())
	}
	if record.CID != cid {
		return refuse("the proof cid changed", "proof", uri)
	}
	assoc, err := market.ParseAssociation(record.Value)
	if err != nil {
		return refuse("the proof is no association", "proof", uri, "err", err.Error())
	}
	if assoc.Contract == nil {
		return skip("the proof is not contract-scoped", "proof", uri)
	}
	if assoc.Subject != requesterDID {
		return refuse("the proof names another subject", "proof", uri, "subject", assoc.Subject)
	}
	if market.ATURIAuthority(assoc.Contract.URI) != authority {
		return refuse("the proof's contract is not the authority's accept", "proof", uri, "contract", assoc.Contract.URI)
	}
	expiresAt, err := market.ParseTime(assoc.ExpiresAt)
	if err != nil {
		return refuse("the proof expiresAt is no datetime", "proof", uri, "expiresAt", assoc.ExpiresAt)
	}
	start := b.now()
	if at, err := market.ParseTime(acceptedAt); err == nil && at.Before(start) {
		start = at
	}
	if bound := start.Add(market.ContractAssociationLifetime); bound.Before(expiresAt) {
		b.log.Info("bidder_association_expiry_capped", "requester", requesterDID, "proof", uri, "expiresAt", assoc.ExpiresAt, "cap", market.FormatTime(bound))
		expiresAt = bound
	}
	out := market.FormatTime(expiresAt)
	b.log.Info("bidder_association_expiry", "requester", requesterDID, "proof", uri, "authority", authority, "expiresAt", out)
	return out
}

func (b *Bidder) releaseAtAssociationExpiry(ctx context.Context, vm *v1alpha1.ComputeVM) time.Duration {
	raw := vm.Spec.AssociationExpiresAt
	if raw == "" || vm.Spec.Release != nil || vm.DeletionTimestamp != nil || b.guests.Ended(vm) {
		return 0
	}
	expiresAt, err := time.Parse(time.RFC3339Nano, raw)
	if err != nil {
		return 0
	}
	deadline := expiresAt.Add(AssociationExpiryGrace)
	if wait := deadline.Sub(b.now()); wait > 0 {
		return wait
	}
	release := v1alpha1.ComputeVMRelease{RequestedAt: b.now().UTC().Format(time.RFC3339)}
	if err := b.intents.ApplyComputeVMRelease(ctx, vm.Name, release); err != nil {
		b.log.Warn("bidder_association_expired_release_failed", "computevm", vm.Name, "err", err.Error())
		return time.Minute
	}
	b.log.Info("bidder_association_expired_release", "computevm", vm.Name, "requester", vm.Spec.Requester.Did, "associationExpiresAt", raw)
	return 0
}