wsbridge

package
v0.64.1 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package wsbridge bidirectionally forwards WebSocket frames between two connections. Frame-level forwarding: doesn't parse JSON-RPC. JSON-RPC envelope boundaries are preserved because each Read/Write pair transfers exactly one frame — never byte concatenation.

Index

Constants

View Source
const TCPKeepAlivePeriod = 15 * time.Second

TCPKeepAlivePeriod is the TCP keepalive period the gateways use on every accepted connection. 15s strikes the balance between probing often enough to defeat aggressive idle middleboxes (NAT/CGNAT timeouts as low as 60-180s) and not flooding healthy paths.

On Linux, Go's net.ListenConfig.KeepAlive sets both TCP_KEEPIDLE (idle before first probe) and TCP_KEEPINTVL (between probes) to this value, with TCP_KEEPCNT defaulting to 9 — so a dead TCP path is detected ~2.5 minutes after the last user/ws-PING traffic.

Variables

View Source
var DropFrame = []byte("__wsbridge_drop_frame__")

DropFrame is returned by an Interceptor callback to indicate the frame should NOT be forwarded downstream. Distinct from returning nil (forward unchanged) and from returning a rewritten slice (forward replacement).

Functions

func KeepAlive added in v0.52.1

func KeepAlive(ctx context.Context, conn *websocket.Conn, interval time.Duration)

KeepAlive sends a ws ping on conn every interval until ctx is cancelled. Exported so the codex-exec-gateway /bridge and inbound handlers (which run their own custom pumps and don't go through RunProxy) can install the same anti-idle behavior.

func ListenWithKeepAlive added in v0.52.1

func ListenWithKeepAlive(ctx context.Context, network, addr string) (net.Listener, error)

ListenWithKeepAlive opens a TCP listener with SO_KEEPALIVE enabled and the keepalive period set to TCPKeepAlivePeriod on every accepted connection. This complements ws-level PING (RFC 6455 control frames) by giving us TCP-layer liveness probes that middleboxes which only inspect TCP traffic can also see.

func PumpFrames

func PumpFrames(ctx context.Context, src, dst *websocket.Conn) error

PumpFrames reads one frame at a time from src and writes the exact same (MessageType, payload) to dst. This preserves JSON-RPC envelope boundaries.

Returns nil when src closes cleanly; otherwise the underlying error.

func RunProxy

func RunProxy(ctx context.Context, a, b *websocket.Conn, onFrame func()) error

RunProxy starts two pumps in parallel and returns when either side closes or errors. Both ws conns are left open for the caller to close. onFrame is called on every successfully read frame (from either direction); pass nil if no callback is needed.

A background ping is sent on `a` every keepAliveInterval to keep idle-killing middleboxes from severing the connection during long quiet periods (e.g. the LLM taking minutes to respond before any frame flows).

func RunProxyWithInterceptor added in v0.59.1

func RunProxyWithInterceptor(ctx context.Context, a, b *websocket.Conn, intc Interceptor, onFrame func()) error

RunProxyWithInterceptor is like RunProxy but lets the caller observe and rewrite frames per direction. `onFrame` is invoked on every successfully forwarded frame (pass nil to skip).

Types

type Interceptor added in v0.59.1

type Interceptor struct {
	OnClientFrame func(frame []byte) []byte // a → b direction
	OnServerFrame func(frame []byte) []byte // b → a direction
}

Interceptor lets a caller observe and optionally rewrite frames as they cross the bridge. Both callbacks may be nil. Returning a non-nil slice replaces the frame written downstream; returning nil forwards the original frame untouched. Return DropFrame to swallow the frame entirely. Callbacks MUST NOT block.

Jump to

Keyboard shortcuts

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