class WsClient::Client
Constants
- FRAME_SIZE
- MS_2
Attributes
connect_options[R]
handshake[R]
message_queue[R]
url[R]
Public Class Methods
new()
click to toggle source
# File lib/ws_client.rb, line 22 def initialize @message_queue = ::Queue.new end
Public Instance Methods
close()
click to toggle source
# File lib/ws_client.rb, line 84 def close return if @closed write_data nil, :type => :close rescue nil ensure @closed = true @socket.close if @socket @tcp_socket.close if @tcp_socket @socket = nil @tcp_socket = nil end
closed?()
click to toggle source
# File lib/ws_client.rb, line 96 def closed? !open? end
connect(url = nil, options={})
click to toggle source
# File lib/ws_client.rb, line 26 def connect(url = nil, options={}) return if open? @connect_options = options @connect_url = @url = url || @connect_url || @url raise "No URL to connect to" if url.nil? uri = URI.parse url @socket = TCPSocket.new(uri.host, uri.port || (uri.scheme == 'wss' ? 443 : 80)) @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if ['https', 'wss'].include?(uri.scheme) ssl_context = options[:ssl_context] || begin ctx = OpenSSL::SSL::SSLContext.new ctx.ssl_version = options[:ssl_version] || 'SSLv23' ctx.verify_mode = options[:verify_mode] || OpenSSL::SSL::VERIFY_NONE #use VERIFY_PEER for verification cert_store = OpenSSL::X509::Store.new cert_store.set_default_paths ctx.cert_store = cert_store ctx end # Keep a handle to the TCPSocket, because the SSLSocket will not clean it up for us. @tcp_socket = @socket @socket = ::OpenSSL::SSL::SSLSocket.new(@tcp_socket, ssl_context) @socket.connect end @closed = false handshake rescue OpenSSL::SSL::SSLError, EOFError # Re-use the socket cleanup logic if we have a connect failure. close raise end
open?()
click to toggle source
# File lib/ws_client.rb, line 100 def open? @handshake && @handshake.finished? && !@closed end
reconnect()
click to toggle source
# File lib/ws_client.rb, line 64 def reconnect connect(nil) end
send_data_and_wait(data, timeout = MS_2, opt = { :type => :text })
click to toggle source
Returns all responses that have been accepted
# File lib/ws_client.rb, line 69 def send_data_and_wait(data, timeout = MS_2, opt = { :type => :text }) response_data = [] write_data(data, opt) pull_next_message_off_of_socket(@socket, timeout) if message_queue.length > 0 message_queue.length.times do response_data << message_queue.pop end end response_data end
Also aliased as: send_data
Private Instance Methods
pull_next_message_off_of_socket(socket, timeout = 10, last_frame = nil)
click to toggle source
# File lib/ws_client.rb, line 133 def pull_next_message_off_of_socket(socket, timeout = 10, last_frame = nil) read_sockets, _, _ = IO.select([socket], nil, nil, timeout) if read_sockets && read_sockets[0] frame = last_frame || ::WebSocket::Frame::Incoming::Client.new begin frame << socket.read_nonblock(FRAME_SIZE) if socket.respond_to?(:pending) frame << socket.read(socket.pending) while socket.pending > 0 end if msg = frame.next case msg.type when :ping send_data_and_wait(msg.data, 10, :type => :pong) else message_queue << msg end pull_next_message_off_of_socket(socket, MS_2) # 2ms penalty for new frames else pull_next_message_off_of_socket(socket, timeout, frame) end rescue IO::WaitReadable IO.select([socket]) retry rescue IO::WaitWritable IO.select(nil, [socket]) retry rescue => e close raise end end end
write_data(data, opt)
click to toggle source
# File lib/ws_client.rb, line 171 def write_data(data, opt) frame = ::WebSocket::Frame::Outgoing::Client.new(:data => data, :type => opt[:type], :version => @handshake.version) frame_str = frame.to_s loop do break if frame_str.empty? || @closed begin num_bytes_written = @socket.write_nonblock(frame_str) frame_str = frame_str[num_bytes_written..-1] rescue IO::WaitReadable IO.select([@socket]) # OpenSSL needs to read internally retry rescue IO::WaitWritable, Errno::EINTR IO.select(nil, [@socket]) retry rescue => e close raise end end end