Documentation
¶
Overview ¶
Package wsclient is the aspect-and-Outpost-side WebSocket client. Handles dial + auth + reconnect + framed send/receive + correlation- id tracking for request/response pairs. Used by the aspect runtime in part 3 and the Outpost in part 6.
Design: one Client per logical connection. Run() blocks until ctx is cancelled, transparently reconnecting on drop. Callers send frames via Send (fire-and-forget) or Request (awaits correlated response). Incoming frames with no pending correlation are delivered via the Handler callback.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a persistent WS connection that handles reconnection and request/response correlation. Safe for concurrent use of Send and Request after Run has started.
func (*Client) Connected ¶
Connected reports whether the client currently has an active WS. Useful for tests and observability.
func (*Client) Events ¶
func (c *Client) Events() <-chan ConnectEvent
Events returns the connect-event channel. Subscribers get a ConnectEvent on every dial-success and every disconnect. The channel is shared (single channel, not fan-out) — only one consumer per Client; that consumer must read promptly or events get dropped. Use this instead of polling Connected() for register-on-connect flows (#29).
func (*Client) Request ¶
Request sends a frame and waits for the correlated response. The frame must be a NewRequest-shaped envelope (non-empty ID). Returns the response envelope or an error (timeout via ctx, or disconnect).
func (*Client) Run ¶
Run drives the dial+serve+reconnect loop. Blocks until ctx done. Returns the first-connect error if FailFirstConnect is true and the initial dial fails; otherwise always returns ctx.Err() on exit.
Backoff: on dial failure (never connected), exponential backoff applies. On read-loop failure (connection was established then dropped), backoff resets to MinReconnectDelay — a sleep gap or transient network flap shouldn't permanently accumulate delay.
type Config ¶
type Config struct {
// URL is the WS endpoint to dial, e.g. wss://nexus.host:7888/connect.
URL string
// AuthToken is sent as Authorization: Bearer on the upgrade.
// When TokenProvider is set, AuthToken is the fallback used if
// TokenProvider returns an error. In the common JWT case set
// AuthToken to the initial token and wire TokenProvider to return
// a fresh token on each reconnect.
AuthToken string
// TokenProvider, when set, is called before each dial attempt to
// obtain a fresh auth token. The returned string is used instead
// of Config.AuthToken for this dial. If TokenProvider returns an
// error, AuthToken is used as a fallback (retaining whatever was
// previously set). Callers with JWT-based auth should wire a
// TokenProvider that re-validates against the keyfile endpoint.
// When nil, AuthToken is used directly (backward compatible).
TokenProvider func(ctx context.Context) (string, error)
// Handler receives uncorrelated incoming frames. Required.
Handler Handler
// Logger is optional; nil falls back to slog.Default().
Logger *slog.Logger
// FailFirstConnect, when true, causes Run to return an error if
// the initial dial fails. Aspects with NEXUS_OUTPOST set use this
// to fail-loudly per transport spec §3.5. Aspects doing a pure
// reconnect (no explicit outpost override) set false.
FailFirstConnect bool
// MinReconnectDelay / MaxReconnectDelay bound the exponential
// backoff on reconnect. Defaults: 1s → 60s.
MinReconnectDelay time.Duration
MaxReconnectDelay time.Duration
}
Config configures a Client.
type ConnectEvent ¶
type ConnectEvent struct {
Connected bool
}
ConnectEvent is delivered on the channel returned by Events() each time the connection transitions. Connected=true means a fresh dial succeeded; Connected=false means the active connection dropped. Pre-#29 callers polled Connected() on a 50ms tick — wasteful and missed mid-tick disconnects so a reconnect didn't trigger re-register.
type Handler ¶
Handler processes incoming frames that aren't correlated to a pending Request. The client calls Handle from its read goroutine; handlers should not block.
type HandlerFunc ¶
HandlerFunc adapts a plain function to the Handler interface.
func (HandlerFunc) Handle ¶
func (f HandlerFunc) Handle(env frames.Envelope)
Handle implements Handler.