Skip to main content

Overview

The WsManager class is a singleton that manages WebSocket connections to the Exchange Web backend. It handles message buffering, callback registration, and real-time data streaming for market depth and trades.

Base URL

const BASE_URL = "wss://exchange.jogeshwar.xyz/ws";

Class: WsManager

Static Methods

getInstance()

Returns the singleton instance of WsManager. Creates a new instance if one doesn’t exist.
public static getInstance(): WsManager
return
WsManager
The singleton WsManager instance

Instance Methods

init()

Initializes the WebSocket connection and sets up event handlers. Called automatically by the constructor.
init(): void

Connection Behavior

  • On Open: Flushes all buffered messages to the WebSocket
  • On Message: Parses incoming messages and invokes registered callbacks based on message type

Supported Message Types

depth
object
Order book depth updates
  • bids (array): Updated bid orders [[price, quantity], …]
  • asks (array): Updated ask orders [[price, quantity], …]
trade
object
Trade execution data
  • Contains trade information from the message data

sendMessage()

Sends a message to the WebSocket server. Automatically buffers messages if connection is not yet established.
sendMessage(message: any): void
message
object
required
Message object to send. The method automatically adds a unique id field.
If the WebSocket connection is not initialized, messages are buffered and sent when the connection opens.

Example Message

wsManager.sendMessage({
  method: "SUBSCRIBE",
  params: ["depth.SOL_USDCT"],
});

registerCallback()

Registers a callback function for a specific message type.
async registerCallback(
  type: string,
  callback: any,
  id: string
): Promise<void>
type
string
required
Message type to listen for (e.g., “depth”, “trade”, “ticker”)
callback
function
required
Callback function to invoke when messages of this type are received
id
string
required
Unique identifier for this callback registration (used for deregistration)

Callback Signatures

(data: { bids: [string, string][], asks: [string, string][] }) => void

deRegisterCallback()

Removes a previously registered callback.
async deRegisterCallback(type: string, id: string): Promise<void>
type
string
required
Message type the callback was registered for
id
string
required
Unique identifier of the callback to remove

Usage Example

Basic Setup

import { WsManager } from "@/utils/ws_manager";

// Get singleton instance
const wsManager = WsManager.getInstance();

// Subscribe to depth updates
wsManager.sendMessage({
  method: "SUBSCRIBE",
  params: ["depth.SOL_USDCT"],
});

// Register callback for depth updates
await wsManager.registerCallback(
  "depth",
  (data) => {
    console.log("Bids:", data.bids);
    console.log("Asks:", data.asks);
  },
  "depth-handler-1"
);

React Integration

import { useEffect } from "react";
import { WsManager } from "@/utils/ws_manager";

function MarketDepth({ market }) {
  useEffect(() => {
    const wsManager = WsManager.getInstance();
    const callbackId = `depth-${market}`;

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

    // Register callback
    wsManager.registerCallback(
      "depth",
      (data) => {
        // Update state with depth data
        setBids(data.bids);
        setAsks(data.asks);
      },
      callbackId
    );

    // Cleanup
    return () => {
      wsManager.deRegisterCallback("depth", callbackId);
      wsManager.sendMessage({
        method: "UNSUBSCRIBE",
        params: [`depth.${market}`],
      });
    };
  }, [market]);

  return <div>{/* Render depth data */}</div>;
}

Multiple Callbacks

const wsManager = WsManager.getInstance();

// Register multiple callbacks for the same type
await wsManager.registerCallback(
  "trade",
  (trade) => {
    updateTradeHistory(trade);
  },
  "trade-history"
);

await wsManager.registerCallback(
  "trade",
  (trade) => {
    updateLastPrice(trade.price);
  },
  "last-price"
);

// Both callbacks will be invoked for each trade message

Message Buffering

The WsManager automatically buffers messages sent before the WebSocket connection is established:
const wsManager = WsManager.getInstance();

// These messages are buffered if connection isn't ready
wsManager.sendMessage({ method: "SUBSCRIBE", params: ["depth.SOL_USDCT"] });
wsManager.sendMessage({ method: "SUBSCRIBE", params: ["trade.SOL_USDCT"] });

// All buffered messages are sent when connection opens

Architecture Notes

The WsManager uses the singleton pattern to ensure only one WebSocket connection exists across the application. This prevents duplicate connections and ensures efficient resource usage.
Callbacks are stored in a dictionary keyed by message type. Multiple callbacks can be registered for the same type, and all will be invoked when messages of that type are received.

Source Location

apps/web/src/utils/ws_manager.ts

Build docs developers (and LLMs) love