View Source Hyperliquid.WebSocket.Manager (hyperliquid v0.4.1)
WebSocket connection and subscription manager.
Manages multiple WebSocket connections, routes subscriptions to appropriate connections, and provides a registry of active subscriptions.
Connection Strategy
All subscriptions share as few connections as possible within Hyperliquid's limits:
Shared socket (
"shared") — all:sharedand:dedicatedsubscriptions land here. The:dedicatedtype is legacy; modules may still declare it but the manager treats it identically to:shared.First user socket — when the first
:user_groupedsubscription is created, it is placed on the shared socket. No extra connection is opened.Per-user sockets (
"user:<address>") — each additional unique user gets its own connection so that message routing remains unambiguous (the connection itself is the routing tag; user addresses are not guaranteed in WS responses).
Because the shared socket carries mixed subscription types, the manager filters incoming messages by channel before dispatching to each subscription's callback.
Usage
# Subscribe to allMids (shared socket)
{:ok, sub_id} = Manager.subscribe(Hyperliquid.Api.Subscription.AllMids, %{})
# Subscribe to l2Book — also lands on the shared socket
{:ok, sub_id} = Manager.subscribe(Hyperliquid.Api.Subscription.L2Book, %{
coin: "BTC", nSigFigs: 5
})
# First user subscription — shares the existing shared socket
{:ok, sub_id} = Manager.subscribe(Hyperliquid.Api.Subscription.UserFills, %{
user: "0x1234..."
})
# Second user — gets its own socket
{:ok, sub_id} = Manager.subscribe(Hyperliquid.Api.Subscription.UserFills, %{
user: "0xabcd..."
})
# Unsubscribe
:ok = Manager.unsubscribe(sub_id)
# List active subscriptions
Manager.list_subscriptions()Architecture
The Manager uses a DynamicSupervisor to manage WebSocket connections. Each connection is a GenServer that handles the actual WebSocket communication. The Manager maintains:
- A registry of active subscriptions (ETS table)
- A mapping of connection keys to connection PIDs
- Connection metadata and per-subscription metrics
Summary
Functions
Returns a specification to start this module under a supervisor.
Get connection info for debugging.
Get metrics for a specific subscription.
Get subscription by ID.
Get metrics for all subscriptions.
List all active subscriptions.
List subscriptions for a specific user.
Start the WebSocket manager.
Subscribe to a WebSocket endpoint.
Unsubscribe from a WebSocket endpoint.
Types
@type connection_type() :: :shared | :dedicated | :user_grouped
@type subscription_id() :: String.t()
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec connection_info() :: map()
Get connection info for debugging.
@spec get_metrics(subscription_id()) :: {:ok, map()} | {:error, :not_found}
Get metrics for a specific subscription.
Parameters
subscription_id- The subscription ID
Returns
{:ok, metrics}- Subscription metrics{:error, :not_found}- Subscription not found
Metrics
:message_count- Total messages received:last_message_at- Timestamp of last message:subscribed_at- When subscription was created:messages_per_minute- Average messages per minute:uptime_seconds- Time since subscription started
@spec get_subscription(subscription_id()) :: {:ok, Hyperliquid.WebSocket.Manager.Subscription.t()} | {:error, :not_found}
Get subscription by ID.
@spec list_all_metrics() :: [map()]
Get metrics for all subscriptions.
@spec list_subscriptions() :: [Hyperliquid.WebSocket.Manager.Subscription.t()]
List all active subscriptions.
@spec list_user_subscriptions(String.t()) :: [ Hyperliquid.WebSocket.Manager.Subscription.t() ]
List subscriptions for a specific user.
Start the WebSocket manager.
@spec subscribe(module(), map(), function() | nil) :: {:ok, subscription_id()} | {:error, term()}
Subscribe to a WebSocket endpoint.
Parameters
module- The subscription endpoint moduleparams- Subscription parameterscallback- Function to call with incoming messages (optional)
Returns
{:ok, subscription_id}- Subscription created{:error, reason}- Failed to subscribe
@spec unsubscribe(subscription_id()) :: :ok | {:error, :not_found}
Unsubscribe from a WebSocket endpoint.
Parameters
subscription_id- The subscription ID returned from subscribe/3
Returns
:ok- Unsubscribed successfully{:error, :not_found}- Subscription not found