~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
89 lines · 2.5 KB Raw History
package exposure

import (
	"cmp"
	"context"
	"errors"
	"fmt"
	"net/http"
	"strings"

	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/internal/component"
)

var ErrUnknownProtocol = errors.New("unknown protocol")

func Target(ref commonv1.ObjectRef, workspace string) (component.Key, error) {
	kind := strings.TrimSpace(ref.Kind)
	name := strings.TrimSpace(ref.Name)
	if kind == "" {
		return component.Key{}, errors.New("the targetRef has no kind")
	}
	if name == "" {
		return component.Key{}, errors.New("the targetRef has no name")
	}
	targetWorkspace := cmp.Or(strings.TrimSpace(ref.Workspace), workspace)
	return component.Key{Workspace: targetWorkspace, Kind: kind, Name: name}, nil
}

func protocolKind(value exposurev1alpha1.ServiceProtocol) string {
	return strings.ToLower(strings.TrimSpace(string(value)))
}

func HandlerName(value string) string {
	value = strings.TrimSpace(value)
	if value == "" {
		return component.DefaultHandlerName
	}
	return value
}

func FindHandler(ctx context.Context, handlers *component.Handlers, key component.Key, protocol exposurev1alpha1.ServiceProtocol, name string) (http.Handler, bool, error) {
	if handlers == nil {
		return nil, false, nil
	}
	switch protocolKind(protocol) {
	case component.ProtocolHTTP, component.ProtocolWS:
		handler, ok := handlers.Handler(key, name)
		return handler, ok, nil
	case component.ProtocolTCP, component.ProtocolSSH:
		conn, err := handlers.DialStream(ctx, key, name)
		if err != nil {
			if errors.Is(err, component.ErrNoStream) || errors.Is(err, component.ErrHandlersStopped) {
				return nil, false, nil
			}
			return nil, false, err
		}
		_ = conn.Close()
		return nil, true, nil
	default:
		return nil, false, fmt.Errorf("%w %q", ErrUnknownProtocol, protocol)
	}
}

func Endpoints(registry *component.Registry, key component.Key) []string {
	if registry == nil {
		return nil
	}
	seen := map[string]bool{}
	var out []string
	for _, endpoint := range registry.Endpoints(key.Workspace, key.Kind, key.Name) {
		value := strings.TrimSpace(endpoint.URL)
		if value == "" && endpoint.Address != "" {
			protocol := strings.TrimSpace(endpoint.Protocol)
			if protocol != "" {
				value = protocol + "://" + endpoint.Address
			} else {
				value = endpoint.Address
			}
		}
		if value == "" || seen[value] {
			continue
		}
		seen[value] = true
		out = append(out, value)
	}
	return out
}