class NIO::WebSocket::RawAdapter

Attributes

closing[R]
inner[R]
monitor[R]
options[R]

Public Class Methods

new(io, options) click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 4
def initialize(io, options)
  @inner = io
  @options = options
  @buffer = ""
  @mutex = Mutex.new
end

Public Instance Methods

add_to_reactor() click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 26
def add_to_reactor
  @monitor = Reactor.selector.register(inner, :rw) # This can block if this is the main thread and the reactor is busy
  monitor.value = proc do
    begin
      read if monitor.readable?
      pump_buffer if monitor.writable?
    rescue Errno::ECONNRESET, EOFError, Errno::ECONNABORTED
      teardown
      WebSocket.logger.info "#{inner} socket closed"
    rescue IO::WaitReadable # rubocop:disable Lint/HandleExceptions
    rescue IO::WaitWritable
      monitor.interests = :rw
    end
    if @closing
      if !monitor.readable? && @buffer.empty?
        teardown
        WebSocket.logger.info "#{inner} closed"
      else
        monitor.interests = :rw unless monitor.closed? # keep the :w interest so that our block runs each time
        # edge case: if monitor was readable this time, and the write buffer is empty, if we emptied the read buffer this time our block wouldn't run again
      end
    end
  end
end
close() click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 17
def close
  return false if @closing

  @closing = true
  monitor.interests = :rw
  Reactor.selector.wakeup
  true
end
pump_buffer() click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 69
def pump_buffer
  @mutex.synchronize do
    written = 0
    begin
      written = inner.write_nonblock @buffer unless @buffer.empty?
      WebSocket.logger.debug { "Pumped #{written} bytes of data from buffer to #{inner}:\n#{@buffer}" } unless @buffer.empty? || !WebSocket.log_traffic?
      @buffer = @buffer.byteslice(written..-1) if written > 0
      WebSocket.logger.debug { "The buffer is now:\n#{@buffer}" } unless @buffer.empty? || !WebSocket.log_traffic?
    rescue IO::WaitWritable, IO::WaitReadable
      return written
    ensure
      monitor.interests = @buffer.empty? ? :r : :rw
    end
    written
  end
end
read() { |data| ... } click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 51
def read
  data = inner.read_nonblock(16384)
  if data
    WebSocket.logger.debug { "Incoming data on #{inner}:\n#{data}" } if WebSocket.log_traffic?
    yield data if block_given?
  end
  data
end
teardown() click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 12
def teardown
  monitor.close
  inner.close
end
write(data) click to toggle source
# File lib/nio/websocket/raw_adapter.rb, line 60
def write(data)
  @mutex.synchronize do
    @buffer << data
  end
  return unless monitor
  pump_buffer
  Reactor.selector.wakeup unless monitor.interests == :r
end