Documentation
¶
Overview ¶
Code generated by apic; DO NOT EDIT.
Index ¶
- Variables
- func ReadFeed(conn *wsx.Conn) (types.FeedMsg, error)
- func RegisterGeneratedWS(mux *http.ServeMux, srv WSServerInterface, opts WSOptions)
- func WithWSLimiter(opts *WSOptions, path string, lim *wsx.Limiter)
- func WsValidateFeedMsg(b []byte) (types.FeedMsg, error)
- type UnimplementedWSServer
- type WSOptions
- type WSServerInterface
Constants ¶
This section is empty.
Variables ¶
var ErrNotImplemented = errors.New("not implemented")
ErrNotImplemented is returned by UnimplementedWSServer methods.
Functions ¶
func ReadFeed ¶ added in v0.17.0
ReadFeed is the VALIDATING entry point for this endpoint's declared messageSchema (types.FeedMsg): it reads one WebSocket message from conn and runs it through WsValidateFeedMsg (G-04) before returning it. Call this instead of conn.ReadMessage() directly inside Feed -- conn.ReadMessage() returns the raw frame with NO schema validation performed; this wrapper is the only way that validation actually happens on the read path (L-53: it is opt-in, not framework-enforced -- nothing stops Feed from calling conn.ReadMessage() instead and skipping validation entirely).
func RegisterGeneratedWS ¶
func RegisterGeneratedWS(mux *http.ServeMux, srv WSServerInterface, opts WSOptions)
RegisterGeneratedWS registers WebSocket endpoints; srv handles business logic.
Each accepted connection is handed to srv with a connection-scoped ctx carrying the verified caller; see WSServerInterface for what it carries and when it ends, and WSOptions.ShutdownContext for ending every open connection these routes accepted at once, with status 1001 (going away).
GAP-0076: when the configuration declares at least one WebSocket endpoint with auth: "jwt" but the caller supplied a nil opts.AuthJWT, this function panics with securex.ErrAuthVerifierRequired BEFORE any endpoint is registered. The same guard fires for auth: "api_key" + nil opts.Auth via securex.ErrAuthAPIKeyRequired. Use securex.NewTestVerifier() as the unit-test escape hatch.
func WithWSLimiter ¶
WithWSLimiter installs a custom *wsx.Limiter for a single path. Pass to the caller's option-builder when assembling WSOptions. The override survives ws.go.tmpl regeneration: a consumer that wires a Redis-backed cap need not patch the template. GAP-0075.
func WsValidateFeedMsg ¶ added in v0.17.0
WsValidateFeedMsg decodes a WebSocket text/JSON message payload against the declared messageSchema types.FeedMsg and enforces its Valid() constraints (G-04). REST, MCP, and GraphQL all decode + Valid() their bound schemas before a handler ever sees the value; the WebSocket surface owns its own read loop (WSServerInterface hands the raw *wsx.Conn to the business handler, so the generator cannot unilaterally intercept every read the way it does for REST/MCP/GraphQL's single request/response cycle), so this helper -- plus the Read<MethodName> wrapper(s) below that call it -- is the enforcement point: use it (directly, or via the wrapper) instead of decoding conn.ReadMessage()'s payload by hand, and a malformed or constraint-violating frame is rejected before your handler logic runs. The frame is decoded strictly (RejectUnknownMembers, as the REST binder does), so an unknown or misspelled member is refused, not dropped (SONNY-2538).
Types ¶
type UnimplementedWSServer ¶
type UnimplementedWSServer struct{}
UnimplementedWSServer returns ErrNotImplemented for every WebSocket endpoint, after closing the connection with status 1011 (the server cannot fulfil the request) and reason "not implemented".
type WSOptions ¶
type WSOptions struct {
Auth func(*http.Request) error
AuthJWT func(*http.Request) error
// Limiters is an optional per-path override of the auto-built
// process-local *wsx.Limiter. Use to wire e.g. a Redis-backed
// limiter for cross-pod accounting. A path not present in the map
// gets the auto-built limiter. GAP-0075.
Limiters map[string]*wsx.Limiter
// ShutdownContext, when non-nil, bounds every connection these routes
// accept: once it is cancelled, each open connection is closed with
// status 1001 (going away) and its ctx is cancelled, so a handler parked
// in conn.ReadMessage returns. http.Server.Shutdown neither closes nor
// waits for hijacked connections, so a server that mounts these routes
// should cancel it when it shuts down; the generated Serve does
// (SONNY-792). Nil leaves each connection open until its handler returns
// or its upgrade request's context ends. It bounds the connections these
// routes accept; a handler a GraphQL subscription runs in-process is
// bounded by the resolvers' WithShutdownContext instead, which the
// generated Serve passes the same context.
ShutdownContext context.Context
// Handlers, when non-nil, counts every handler these routes run, from
// the upgrade request until the connection is closed, so a server's
// shutdown can wait for them (Handlers.Wait). Once Wait has begun, a new
// upgrade is refused with 503. The generated Serve cancels
// ShutdownContext, then waits under its shutdown deadline (SONNY-792).
Handlers *wsx.HandlerGroup
}
WSOptions configures cross-cutting concerns for WebSocket endpoints.
type WSServerInterface ¶
type WSServerInterface interface {
Binary(ctx context.Context, conn *wsx.Conn) error
Feed(ctx context.Context, conn *wsx.Conn) error
}
WSServerInterface defines the business logic contract for generated WebSocket endpoints. Embed UnimplementedWSServer and override only the endpoints you need.
ctx is the connection-scoped context (SONNY-792). The generated wrapper derives it from the upgrade request's context after the route's auth verifier has run, so it keeps every value that request carried -- the verifier's claims (securex.ClaimsFromContext), the request and correlation ids, the upgrade's tracing span -- and adds the verified caller: callerctx.MustCaller(ctx) (or securex.MustCaller(ctx)). The caller is built once, at upgrade time, and is shared and read-only; its identity fields come only from what the route's verifier attested -- never from an unverified header, a query parameter or a frame. It is KindUnknown, with no roles and no scopes, when nothing attested an identity: every public route, and an api_key route unless its verifier stashes claims. conn.Context() returns this same ctx.
ctx lives exactly as long as the connection. It is cancelled when your method returns (the wrapper then closes conn). If ctx ends first -- WSOptions.ShutdownContext is cancelled (the generated Serve does this when the server shuts down; the client then gets close status 1001, going away) or the upgrade request's own context is cancelled -- the wrapper closes conn, so a method parked in conn.ReadMessage returns. A peer close or network failure reaches your method as a conn.ReadMessage or conn.WriteMessage error: return, and every goroutine you started with ctx sees it end. Pass ctx to every downstream call; do not swap in a detached root context, which would lose both the caller and the cancellation.
A method can also be reached through a GraphQL subscription, over an in-process connection. ctx then ends with the subscription, or when the server shuts down (the GraphQL resolvers' WithShutdownContext; the generated Serve passes it, and closes the subscriber's graphql-ws connection with 1001 too). Either way the generated Serve ends every WebSocket connection it owns at shutdown.
IMPORTANT (L-53): each method receives the raw *wsx.Conn. Calling conn.ReadMessage() directly performs NO schema validation, even for an endpoint that declares a messageSchema -- the framework cannot intercept or enforce validation on your behalf here (doing so would require either a breaking signature change on this interface, or teaching the config-agnostic pkg/wsx package about a specific generation's schema types, neither of which is done). For an endpoint with a declared messageSchema, call Read<MethodName>(conn) instead of conn.ReadMessage() -- that is the validating entry point; see its doc comment below.