Class: Hyperliquid::WS::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperliquid/ws/client.rb

Overview

Managed WebSocket client for subscribing to real-time data channels

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(testnet: false, max_queue_size: Constants::WS_MAX_QUEUE_SIZE, reconnect: true, explorer_ws_url: nil) ⇒ Client

Returns a new instance of Client.



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/hyperliquid/ws/client.rb', line 12

def initialize(testnet: false, max_queue_size: Constants::WS_MAX_QUEUE_SIZE, reconnect: true,
               explorer_ws_url: nil)
  base_url = testnet ? Constants::TESTNET_API_URL : Constants::MAINNET_API_URL
  @url = base_url.sub(%r{^https?://}, 'wss://') + Constants::WS_ENDPOINT
  @max_queue_size = max_queue_size
  @reconnect_enabled = reconnect
  @mutex = Mutex.new

  init_main_ws_state
  init_explorer_ws_state(explorer_ws_url)
end

Instance Attribute Details

#dropped_message_countObject (readonly)

Returns the value of attribute dropped_message_count.



10
11
12
# File 'lib/hyperliquid/ws/client.rb', line 10

def dropped_message_count
  @dropped_message_count
end

#explorer_dropped_message_countObject (readonly)

Returns the value of attribute explorer_dropped_message_count.



10
11
12
# File 'lib/hyperliquid/ws/client.rb', line 10

def explorer_dropped_message_count
  @explorer_dropped_message_count
end

Instance Method Details

#closeObject



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/hyperliquid/ws/client.rb', line 145

def close
  @closing = true
  @connected = false
  @explorer_closing = true
  @explorer_connected = false

  @ping_thread&.kill
  @ping_thread = nil
  @explorer_ping_thread&.kill
  @explorer_ping_thread = nil

  @queue&.close if @queue.respond_to?(:close)
  @explorer_queue&.close if @explorer_queue.respond_to?(:close)

  @dispatch_thread&.join(5)
  @dispatch_thread = nil
  @explorer_dispatch_thread&.join(5)
  @explorer_dispatch_thread = nil

  @ws&.close
  @ws = nil
  @explorer_ws&.close
  @explorer_ws = nil
end

#connectObject



62
63
64
65
66
67
68
69
# File 'lib/hyperliquid/ws/client.rb', line 62

def connect
  @closing = false
  @reconnect_attempts = 0
  establish_connection
  start_dispatch_thread
  start_ping_thread
  self
end

#connected?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/hyperliquid/ws/client.rb', line 170

def connected?
  @connected
end

#explorer_connected?Boolean

Returns:

  • (Boolean)


174
175
176
# File 'lib/hyperliquid/ws/client.rb', line 174

def explorer_connected?
  @explorer_connected
end

#on(event, &callback) ⇒ Object



178
179
180
# File 'lib/hyperliquid/ws/client.rb', line 178

def on(event, &callback)
  @lifecycle_callbacks[event] = callback
end

#subscribe(subscription, &callback) ⇒ Object

Raises:

  • (ArgumentError)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/hyperliquid/ws/client.rb', line 71

def subscribe(subscription, &callback)
  raise ArgumentError, 'Block required for subscribe' unless block_given?

  identifier = subscription_identifier(subscription)
  sub_id = nil

  @mutex.synchronize do
    sub_id = @next_id
    @next_id += 1

    @subscriptions[identifier] ||= []
    @subscriptions[identifier] << { id: sub_id, callback: callback }
    @subscription_msgs[sub_id] = { subscription: subscription, identifier: identifier }
  end

  if @connected
    send_subscribe(subscription)
  else
    @mutex.synchronize { @pending_subscriptions << subscription }
    connect unless @ws
  end

  sub_id
end

#subscribe_explorer_blockObject

Raises:

  • (ArgumentError)


96
97
98
99
100
101
# File 'lib/hyperliquid/ws/client.rb', line 96

def subscribe_explorer_block(&)
  raise ArgumentError, 'Block required for subscribe_explorer_block' unless block_given?
  raise ConfigurationError, 'Explorer WebSocket URL not configured' unless @explorer_ws_url

  subscribe_explorer({ type: 'explorerBlock' }, 'explorerBlock', &)
end

#subscribe_explorer_txsObject

Raises:

  • (ArgumentError)


103
104
105
106
107
108
# File 'lib/hyperliquid/ws/client.rb', line 103

def subscribe_explorer_txs(&)
  raise ArgumentError, 'Block required for subscribe_explorer_txs' unless block_given?
  raise ConfigurationError, 'Explorer WebSocket URL not configured' unless @explorer_ws_url

  subscribe_explorer({ type: 'explorerTxs' }, 'explorerTxs', &)
end

#unsubscribe(subscription_id) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/hyperliquid/ws/client.rb', line 110

def unsubscribe(subscription_id)
  sub_msg = nil
  should_send = false
  explorer = false

  @mutex.synchronize do
    sub_msg = @subscription_msgs.delete(subscription_id)
    unless sub_msg
      sub_msg = @explorer_subscription_msgs.delete(subscription_id)
      explorer = true if sub_msg
    end
    return unless sub_msg

    identifier = sub_msg[:identifier]
    map = explorer ? @explorer_subscriptions : @subscriptions
    callbacks = map[identifier]
    return unless callbacks

    callbacks.reject! { |entry| entry[:id] == subscription_id }

    if callbacks.empty?
      map.delete(identifier)
      should_send = true
    end
  end

  return unless should_send

  if explorer
    send_explorer_unsubscribe(sub_msg[:subscription]) if @explorer_connected
  elsif @connected
    send_unsubscribe(sub_msg[:subscription])
  end
end