~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
158 lines · 5.7 KB Raw History
package marketnetwork

import (
	"context"
	"encoding/json"
	"strings"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	commonv1 "github.com/johnandersen777/socialweb-computer-kcp/api/common/v1alpha1"
	exposurev1alpha1 "github.com/johnandersen777/socialweb-computer-kcp/api/exposure/v1alpha1"
	"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/app/compose"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/contract/atprotorepo"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/devinstance"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/fsx"
)

const (
	NetworkVouchLabel = "apps.socialweb.computer/network-vouch"

	networkVouchLinkSet = "network-vouches"

	bidderVouchPrefix = "network-vouch-"
)

func requesterVouchApp(requesterDid string) string {
	return "requester-" + compose.Stamp(requesterDid)
}

func RequesterVouchName(requesterDid string) string {
	return compose.OperatorVouchPrefix + requesterVouchApp(requesterDid)
}

func BidderVouchName(bidderApp string) string {
	return bidderVouchPrefix + bidderApp
}

type operatorOf struct {
	app string
	did string
	at  string
}

type networkRequester struct {
	ws  string
	did string
	at  string
}

type networkBidder struct {
	app string
	ws  string
	did string
}

func (ctl *Controller) declareOperatorVouches(ctx context.Context, r compose.Root, apps []v1alpha1.NetworkApp) {
	var bidderOps, gatewayOps []operatorOf
	var bidders, gateways []string
	var bidderApps []networkBidder
	var requesters []networkRequester
	operator := func(ws, name, app string) (operatorOf, bool) {
		id, err := ctl.c.Identity(ctx, ws, name)
		if err != nil {
			return operatorOf{}, false
		}
		did := compose.OperatorDID(nil, id)
		if did == "" {
			return operatorOf{}, false
		}
		return operatorOf{app: app, did: did, at: id.CreationTimestamp.UTC().Format("2006-01-02T15:04:05Z")}, true
	}
	for _, app := range apps {
		if app.Stopped {
			continue
		}
		ch, err := ctl.child(app)
		if err != nil {
			continue
		}
		var rec devinstance.Record
		if fsx.ReadJSON(ch.layout.Record, &rec) != nil || rec.BaseWorkspace == "" {
			continue
		}
		switch app.Kind {
		case v1alpha1.ApplicationKindMarketBidder:
			bidders = append(bidders, rec.BaseWorkspace)
			if op, ok := operator(rec.BaseWorkspace, BidderIdentity, app.Name); ok {
				bidderOps = append(bidderOps, op)
			}
			if did := strings.TrimSpace(ctl.c.IdentityDid(ctx, rec.BaseWorkspace, BidderIdentity)); did != "" {
				bidderApps = append(bidderApps, networkBidder{app: app.Name, ws: rec.BaseWorkspace, did: did})
			}
		case v1alpha1.ApplicationKindGateway:
			ws := rec.BaseWorkspace + ":" + compose.ComponentWorkspace
			gateways = append(gateways, ws)
			if op, ok := operator(ws, RequesterIdentity, app.Name); ok {
				gatewayOps = append(gatewayOps, op)
			}
		case v1alpha1.ApplicationKindMarketRequester:
			id, err := ctl.c.Identity(ctx, rec.BaseWorkspace, RequesterIdentity)
			if err != nil || strings.TrimSpace(id.Status.Did) == "" {
				continue
			}
			requesters = append(requesters, networkRequester{ws: rec.BaseWorkspace, did: strings.TrimSpace(id.Status.Did),
				at: id.CreationTimestamp.UTC().Format("2006-01-02T15:04:05Z")})
		}
	}
	declare := func(workspaces []string, ops []operatorOf, what string) {
		for _, ws := range workspaces {
			for _, op := range ops {
				if err := ctl.c.ApplyOperatorVouch(ctx, r, ws, op.app, op.did, op.at); err != nil {
					ctl.log().Warn(what, "workspace", ws, "app", op.app, "err", err.Error())
				}
			}
		}
	}
	declare(gateways, bidderOps, "declaring the gateway operator's vouch for a bidder's operator")
	declare(bidders, gatewayOps, "declaring the bidder operator's vouch for a gateway's operator")
	for _, req := range requesters {
		for _, b := range bidderApps {
			if err := ctl.c.ApplyOperatorVouch(ctx, r, b.ws, requesterVouchApp(req.did), req.did, req.at); err != nil {
				ctl.log().Warn("declaring the bidder operator's vouch for a network requester", "workspace", b.ws, "requester", req.did, "err", err.Error())
			}
		}
		if err := ctl.applyRequesterVouches(ctx, r, req, bidderApps); err != nil {
			ctl.log().Warn("declaring a network requester's vouches for the network bidders", "workspace", req.ws, "requester", req.did, "err", err.Error())
		}
	}
}

func (ctl *Controller) applyRequesterVouches(ctx context.Context, r compose.Root, req networkRequester, bidders []networkBidder) error {
	if len(bidders) == 0 {
		return nil
	}
	repo := commonv1.ObjectRef{Group: v1alpha1.GroupName, Kind: compose.KindAtprotoRepo, Name: atprotorepo.RepoName(req.did), Workspace: req.ws}
	records := exposurev1alpha1.ComponentLinkSelector{Group: v1alpha1.GroupName, Kind: "AtprotoRecord", Workspace: req.ws,
		MatchLabels: map[string]string{NetworkVouchLabel: "true"}}
	link := compose.SelectorLink(compose.LinkName("network-vouches", req.ws), records, repo, compose.Cap(atprotorepo.CapabilityWrite, compose.VouchNSID))
	if err := ctl.c.AddLinks(ctx, r, networkVouchLinkSet, []compose.Link{link}); err != nil {
		return err
	}
	for _, b := range bidders {
		record, err := json.Marshal(map[string]any{"$type": compose.VouchNSID, "subject": b.did, "createdAt": req.at})
		if err != nil {
			return err
		}
		repoRef := repo
		repoRef.Workspace = ""
		obj := &v1alpha1.AtprotoRecord{ObjectMeta: metav1.ObjectMeta{Name: BidderVouchName(b.app), Labels: map[string]string{NetworkVouchLabel: "true"}},
			Spec: v1alpha1.AtprotoRecordSpec{RepoRef: &repoRef, Collection: compose.VouchNSID, Rkey: b.did, Record: record,
				DeletionPolicy: v1alpha1.RecordDeletionRetain}}
		if err := ctl.c.ApplyTyped(ctx, r, req.ws, compose.AtprotoRecordGVR, v1alpha1.GroupVersion.String(), "AtprotoRecord", obj); err != nil {
			return err
		}
	}
	return nil
}