websocket.ts
Overview
`websocket.ts` provides an abstract foundation for implementing resilient WebSocket clients. It defines the `WebsocketClient` abstract class, which manages WebSocket connection lifecycle, including automatic reconnection, heartbeat monitoring via ping/pong frames, and connection resets. The class is designed to be extended by concrete implementations that specify how to handle incoming messages and subscribe to data streams.
This file also exports interfaces to define subscription messages and configuration options, allowing flexible customization of client behavior. The primary goal is to provide a robust, reusable WebSocket client base that handles common networking concerns transparently, enabling subclasses to focus on application-specific processing.
Interfaces
Subscription
Represents a JSON-RPC 2.0 subscription message to be sent over the WebSocket.
Property | Type | Description |
|---|---|---|
jsonrpc | `'2.0'` | JSON-RPC protocol version (fixed) |
id | `string` | Unique identifier for the request |
method | `string` | The RPC method name |
params | `unknown` (optional) | Optional parameters for the method |
**Usage Example:**
const sub: Subscription = {
jsonrpc: '2.0',
id: '1',
method: 'subscribe',
params: { channel: 'orders' }
}
Args
Configuration parameters required when constructing a `WebsocketClient`.
Property | Type | Description |
|---|---|---|
apiKey | `string` (optional) | API key for authentication |
logger | `Logger` | Logger instance for logging |
Options
Optional parameters to fine-tune WebSocket client behavior.
Property | Type | Default | Description |
|---|---|---|---|
pingInterval | `number` | `10000` ms | Interval between sending ping frames to keep connection alive |
retryAttempts | `number` | `0` (infinite retries) | Maximum reconnection attempts before throwing error |
resetInterval | `number` | `30000` ms | Time interval after which the connection is reset |
Class: WebsocketClient
Abstract base class for a WebSocket client that manages connection lifecycle, retries, heartbeat, and message handling.
Properties
Name | Type | Description |
|---|---|---|
`socket` | `WebSocket` | The current WebSocket connection instance |
`url` | `string` | URL of the WebSocket server |
`pingTimeout` | `NodeJS.Timeout \ | undefined` |
`interval` | `NodeJS.Timeout \ | undefined` |
`resetTimeout` | `NodeJS.Timeout \ | undefined` |
`retryCount` | `number` | Number of reconnection attempts so far |
`logger` | `Logger` | Logger instance for debug and error messages |
`pingInterval` | `number` | Interval between ping frames |
`retryAttempts` | `number` | Max reconnection attempts |
`resetInterval` | `number` | Interval after which the connection is reset |
Constructor
constructor(url: string, args: Args, opts?: Options)
url: WebSocket server URL.
args: Object containing
loggerand optionalapiKey.opts: Optional configuration overrides for ping interval, retry attempts, and reset interval.
Initializes the WebSocket connection and sets configuration parameters.
Abstract Methods
Subclasses must implement these methods to provide custom connection logic.
onOpen(): void
Called once the WebSocket connection is opened and ready.
Use this method to send subscription messages or initialize client state.
onMessage(message: WebSocket.MessageEvent): Promise<void>
Handles incoming messages from the WebSocket.
message: The raw message event received.
Return a
Promiseto support asynchronous processing.
subscribeAddresses(addresses: string[]): void
Abstract method to subscribe to updates for a list of blockchain addresses or similar entities.
addresses: Array of strings representing target subscription addresses.
Protected Methods
initialize(): void
Sets up event handlers for the WebSocket connection:
Responds to
pingwithpong.Handles
pongto reset heartbeat timeout.Logs and handles errors and connection closure.
Handles incoming messages by calling
onMessage.On open, resets retry count, starts ping interval, triggers heartbeat, calls
onOpen, and schedules connection reset.
Called internally when a new WebSocket connection is created.
reset(): void
Schedules a connection reset after `resetInterval` milliseconds by terminating the socket, which triggers a reconnect.
If `resetInterval` is 0, disables automatic reset.
Private Methods
close(): void
Handles connection closure and reconnection logic:
Clears ping intervals.
Increments retry count and throws error if max retries exceeded (unless 0 for infinite).
Attempts to reconnect after a randomized exponential backoff delay capped by
MAX_DELAY.
heartbeat(): void
Sets a timeout waiting for a `pong` response to the last ping. If the timeout fires, it terminates the socket connection indicating a failed heartbeat.
Implementation Details
Exponential Backoff with Jitter: Reconnection delay uses
BASE_DELAY * retryCount^2with randomness to avoid thundering herd reconnections.Heartbeat via ping/pong: Maintains connection liveness and detects dead peers.
Automatic Reset: Periodic forced connection reset to avoid stale connections.
Zero retryAttempts means infinite retries.
Uses
wspackage for WebSocket client functionality.Uses
@shapeshiftoss/loggerfor structured logging.
Interaction with Other System Components
This file is a foundational utility used by modules requiring WebSocket connectivity.
The
Loggerinstance is injected, allowing consistent logging across the system.Concrete subclasses implement protocol-specific message handling and subscription logic, integrating with business logic layers.
WebSocket server URLs and API keys are passed from configuration or environment.
This class handles network robustness, allowing upper layers to focus on domain-specific processing.
Usage Example (Subclass Skeleton)
import { WebsocketClient, Args } from './websocket'
class MyWebsocketClient extends WebsocketClient {
protected onOpen(): void {
this.logger.info('Connection established')
this.subscribeAddresses(['addr1', 'addr2'])
}
protected async onMessage(message: WebSocket.MessageEvent): Promise<void> {
const data = JSON.parse(message.data.toString())
this.logger.debug({ data }, 'Received message')
// process data here
}
subscribeAddresses(addresses: string[]): void {
const subscription = {
jsonrpc: '2.0',
id: '1',
method: 'subscribe',
params: { addresses }
}
this.socket.send(JSON.stringify(subscription))
}
}
const client = new MyWebsocketClient('wss://example.com/ws', { logger })
client.initialize()
Mermaid Class Diagram
classDiagram
class WebsocketClient {
-socket: WebSocket
-url: string
-pingTimeout: NodeJS.Timeout
-interval: NodeJS.Timeout
-resetTimeout: NodeJS.Timeout
-retryCount: number
-logger: Logger
-pingInterval: number
-retryAttempts: number
-resetInterval: number
+constructor(url: string, args: Args, opts?: Options)
+initialize(): void
+reset(): void
#onOpen(): void
#onMessage(message: WebSocket.MessageEvent): Promise~void~
+subscribeAddresses(addresses: string[]): void
-close(): void
-heartbeat(): void
}
This documentation covers the design and usage of `websocket.ts`, enabling developers to extend or utilize `WebsocketClient` for robust WebSocket communication in their applications.