zapclient

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Jun 6, 2026 License: BSD-3-Clause Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoPeers is returned when discovery has no live peer for the
	// requested service type.
	ErrNoPeers = errors.New("zapclient: no peers discovered")

	// ErrUnknownProcedure is returned by the server when an incoming
	// opcode does not match any Register call.
	ErrUnknownProcedure = errors.New("zapclient: unknown procedure")

	// ErrPeerUnauthorized is returned when PeerVerifier refuses the
	// incoming peer. Maps to a transport-layer reject.
	ErrPeerUnauthorized = errors.New("zapclient: peer unauthorized")

	// ErrCallTimeout is returned by Call when the per-call deadline
	// elapses before the response arrives.
	ErrCallTimeout = errors.New("zapclient: call timed out")
)

Sentinel errors. Callers branch via errors.Is.

View Source
var ErrReservedOpcode = errors.New("zapclient: procedure name hashes to a reserved opcode")

ErrReservedOpcode is returned when ProcedureOpcode collides with a reserved value. The procedure must be re-named to avoid the conflict.

Functions

func MustOpcode

func MustOpcode(name string) uint16

MustOpcode is ProcedureOpcode that panics on error. Use in package-level var initialisers where a bad procedure name is a build-time bug.

func ProcedureOpcode

func ProcedureOpcode(name string) (uint16, error)

ProcedureOpcode returns the uint16 opcode for a procedure name. The lower 8 bits are zero (matching the existing MsgType<<8 shape in lux/zap); the upper 8 bits are FNV-1a(name) modulo 254 + 1.

Returns ErrReservedOpcode if the hash lands on 0x00 or 0xFF.

Types

type AllowListVerifier

type AllowListVerifier struct {
	// Allowed maps procedure name → set of NodeIDs permitted to call
	// it. Empty set = procedure disabled.
	Allowed map[string]map[string]struct{}
}

AllowListVerifier accepts only peers whose NodeID appears in Allowed[procedure]. Empty Allowed[procedure] means the procedure is not exposed.

func (AllowListVerifier) Verify

func (a AllowListVerifier) Verify(ctx context.Context, peer PeerInfo, procedure string) error

Verify accepts if NodeID is in Allowed[procedure].

type Client

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

Client is a native ZAP RPC client. Created by Connect; closed by Close (or returned stop function from MustConnect).

func Connect

func Connect(ctx context.Context, serviceType string, opts ...ClientOption) (*Client, error)

Connect resolves a service via Discovery and returns a Client. Always defer Close on the returned client.

func MustConnect

func MustConnect(ctx context.Context, serviceType string, opts ...ClientOption) *Client

MustConnect is Connect that panics on error.

func (*Client) Broadcast

func (c *Client) Broadcast(ctx context.Context, procedure string, req *zap.Message) map[string]error

Broadcast sends procedure to every current peer. Returns a map of peer NodeID → error so the caller can re-try the failures.

func (*Client) Call

func (c *Client) Call(ctx context.Context, procedure string, req *zap.Message) (*zap.Message, error)

Call invokes procedure on the picked peer and waits for a response. Respects the client-level CallTimeout in addition to ctx.

func (*Client) Close

func (c *Client) Close() error

Close releases the underlying ZAP node + discovery.

func (*Client) Peers

func (c *Client) Peers() []Peer

Peers returns the current peer snapshot.

func (*Client) Send

func (c *Client) Send(ctx context.Context, procedure string, req *zap.Message) error

Send invokes procedure as fire-and-forget — no response awaited.

type ClientOption

type ClientOption func(*ClientOptions)

ClientOption is the functional-option constructor knob.

func WithBrowseInterval

func WithBrowseInterval(d time.Duration) ClientOption

WithBrowseInterval sets the default mDNS browse interval.

func WithCallTimeout

func WithCallTimeout(d time.Duration) ClientOption

WithCallTimeout caps each Call's wait for a response.

func WithDiscoverTimeout

func WithDiscoverTimeout(d time.Duration) ClientOption

WithDiscoverTimeout caps the initial peer-discovery wait.

func WithDiscovery

func WithDiscovery(d Discovery) ClientOption

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

func WithLogger

func WithLogger(l *slog.Logger) ClientOption

WithLogger sets the structured logger.

func WithMinPeers

func WithMinPeers(n int) ClientOption

WithMinPeers blocks Connect until N peers are discovered.

func WithNodeID

func WithNodeID(id string) ClientOption

WithNodeID names the caller in mDNS announcements.

func WithPicker

func WithPicker(p Picker) ClientOption

WithPicker overrides the per-Call peer selector.

func WithTLS

func WithTLS(cfg *tls.Config) ClientOption

WithTLS configures mutual TLS for the underlying ZAP connection. Required for the local-trust authorisation model on the server side (the server's PeerVerifier reads the peer cert).

type ClientOptions

type ClientOptions struct {
	// NodeID is the caller's identity in mDNS announcements. Empty
	// auto-generates a short suffix.
	NodeID string
	// MinPeers blocks Connect 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 the default mDNS Discovery
	// re-browses. Default 5 seconds.
	BrowseInterval time.Duration
	// CallTimeout caps each Call. Zero = no timeout. Default 30s.
	CallTimeout time.Duration
	// TLS configures mutual TLS. Nil = plaintext (dev only — local-
	// trust mode requires mTLS against the cluster CA).
	TLS *tls.Config
	// Logger for ZAP node + client. Defaults to slog.Default().
	Logger *slog.Logger

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

ClientOptions configure Connect. Construct via WithX options.

type Discovery

type Discovery interface {
	// Peers returns the current peer snapshot. The returned slice is
	// freshly allocated; callers may retain it.
	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; the client may call Peers() from every in-flight Call and Send.

type LocalTrustVerifier

type LocalTrustVerifier struct{}

LocalTrustVerifier accepts any peer presenting a valid mTLS cert from the cluster CA. The underlying TLS handshake already verified the chain; this verifier returns nil for every authenticated peer.

Use when:

  • the peer is on the cluster-private network
  • the listener was constructed with the cluster CA in ClientCAs
  • all in-cluster services should be allowed to call all procedures (apply per-procedure RBAC in the handler if needed)

func (LocalTrustVerifier) Verify

func (LocalTrustVerifier) Verify(ctx context.Context, peer PeerInfo, procedure string) error

Verify accepts any authenticated peer.

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.

NodeID uniquely identifies the peer within ServiceType across discovery cycles. Address is the dial target (host:port). For in-cluster peers under mTLS, the authenticated peer identity comes from the TLS session — NodeID is a hint, not a trust anchor.

type PeerInfo

type PeerInfo struct {
	NodeID      string
	ServiceType string
	// TLSCertSubject is the Subject CN of the mTLS peer cert, when
	// the listener was configured with TLS. Empty under plaintext
	// (local-dev) transport.
	TLSCertSubject string
	// TLSCertSANs are the Subject Alternative Names from the peer
	// cert. Authorisation should prefer SANs over the legacy CN.
	TLSCertSANs []string
}

PeerInfo is the authenticated peer identity surfaced to server-side handlers and PeerVerifier.

type PeerVerifier

type PeerVerifier interface {
	// Verify returns nil on accept, ErrPeerUnauthorized (or wrapping
	// error) on reject. Implementations MUST NOT block — refer to
	// pre-built decision tables, not network calls.
	Verify(ctx context.Context, peer PeerInfo, procedure string) error
}

PeerVerifier is the server-side authorisation hook. Runs on every inbound message before procedure dispatch — return non-nil to reject the call.

The PeerInfo carries the authenticated peer identity (NodeID + mTLS cert chain if present). Procedure is the procedure name the caller requested. PeerVerifier should compare the (peer, procedure) pair against the service's authorisation policy.

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 for a single Call or Send. Implementations MUST be cheap (sub-microsecond) and goroutine-safe; the client invokes Pick from every concurrent op.

type ProcedureHandler

type ProcedureHandler func(ctx context.Context, peer PeerInfo, req *zap.Message) (*zap.Message, error)

ProcedureHandler runs server-side for one inbound procedure call. Return nil + nil-err to ack a fire-and-forget Send. Return a response + nil-err to reply to a Call. Return nil + non-nil err to signal failure; the client side observes the err on its Call.

type RoundRobinPicker

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

RoundRobinPicker rotates through peers in registration order. Zero-value is ready to use; goroutine-safe.

func (*RoundRobinPicker) Pick

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

Pick returns the next peer via round-robin.

type Server

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

Server is the native ZAP server side: procedure-name dispatch on top of *zap.Node. Construct with NewServer, Register procedures, Start to begin accepting, Stop to release.

func NewServer

func NewServer(serviceType string, opts ...ServerOption) (*Server, error)

NewServer constructs a server for the given service type + port. The returned Server is not yet listening — call Start.

func (*Server) NodeID

func (s *Server) NodeID() string

NodeID returns the server's NodeID — useful for tests + ops.

func (*Server) Register

func (s *Server) Register(procedure string, h ProcedureHandler) error

Register binds a procedure name to a handler.

Refuses to register if the procedure's opcode collides with an already-registered procedure — the caller MUST rename. With the 8-bit codespace, occasional collisions are expected; the build fails clearly rather than silently routing to the wrong handler.

func (*Server) Start

func (s *Server) Start() error

Start binds the listener and begins accepting. Call Stop on shutdown.

func (*Server) Stop

func (s *Server) Stop()

Stop releases the underlying node + listener. Idempotent.

type ServerOption

type ServerOption func(*ServerOptions)

ServerOption is a functional-option knob.

func WithNoDiscovery

func WithNoDiscovery() ServerOption

WithNoDiscovery disables mDNS advertisement (test-only).

func WithServerLogger

func WithServerLogger(l *slog.Logger) ServerOption

WithServerLogger sets the structured logger.

func WithServerMetadata

func WithServerMetadata(m map[string]string) ServerOption

WithServerMetadata sets the mDNS TXT-record metadata.

func WithServerNodeID

func WithServerNodeID(id string) ServerOption

WithServerNodeID names this server in mDNS announcements.

func WithServerTLS

func WithServerTLS(cfg *tls.Config) ServerOption

WithServerTLS configures mutual TLS on the listener.

func WithVerifier

func WithVerifier(v PeerVerifier) ServerOption

WithVerifier installs the server-side PeerVerifier. Default is LocalTrustVerifier, which accepts any authenticated peer. Set to AllowListVerifier or a custom impl for stricter policy.

type ServerOptions

type ServerOptions struct {
	NodeID   string
	Port     int
	TLS      *tls.Config
	Verifier PeerVerifier
	Logger   *slog.Logger
	// Metadata is the mDNS TXT-record metadata advertised to peers.
	Metadata map[string]string
	// NoDiscovery disables mDNS advertisement entirely. Use for
	// stdio / unix-socket tests.
	NoDiscovery bool
}

ServerOptions configure NewServer.

Jump to

Keyboard shortcuts

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