~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
101 lines · 2.7 KB Raw History
package gateway

import (
	"context"
	"errors"
)

const (
	EventCluster   = "cluster"
	EventMember    = "member"
	EventNodeClaim = "nodeClaim"
	EventInfo      = "info"

	InfoSnapshotComplete = "SnapshotComplete"
)

type ClusterEvent struct {
	Name            string `cbor:"name"`
	Phase           string `cbor:"phase"`
	Running         bool   `cbor:"running,omitempty"`
	Instance        string `cbor:"instance,omitempty"`
	Server          string `cbor:"server,omitempty"`
	Reason          string `cbor:"reason,omitempty"`
	Message         string `cbor:"message,omitempty"`
	TeardownBlocked bool   `cbor:"teardownBlocked,omitempty"`
	Deleted         bool   `cbor:"deleted,omitempty"`
	Snapshot        bool   `cbor:"snapshot,omitempty"`
	Time            string `cbor:"time"`
}

type MemberEvent struct {
	Cluster  string `cbor:"cluster"`
	Member   string `cbor:"member"`
	Phase    string `cbor:"phase"`
	Reason   string `cbor:"reason,omitempty"`
	Message  string `cbor:"message,omitempty"`
	Deleted  bool   `cbor:"deleted,omitempty"`
	Snapshot bool   `cbor:"snapshot,omitempty"`
	Time     string `cbor:"time"`
}

type NodeClaimEvent struct {
	Cluster       string `cbor:"cluster"`
	Name          string `cbor:"name"`
	NodeName      string `cbor:"nodeName,omitempty"`
	Phase         string `cbor:"phase"`
	Message       string `cbor:"message,omitempty"`
	ContractPhase string `cbor:"contractPhase,omitempty"`
	Outcome       string `cbor:"outcome,omitempty"`
	Bidder        string `cbor:"bidder,omitempty"`
	FQDN          string `cbor:"fqdn,omitempty"`
	Deleted       bool   `cbor:"deleted,omitempty"`
	Snapshot      bool   `cbor:"snapshot,omitempty"`
	Time          string `cbor:"time"`
}

type InfoEvent struct {
	Name    string `cbor:"name"`
	Message string `cbor:"message,omitempty"`
}

type Event struct {
	Type    string
	Payload any
}

type Emit func(Event) error

type Feed interface {
	Follow(ctx context.Context, caller Caller, name string, emit Emit) error
}

var (
	ErrTokenExpired = &XRPCError{"TokenExpired", "the token is expired; get a fresh one and reconnect", 401}

	ErrConsumerTooSlow = &XRPCError{"ConsumerTooSlow", "the client did not read frames fast enough", 429}

	ErrNoFeed = &XRPCError{
		"ClusterUnavailable",
		"this gateway was built without a cluster feed, so there is nothing to subscribe to",
		503,
	}
)

func (s *Server) SubscribeClusters(ctx context.Context, caller Caller, name string, emit Emit) error {
	if caller == "" {
		return ErrUnauthorized
	}
	if s.Feed == nil {
		return ErrNoFeed
	}
	err := s.Feed.Follow(ctx, caller, name, emit)
	if err == nil || errors.Is(err, context.Canceled) {
		return err
	}
	var xe *XRPCError
	if errors.As(err, &xe) {
		return xe
	}
	return &XRPCError{"ClusterUnavailable", "the cluster feed stopped: " + oneLine(err.Error()), 503}
}