Skip to content

WebSocket-to-TCP Proxy

Connect browsers to native Cap'n Proto services (C++, etc.) via WebSocket.

Overview

Browsers can only use WebSocket, while native Cap'n Proto services use raw TCP. This proxy bridges the two:

Browser ──WebSocket──→ Proxy ──TCP──→ C++ Cap'n Proto Service

Quick Start

1. Start Your Cap'n Proto Service

For example, a C++ service on port 7000:

bash
./my-cpp-capnp-server --port 7000

2. Start the Proxy

bash
npx @naeemo/capnp proxy -p 9000 -t localhost:7000

Options:

  • -p, --ws-port: WebSocket server port (default: 8080)
  • -t, --target: Target TCP service (default: localhost:8081)
  • -d, --debug: Enable debug logging

3. Connect from Browser

typescript
import { RpcConnection, WebSocketTransport } from '@naeemo/capnp';
import { MyService } from './my-service.js';

// Connect via proxy
const transport = await WebSocketTransport.connect('ws://localhost:9000');
const connection = new RpcConnection(transport);

// Use the service as if directly connected
const service = await connection.bootstrap().getAs(MyService);
const result = await service.myMethod({ data: 'hello' });

Programmatic Usage

typescript
import { CapnpWebSocketProxy } from '@naeemo/capnp';

const proxy = new CapnpWebSocketProxy({
  wsPort: 9000,
  targetHost: 'localhost',
  targetPort: 7000,
  maxMessageSize: 16 * 1024 * 1024, // 16MB
  connectionTimeout: 30000, // 30 seconds
  debug: true,
});

// Monitor connections
proxy.on('connection', (conn) => {
  console.log('New connection');
});

proxy.on('disconnection', (conn) => {
  console.log('Connection closed');
  console.log('Stats:', conn.getStats());
});

// Shutdown
await proxy.close();

Architecture

Message Flow

  1. Browser → Proxy: WebSocket binary message
  2. Proxy → TCP Service: Raw bytes (no modification)
  3. TCP Service → Proxy: Raw bytes
  4. Proxy → Browser: WebSocket binary message

Protocol Compatibility

FeatureBrowserProxyTCP Service
TransportWebSocketBridgeTCP
FramingWebSocket framesPassthroughCap'n Proto messages
Binary
Full-duplex

Use Cases

Web Dashboard for Native Service

typescript
// Browser: Real-time metrics from C++ backend
const transport = await WebSocketTransport.connect('ws://proxy:9000');
const metrics = await connection.bootstrap().getAs(MetricsService);

// Stream real-time data
for await (const update of metrics.subscribe()) {
  updateChart(update);
}

Cross-Language RPC

typescript
// Browser (TypeScript) calling Python service
// Browser → Proxy → Python Cap'n Proto Server
const transport = await WebSocketTransport.connect('ws://proxy:9000');
const pythonService = await connection.bootstrap().getAs(PythonService);

Development & Debugging

bash
# Proxy local C++ service for browser dev tools
npx @naeemo/capnp proxy -p 9000 -t localhost:7000 --debug

Performance

MetricValue
Latency overhead~1-2ms
Throughput900+ MB/s
Concurrent connections1000+
Message size limitConfigurable (default 16MB)

Security Considerations

  1. CORS: Proxy accepts connections from any origin. Deploy behind a reverse proxy (nginx, etc.) for production.

  2. TLS: Use WSS (WebSocket Secure) in production:

    Browser ──WSS──→ nginx ──WS──→ Proxy ──TCP──→ Service
  3. Authentication: Implement auth at the application layer (Cap'n Proto capabilities) or use a token in the WebSocket URL.

Troubleshooting

Connection Refused

Check that the target TCP service is running:

bash
telnet localhost 7000

Large Messages Fail

Increase the max message size:

typescript
const proxy = new CapnpWebSocketProxy({
  wsPort: 9000,
  targetHost: 'localhost',
  targetPort: 7000,
  maxMessageSize: 64 * 1024 * 1024, // 64MB
});

Debug Mode

Enable verbose logging:

bash
npx @naeemo/capnp proxy -p 9000 -t localhost:7000 --debug

Example: Complete Setup

See examples/websocket-proxy for a complete working example with:

  • C++ Cap'n Proto server
  • WebSocket-to-TCP proxy
  • Browser client

API Reference

CapnpWebSocketProxy

Main proxy class.

Constructor

typescript
new CapnpWebSocketProxy(options: ProxyOptions)

Methods

  • getConnectionCount(): number - Active connections
  • getAllStats(): ConnectionStats[] - Stats for all connections
  • close(): Promise<void> - Graceful shutdown

Events

  • connection - New client connected
  • disconnection - Client disconnected
  • error - Error occurred

ProxyOptions

OptionTypeDefaultDescription
wsPortnumberrequiredWebSocket server port
targetHoststringrequiredTarget TCP host
targetPortnumberrequiredTarget TCP port
maxMessageSizenumber16MBMax WebSocket message size
connectionTimeoutnumber30000TCP connection timeout (ms)
debugbooleanfalseEnable debug logging

Released under the MIT License.