Skip to content

Latest commit

 

History

History
214 lines (158 loc) · 3.71 KB

File metadata and controls

214 lines (158 loc) · 3.71 KB

WebSocket Guide

Overview

The WebSocket server provides real-time bidirectional communication between clients and the server.

Server Configuration

WebSocket server runs on port 3001 (configurable via WS_PORT environment variable).

Starting the Server

npm run ws:server

Client Usage

Browser Client

import { WebSocketClient } from '@/lib/websocket/client';

const client = new WebSocketClient('ws://localhost:3001');

// Subscribe to a channel
client.subscribe('my-channel', (data) => {
  console.log('Received message:', data);
});

// Send a message
client.broadcast('my-channel', { message: 'Hello!' });

// Unsubscribe
client.unsubscribe('my-channel');

// Close connection
client.close();

CLI Client

# Listen to a channel
npm run cli ws listen demo

# Send a message to a channel
npm run cli ws send demo "Hello, World!"

Message Protocol

Subscribe to a Channel

Send:

{
  "type": "subscribe",
  "channel": "channel-name"
}

Response:

{
  "type": "subscribed",
  "channel": "channel-name"
}

Unsubscribe from a Channel

Send:

{
  "type": "unsubscribe",
  "channel": "channel-name"
}

Response:

{
  "type": "unsubscribed",
  "channel": "channel-name"
}

Broadcast a Message

Send:

{
  "type": "broadcast",
  "channel": "channel-name",
  "data": { "any": "data" }
}

Notification (sent to all channel subscribers):

{
  "type": "message",
  "channel": "channel-name",
  "data": { "any": "data" }
}

Ping/Pong

Send:

{
  "type": "ping"
}

Response:

{
  "type": "pong"
}

Channel-Based Communication

The WebSocket server uses a channel-based pub/sub model:

  1. Clients subscribe to channels by name
  2. Messages broadcast to a channel are sent to all subscribers
  3. Clients can be subscribed to multiple channels simultaneously
  4. Each client maintains its own set of subscriptions

React Component Example

'use client';

import { useEffect, useState } from 'react';
import { WebSocketClient } from '@/lib/websocket/client';

export function ChatComponent() {
  const [client, setClient] = useState<WebSocketClient | null>(null);
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    const ws = new WebSocketClient('ws://localhost:3001');

    ws.subscribe('chat', (data) => {
      setMessages(prev => [...prev, data.message]);
    });

    setClient(ws);

    return () => ws.close();
  }, []);

  const sendMessage = (message: string) => {
    client?.broadcast('chat', { message });
  };

  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}>{msg}</div>
      ))}
      <button onClick={() => sendMessage('Hello!')}>
        Send
      </button>
    </div>
  );
}

Server Implementation

The WebSocket server is implemented in server/websocket.ts. It maintains:

  • Connection pool of all connected clients
  • Channel subscriptions for each client
  • Message routing between clients on the same channel

Environment Variables

WS_PORT=3001

Production Considerations

Scaling

For production deployments with multiple server instances, consider using Redis Pub/Sub to synchronize messages across WebSocket servers:

// Example pattern
import { createClient } from 'redis';

const redis = createClient({ url: process.env.REDIS_URL });
await redis.subscribe('channel', (message) => {
  // Broadcast to local WebSocket clients
});

Security

Add authentication to WebSocket connections:

ws.on('connection', (socket, request) => {
  const token = new URL(request.url!, 'ws://base').searchParams.get('token');
  // Verify token
});