clienthttp

package
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 13, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoPeers is returned by Picker when discovery has no live
	// peers for the service.
	ErrNoPeers = errors.New("clienthttp: no peers discovered")
)

Sentinel errors. Callers branch via errors.Is.

Functions

func NewClient

func NewClient(serviceType string, opts ...Option) (*http.Client, func(), error)

NewClient resolves a service and returns an *http.Client that composes Discovery + Picker + Dialer + AuthAttacher.

The returned stop function releases the underlying Discovery and the Dialer's cached transports. Always defer stop() on success.

Types

type AuthAttacher

type AuthAttacher interface {
	// Attach mutates req in place. A non-nil error aborts the
	// RoundTrip — surface this rather than silently dropping auth.
	Attach(req *http.Request, peer Peer) error
}

AuthAttacher injects per-call authentication onto outgoing requests. It runs after Picker selects the peer but before the RoundTrip itself, so the chosen peer can influence which credential gets attached (e.g. local-trust skips the bearer, cross-cluster uses a different key).

Implementations MUST NOT block — set headers and return. Network I/O belongs in the Dialer's RoundTripper, not the AuthAttacher.

type BearerAttacher

type BearerAttacher struct {
	Bearer string
}

BearerAttacher attaches a bearer token. Empty Bearer is a no-op (the bearer field is the no-trust-needed signal).

func (BearerAttacher) Attach

func (a BearerAttacher) Attach(req *http.Request, _ Peer) error

Attach sets `Authorization: Bearer <Bearer>` unless the request already carries an Authorization header (per-call overrides win).

type Dialer

type Dialer interface {
	// Dial returns a RoundTripper speaking to peer.Address. The
	// returned RoundTripper is goroutine-safe and reusable.
	Dial(ctx context.Context, peer Peer) (http.RoundTripper, error)
}

Dialer returns an http.RoundTripper that talks to one peer.

The returned RoundTripper SHOULD be cached per address so the underlying transport's connection pool gets reused. clienthttp's default transport handles caching internally; custom Dialers MAY cache or return fresh RoundTrippers as appropriate.

type Discovery

type Discovery interface {
	// Peers returns the current peer snapshot. Order is implementation-
	// defined; consumers MUST NOT mutate the returned slice.
	Peers() []Peer

	// PeerCount returns len(Peers()) cheaply.
	PeerCount() int

	// ServiceType reports the service the Discovery is browsing.
	ServiceType() string

	// Start begins the discovery loop. Calling Start twice on the same
	// Discovery is a programmer error.
	Start() error

	// Stop releases all resources. Idempotent.
	Stop()
}

Discovery is the peer-enumeration contract.

Implementations MUST be goroutine-safe; clienthttp may call Peers() from every in-flight RoundTrip and from background reconciliation. PeerCount() is a hot-path helper for waitForPeers and similar gating logic; it MUST return cheap snapshot semantics, not require a network probe.

type NoAuthAttacher

type NoAuthAttacher struct{}

NoAuthAttacher is the local-trust attacher: trust comes from the mDNS-bounded ZAP TLS scope, not from a header. Calling code can still pass per-call headers; this attacher just does nothing.

func (NoAuthAttacher) Attach

func (NoAuthAttacher) Attach(*http.Request, Peer) error

Attach is a no-op.

type Option

type Option func(*Options)

Option is the functional-option constructor knob.

func WithAuthAttacher

func WithAuthAttacher(a AuthAttacher) Option

WithAuthAttacher pins a custom AuthAttacher (mTLS-derived identity, signed-request headers, etc.). Overrides WithBearer and WithLocalTrust.

func WithBearer

func WithBearer(b string) Option

WithBearer attaches `Authorization: Bearer <b>` on every call. Mutually exclusive with WithLocalTrust / WithAuthAttacher.

func WithBrowseInterval

func WithBrowseInterval(d time.Duration) Option

WithBrowseInterval sets the mDNS browse interval (default backend).

func WithClientID

func WithClientID(id string) Option

WithClientID names this caller in its mDNS announcement.

func WithDialer

func WithDialer(d Dialer) Option

WithDialer overrides the per-peer RoundTripper factory.

func WithDiscoverTimeout

func WithDiscoverTimeout(d time.Duration) Option

WithDiscoverTimeout caps the initial peer-discovery wait.

func WithDiscovery

func WithDiscovery(d Discovery) Option

WithDiscovery overrides the peer-discovery backend. Useful for tests + non-mDNS environments (Consul, etcd, static).

func WithHTTPTimeout

func WithHTTPTimeout(d time.Duration) Option

WithHTTPTimeout caps each outbound request's total time.

func WithLocalTrust

func WithLocalTrust() Option

WithLocalTrust signals that this client runs inside the trusted ZAP mesh — the bearer attach is skipped. Use only when:

  • The peer is reachable only on the cluster-private network (k8s pod network, not the public internet).
  • Discovery is mDNS bounded to that network (multicast scope).
  • ZAP TLS verifies peers against the cluster CA so even an attacker on the same segment cannot impersonate a service.

Cross-cluster + ingress callers MUST NOT use this; they require an explicit bearer attached via WithBearer or a custom AuthAttacher.

func WithMinPeers

func WithMinPeers(n int) Option

WithMinPeers waits for at least N peers before NewClient returns.

func WithPicker

func WithPicker(p Picker) Option

WithPicker overrides the per-RoundTrip peer selector.

type Options

type Options struct {
	// ClientID identifies this caller in mDNS announcements. Empty
	// generates a small uuid-like suffix. The id has no security
	// meaning — auth lives in AuthAttacher.
	ClientID string
	// Bearer is shorthand for the default BearerAttacher. Mutually
	// exclusive with WithLocalTrust / WithAuthAttacher; later option
	// wins.
	Bearer string
	// MinPeers blocks NewClient until at least N peers are discovered
	// (or DiscoverTimeout elapses). Default 1.
	MinPeers int
	// DiscoverTimeout caps the initial peer-discovery wait. Default
	// 10 * BrowseInterval.
	DiscoverTimeout time.Duration
	// BrowseInterval is how often mDNS re-browses for peers. Default
	// 5 seconds.
	BrowseInterval time.Duration
	// HTTPTimeout caps each outbound request. Default 30 seconds.
	HTTPTimeout time.Duration

	// Pluggable wiring. nil means "use default for this concern."
	Discovery Discovery
	Picker    Picker
	Dialer    Dialer
	Auth      AuthAttacher
}

Options configure NewClient. Construct via WithX options; do not instantiate directly.

type Peer

type Peer struct {
	NodeID      string
	ServiceType string
	Address     string
	Metadata    map[string]string
	LastSeen    time.Time
}

Peer is the discovery view of one reachable instance of a service.

Address is the dial target ("host:port"). Metadata carries optional hints (zone, version, capabilities) — implementations choose what to surface. NodeID uniquely identifies the peer within ServiceType across discovery cycles so callers can correlate sticky-routing decisions.

type Picker

type Picker interface {
	// Pick returns the chosen peer. ErrNoPeers if peers is empty.
	Pick(peers []Peer) (Peer, error)
}

Picker selects one peer from a Discovery snapshot.

Pick is called once per RoundTrip; implementations MUST be cheap (sub-microsecond) and goroutine-safe.

type RoundRobinPicker

type RoundRobinPicker struct {
	// contains filtered or unexported fields
}

RoundRobinPicker rotates through peers in registration order. Zero-value is ready to use; safe for concurrent Pick calls.

func (*RoundRobinPicker) Pick

func (p *RoundRobinPicker) Pick(peers []Peer) (Peer, error)

Pick returns the next peer via round-robin.

type ZAPHTTPDialer

type ZAPHTTPDialer struct {
	// contains filtered or unexported fields
}

ZAPHTTPDialer returns RoundTrippers speaking ZAP-HTTP. Goroutine- safe; one instance can serve many concurrent peers via the per-address cache.

func NewZAPHTTPDialer

func NewZAPHTTPDialer() *ZAPHTTPDialer

NewZAPHTTPDialer constructs a ZAPHTTPDialer with an empty cache.

func (*ZAPHTTPDialer) Dial

func (d *ZAPHTTPDialer) Dial(_ context.Context, peer Peer) (http.RoundTripper, error)

Dial returns the cached zaphttp.Transport for peer.Address, constructing one on first use.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL