Class: ScalarRubyTest::Runtime::WebSocketRequest

Inherits:
Object
  • Object
show all
Defined in:
lib/amritk-scalar-test/runtime.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url:, headers: {}, send_descriptor: nil, receive_descriptor: nil, event_name_separator: nil, reconnect_options: nil, heartbeat_options: nil) ⇒ WebSocketRequest

Returns a new instance of WebSocketRequest.



181
182
183
184
185
186
187
188
189
# File 'lib/amritk-scalar-test/runtime.rb', line 181

def initialize(url:, headers: {}, send_descriptor: nil, receive_descriptor: nil, event_name_separator: nil, reconnect_options: nil, heartbeat_options: nil)
  @url = url
  @headers = headers
  @send_descriptor = send_descriptor
  @receive_descriptor = receive_descriptor
  @event_name_separator = event_name_separator
  @reconnect_options = reconnect_options
  @heartbeat_options = heartbeat_options
end

Instance Attribute Details

#event_name_separatorObject (readonly)

Returns the value of attribute event_name_separator.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def event_name_separator
  @event_name_separator
end

#headersObject (readonly)

Returns the value of attribute headers.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def headers
  @headers
end

#heartbeat_optionsObject (readonly)

Returns the value of attribute heartbeat_options.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def heartbeat_options
  @heartbeat_options
end

#receive_descriptorObject (readonly)

Returns the value of attribute receive_descriptor.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def receive_descriptor
  @receive_descriptor
end

#reconnect_optionsObject (readonly)

Returns the value of attribute reconnect_options.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def reconnect_options
  @reconnect_options
end

#send_descriptorObject (readonly)

Returns the value of attribute send_descriptor.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def send_descriptor
  @send_descriptor
end

#urlObject (readonly)

Returns the value of attribute url.



179
180
181
# File 'lib/amritk-scalar-test/runtime.rb', line 179

def url
  @url
end

Instance Method Details

#auth_headersObject



191
192
193
# File 'lib/amritk-scalar-test/runtime.rb', line 191

def auth_headers
  @headers.dup
end

#connectObject



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/amritk-scalar-test/runtime.rb', line 207

def connect
  uri = URI(@url)
  raise WebSocketMessageError, "only ws:// and wss:// URLs are supported by the stdlib connector" unless ["ws", "wss"].include?(uri.scheme)
  socket = TCPSocket.new(uri.host, uri.port || (uri.scheme == "wss" ? 443 : 80))
  if uri.scheme == "wss"
    context = OpenSSL::SSL::SSLContext.new
    socket = OpenSSL::SSL::SSLSocket.new(socket, context)
    socket.hostname = uri.host if socket.respond_to?(:hostname=)
    socket.sync_close = true
    socket.connect
  end
  key = SecureRandom.base64(16)
  path = uri.path.empty? ? "/" : uri.path
  path = "#{path}?#{uri.query}" if uri.query
  headers = { "Host" => uri.host, "Upgrade" => "websocket", "Connection" => "Upgrade", "Sec-WebSocket-Key" => key, "Sec-WebSocket-Version" => "13" }.merge(auth_headers)
  socket.write("GET #{path} HTTP/1.1\r\n")
  headers.each { |name, value| socket.write("#{name}: #{value}\r\n") }
  socket.write("\r\n")
  status = socket.gets
  raise WebSocketMessageError, "WebSocket upgrade failed: #{status}" unless status&.include?(" 101 ")
  WebSocketConnection.new(socket, self)
rescue StandardError
  socket&.close
  raise
end

#deserialize_receive(payload) ⇒ Object



241
242
243
244
245
246
# File 'lib/amritk-scalar-test/runtime.rb', line 241

def deserialize_receive(payload)
  parsed = parse_receive_payload(payload)
  Runtime.deserialize(parsed, @receive_descriptor)
rescue JSON::ParserError => e
  raise WebSocketMessageError, "failed to parse websocket payload: #{e.message}"
end

#normalize_event_name(name) ⇒ Object



248
249
250
251
# File 'lib/amritk-scalar-test/runtime.rb', line 248

def normalize_event_name(name)
  return name if name.nil? || @event_name_separator.nil? || @event_name_separator.empty?
  name.to_s.tr(@event_name_separator, ".")
end

#serialize_send(message) ⇒ Object



233
234
235
236
237
238
239
# File 'lib/amritk-scalar-test/runtime.rb', line 233

def serialize_send(message)
  payload = Runtime.serialize(message)
  return payload if payload.is_a?(String) && @send_descriptor.nil?
  JSON.generate(payload)
rescue JSON::GeneratorError => e
  raise WebSocketMessageError, "failed to serialize websocket payload: #{e.message}"
end

#with_headers(extra = {}) ⇒ Object



195
196
197
# File 'lib/amritk-scalar-test/runtime.rb', line 195

def with_headers(extra = {})
  self.class.new(url: @url, headers: @headers.merge(extra || {}), send_descriptor: @send_descriptor, receive_descriptor: @receive_descriptor, event_name_separator: @event_name_separator, reconnect_options: @reconnect_options, heartbeat_options: @heartbeat_options)
end

#with_heartbeat(interval:, message:) ⇒ Object



203
204
205
# File 'lib/amritk-scalar-test/runtime.rb', line 203

def with_heartbeat(interval:, message:)
  self.class.new(url: @url, headers: @headers, send_descriptor: @send_descriptor, receive_descriptor: @receive_descriptor, event_name_separator: @event_name_separator, reconnect_options: @reconnect_options, heartbeat_options: { interval: interval, message: message })
end

#with_reconnect(**options) ⇒ Object



199
200
201
# File 'lib/amritk-scalar-test/runtime.rb', line 199

def with_reconnect(**options)
  self.class.new(url: @url, headers: @headers, send_descriptor: @send_descriptor, receive_descriptor: @receive_descriptor, event_name_separator: @event_name_separator, reconnect_options: options, heartbeat_options: @heartbeat_options)
end