Skip to main content

WebSocket URL

wss://exchange.jogeshwar.xyz/ws

Connection Management

Exchange Web uses a singleton WsManager class to manage WebSocket connections and handle real-time data streams.

Establishing Connection

import { WsManager } from './utils/ws_manager';

const wsManager = WsManager.getInstance();
The WebSocket connection is automatically established when you get the instance. The manager handles:
  • Automatic connection on initialization
  • Message buffering during connection setup
  • Reconnection logic
  • Callback management for different event types
Messages sent before the connection is fully established are automatically buffered and sent once the connection opens.

Connection Lifecycle

// The WsManager handles connection internally
private constructor() {
  this.ws = new WebSocket(BASE_URL);
  this.bufferedMessages = [];
  this.id = 1;
  this.init();
}

init() {
  this.ws.onopen = () => {
    this.initialized = true;
    // Flush buffered messages
    this.bufferedMessages.forEach((message) => {
      this.ws.send(JSON.stringify(message));
    });
    this.bufferedMessages = [];
  };

  this.ws.onmessage = (event) => {
    const message = JSON.parse(event.data);
    const type = message.data.e;
    // Route to registered callbacks
  };
}

Subscription Messages

Subscribe and unsubscribe to market data streams using the following message format.

Subscribe to Stream

wsManager.sendMessage({
  method: 'SUBSCRIBE',
  params: ['depth.SOL_USDC']
});
Message Format:
method
string
required
Must be SUBSCRIBE
params
string[]
required
Array of stream names to subscribe to. Format: {eventType}.{symbol}
id
number
Auto-generated message ID (handled by WsManager)
Available Streams:
  • depth.{SYMBOL} - Order book depth updates
  • trade.{SYMBOL} - Live trade executions

Unsubscribe from Stream

wsManager.sendMessage({
  method: 'UNSUBSCRIBE',
  params: ['depth.SOL_USDC']
});
{
  "method": "SUBSCRIBE",
  "params": ["depth.SOL_USDC", "trade.SOL_USDC"],
  "id": 1
}

Event Types

Depth Updates

Receive real-time order book updates when bids or asks change. Event Type: depth Registering Callback:
wsManager.registerCallback(
  'depth',
  (data) => {
    console.log('Updated Bids:', data.bids);
    console.log('Updated Asks:', data.asks);
  },
  'depth-callback-id'
);

// Subscribe to depth stream
wsManager.sendMessage({
  method: 'SUBSCRIBE',
  params: ['depth.SOL_USDC']
});
Callback Data Format:
bids
[string, string][]
Array of updated bid orders as [price, quantity] pairs
asks
[string, string][]
Array of updated ask orders as [price, quantity] pairs
Raw Message Format:
{
  "data": {
    "e": "depth",
    "b": [
      ["50000.00", "1.5"],
      ["49999.00", "2.0"]
    ],
    "a": [
      ["50001.00", "0.8"],
      ["50002.00", "1.2"]
    ]
  }
}
Implementation Details:
// From ws_manager.ts:40-44
if (type === "depth") {
  const updatedBids = message.data.b;
  const updatedAsks = message.data.a;
  callback({ bids: updatedBids, asks: updatedAsks });
}

Trade Updates

Receive notifications when new trades are executed on the exchange. Event Type: trade Registering Callback:
wsManager.registerCallback(
  'trade',
  (tradeData) => {
    console.log('New Trade:', tradeData);
  },
  'trade-callback-id'
);

// Subscribe to trade stream
wsManager.sendMessage({
  method: 'SUBSCRIBE',
  params: ['trade.SOL_USDC']
});
Callback Data Format: The callback receives the entire trade data object from the message.
e
string
Event type (always trade)
Additional fields
Trade execution details (price, quantity, timestamp, etc.)
Raw Message Format:
{
  "data": {
    "e": "trade",
    "id": 123456,
    "price": "50000.00",
    "quantity": "0.5",
    "timestamp": 1678901234567,
    "isBuyerMaker": true
  }
}
Implementation Details:
// From ws_manager.ts:46-49
if (type === "trade") {
  const trades = message.data;
  callback(trades);
}

Callback Management

Register Callback

Register a handler function for a specific event type.
await wsManager.registerCallback(
  eventType: string,
  callback: (data: any) => void,
  id: string
);
eventType
string
required
Event type to listen for (depth, trade, etc.)
callback
function
required
Function to call when event is received
id
string
required
Unique identifier for this callback registration
Example:
const callbackId = 'my-depth-handler';

await wsManager.registerCallback(
  'depth',
  (data) => {
    // Update UI with new order book data
    updateOrderBook(data.bids, data.asks);
  },
  callbackId
);

Deregister Callback

Remove a previously registered callback.
await wsManager.deRegisterCallback(
  eventType: string,
  id: string
);
eventType
string
required
Event type the callback was registered for
id
string
required
Unique identifier used during registration
Example:
// Clean up when component unmounts
await wsManager.deRegisterCallback('depth', 'my-depth-handler');

// Unsubscribe from the stream
wsManager.sendMessage({
  method: 'UNSUBSCRIBE',
  params: ['depth.SOL_USDC']
});

Complete Usage Example

Here’s a complete example showing WebSocket connection, subscription, and cleanup:
import { useEffect } from 'react';
import { WsManager } from './utils/ws_manager';

function TradingView({ market }: { market: string }) {
  useEffect(() => {
    const wsManager = WsManager.getInstance();
    const depthCallbackId = `depth-${market}`;
    const tradeCallbackId = `trade-${market}`;

    // Register depth updates
    wsManager.registerCallback(
      'depth',
      (data) => {
        console.log('Order book updated:', data);
        // Update your state/UI here
      },
      depthCallbackId
    );

    // Register trade updates
    wsManager.registerCallback(
      'trade',
      (data) => {
        console.log('New trade:', data);
        // Update your state/UI here
      },
      tradeCallbackId
    );

    // Subscribe to streams
    wsManager.sendMessage({
      method: 'SUBSCRIBE',
      params: [`depth.${market}`, `trade.${market}`]
    });

    // Cleanup on unmount
    return () => {
      wsManager.deRegisterCallback('depth', depthCallbackId);
      wsManager.deRegisterCallback('trade', tradeCallbackId);
      wsManager.sendMessage({
        method: 'UNSUBSCRIBE',
        params: [`depth.${market}`, `trade.${market}`]
      });
    };
  }, [market]);

  return <div>Trading View for {market}</div>;
}

Message Structure

All WebSocket messages follow this structure:

Outgoing Messages (Client → Server)

{
  method: 'SUBSCRIBE' | 'UNSUBSCRIBE',
  params: string[],
  id: number  // Auto-generated by WsManager
}

Incoming Messages (Server → Client)

{
  data: {
    e: string,  // Event type
    // ... event-specific fields
  }
}

Best Practices

Singleton Pattern: Always use WsManager.getInstance() to ensure a single WebSocket connection is shared across your application.
Unique Callback IDs: Use unique identifiers for callback registrations to avoid conflicts, especially when subscribing to the same event type multiple times.
Cleanup: Always deregister callbacks and unsubscribe from streams when components unmount or when subscriptions are no longer needed.
Error Handling: Implement error handling for WebSocket disconnections and reconnection logic if needed beyond the built-in buffering.

Implementation Reference

The WebSocket manager implementation can be found in: source/apps/web/src/utils/ws_manager.ts:1-84 Key features:
  • Singleton pattern for connection management
  • Automatic message buffering during connection
  • Callback routing based on event type
  • Support for multiple callbacks per event type

Build docs developers (and LLMs) love