class Vox::Gateway::WebSocket
Websocket that handles data interchange for {Vox::Gateway::Client}.
Constants
- LOGGER
The logger used for output.
- ZLIB_SUFFIX
Zlib boundary used for separating messages split into multiple frames.
Attributes
Public Class Methods
# File lib/vox/gateway/websocket.rb, line 24 def initialize(url, port: nil, compression: true) @url = url @uri = URI.parse(url) @port = port || @uri.scheme == 'wss' ? 443 : 80 @inflate = Zlib::Inflate.new if compression end
Public Instance Methods
Close the websocket connection. @param reason [String] The reason for closing the websocket. @param code [Integer] The code to close the websocket with. @return [true, false] Whether the websocket closed successfully.
# File lib/vox/gateway/websocket.rb, line 99 def close(reason = nil, code = 1000) @driver.close(reason, code) end
Connect to the websocket server. @return [Thread] The thread handling the read loop.
# File lib/vox/gateway/websocket.rb, line 44 def connect # Flush the zlib buffer @inflate&.reset # Create a socket connection to the URL @socket = create_socket # Initialize the websocket driver setup_driver # Read until our websocket closes. @thread = Thread.new do read_loop end end
@!visibility private @return [nil]
# File lib/vox/gateway/websocket.rb, line 91 def read @driver.parse(@socket.readpartial(4096)) end
Send a `text` message. @param message [String] The `text` message to write to the websocket. @return [true, false] Whether the message was sent successfully.
# File lib/vox/gateway/websocket.rb, line 63 def send(message) LOGGER.debug { "[OUT] #{message} " } @driver.text(message) end
Send a `binary` frame. @param data [String] The binary data to write to the websocket. @return [true, false] Whether the data was send successfully.
# File lib/vox/gateway/websocket.rb, line 79 def send_binary(data) @driver.binary(data) end
Serialize a hash to send as a `text` message. @param hash [Hash] The hash to serialize and send as a `text` message. @return [true, false] Whether the message was sent successfully.
# File lib/vox/gateway/websocket.rb, line 71 def send_json(hash) data = MultiJson.dump(hash) send(data) end
@!visibility private @param data [String] The data to write to the socket.
# File lib/vox/gateway/websocket.rb, line 85 def write(data) @socket.write(data) end
Private Instance Methods
Create a socket, create an SSL socket instead for wss. @return [TCPSocket, SSLSocket]
# File lib/vox/gateway/websocket.rb, line 124 def create_socket if @uri.scheme == 'wss' create_ssl_socket.tap(&:connect) else TCPSocket.new(@uri.host, @port) end end
Create an SSL socket for WSS.
# File lib/vox/gateway/websocket.rb, line 133 def create_ssl_socket ctx = OpenSSL::SSL::SSLContext.new ctx.set_params ssl_version: :TLSv1_2 socket = TCPSocket.new(@uri.host, @port) OpenSSL::SSL::SSLSocket.new(socket, ctx) end
Handle close events.
# File lib/vox/gateway/websocket.rb, line 171 def on_close(event) LOGGER.debug { "WebSocket is closing (#{event.code}) #{event.reason}" } emit(:close, { code: event.code, reason: event.reason }) end
Handle parsed message events.
# File lib/vox/gateway/websocket.rb, line 155 def on_message(event) data = if @inflate packed = event.data.pack('c*') @inflate << packed return unless packed.end_with?(ZLIB_SUFFIX) @inflate.inflate('') else event.data end LOGGER.debug { "[IN] #{data[0].ord == 131 ? data.inspect : data}" } emit(:message, data) end
Handle open events.
# File lib/vox/gateway/websocket.rb, line 149 def on_open(_event) LOGGER.debug { 'Connection open' } emit(:open) end
Read from the socket until the websocket driver reports as closed.
# File lib/vox/gateway/websocket.rb, line 107 def read_loop read until @driver.state == :closed rescue SystemCallError => e LOGGER.error { "(#{e.class.name.split('::').last}) #{e.message}" } rescue EOFError => e LOGGER.error { 'EOF in websocket loop' } end
Register the base handlers.
# File lib/vox/gateway/websocket.rb, line 142 def register_handlers @driver.on(:open, &method(:on_open)) @driver.on(:message, &method(:on_message)) @driver.on(:close, &method(:on_close)) end
# File lib/vox/gateway/websocket.rb, line 115 def setup_driver @driver = ::WebSocket::Driver.client(self) register_handlers @driver.start end