Documentation
¶
Overview ¶
Package wstransport tunnels gRPC over a WebSocket, so a standard google.golang.org/grpc client and server speak to each other across a carrier the browser can actually use.
Like the sibling grpc-transports carriers (ssh, wireguard), the shape is "one net.Listener, one client dialer":
- the server side exposes a net.Listener you hand straight to grpc.Server.Serve (see ListenWebSocket), or an http.Handler + net.Listener pair you mount on an existing mux (see HandlerListener);
- the client side provides a grpc.DialOption whose context dialer opens a WebSocket and presents it to grpc-go as a net.Conn (see DialOption).
Why WebSocket, and why it matters for wasm ¶
grpc-go runs its HTTP/2 framing in userspace over whatever net.Conn the dialer returns — it never needs an OS socket or access to HTTP/2 trailers. A browser cannot open raw TCP and cannot read HTTP/2 trailers, which is why grpc-web is limited to unary and server-streaming and needs an Envoy/ grpcwebproxy sidecar. Wrapping a browser WebSocket as a net.Conn sidesteps both limits: the same grpc-go transport runs unmodified under GOOS=js/GOARCH=wasm and gets full client-streaming and bidirectional streaming, with no sidecar — the server is just a grpc.Server behind this package's net.Listener.
Build targets ¶
DialOption has two implementations selected by build tag. On native targets it dials with github.com/coder/websocket; on js/wasm it dials the browser's WebSocket via syscall/js with zero third-party dependencies. The public signature is identical on both, mirroring wireguard's userspace/kernel backend split.
Transport security ¶
The WebSocket layer carries transport security: use a wss:// URL (set ServerConfig.TLSConfig on the server; the browser or ClientConfig.TLSConfig on the client). grpc-go therefore sees a plain net.Conn and should be dialed with insecure transport credentials:
opt, _ := wstransport.DialOption("wss://svc.example/grpc", wstransport.ClientConfig{})
cc, _ := grpc.NewClient("passthrough:///svc",
grpc.WithTransportCredentials(insecure.NewCredentials()), opt)
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DialOption ¶
func DialOption(wsURL string, cfg ClientConfig) (grpc.DialOption, error)
DialOption returns a grpc.DialOption that tunnels every gRPC channel over a WebSocket to wsURL (ws:// or wss://). Combine it with insecure transport credentials — transport security is provided by the WebSocket layer (wss).
func HandlerListener ¶
func HandlerListener(cfg ServerConfig) (http.Handler, net.Listener)
HandlerListener returns an http.Handler that upgrades WebSocket requests on cfg.Path into net.Conns, together with the net.Listener those conns are delivered on. Mount the handler on an existing http.ServeMux (e.g. to serve a wasm client and its gRPC endpoint from one origin) and pass the listener to grpc.Server.Serve.
func ListenWebSocket ¶
func ListenWebSocket(addr string, cfg ServerConfig) (net.Listener, error)
ListenWebSocket binds addr, serves the WebSocket upgrade handler on it, and returns a net.Listener that yields one net.Conn per accepted WebSocket — ready for grpc.Server.Serve. When cfg.TLSConfig is set the server speaks wss:// (TLS). Closing the returned listener stops the server.
Types ¶
type ClientConfig ¶
type ClientConfig struct {
// Subprotocols requested during the WebSocket handshake.
Subprotocols []string
// TLSConfig customizes TLS for wss:// dials (native only).
TLSConfig *tls.Config
// HTTPHeader is sent with the handshake request (native only).
HTTPHeader http.Header
// Logger, when non-nil, receives non-fatal dial diagnostics.
Logger *log.Logger
}
ClientConfig configures the dialing side of the transport. It is shared by both the native and js/wasm implementations of DialOption; fields noted as native-only are ignored on js/wasm, where the browser owns TLS and headers.
type ServerConfig ¶
type ServerConfig struct {
// Path is the HTTP path WebSocket upgrades are accepted on. Empty means "/".
Path string
// TLSConfig, when non-nil, makes [ListenWebSocket] serve over TLS (wss://).
TLSConfig *tls.Config
// OriginPatterns is passed to the WebSocket handshake to authorize browser
// Origins. Empty means same-origin only; use []string{"*"} to allow all.
OriginPatterns []string
// Logger, when non-nil, receives non-fatal handshake diagnostics.
Logger *log.Logger
}
ServerConfig configures the WebSocket-accepting side of the transport.
