class QuartzTorrent::IoFacade

This class provides a facade for an IO object. The read method on this object acts as a blocking read. Internally it reads nonblockingly and passes processing to other ready sockets if this socket would block.

Attributes

logger[RW]

Public Class Methods

new(ioInfo, logger = nil) click to toggle source
# File lib/quartz_torrent/reactor.rb, line 215
def initialize(ioInfo, logger = nil)
  @ioInfo = ioInfo
  @io = ioInfo.io
  @logger = logger
end

Public Instance Methods

close() click to toggle source

Close the io.

# File lib/quartz_torrent/reactor.rb, line 295
def close
  @io.close
end
closed?() click to toggle source

Check if the io is closed.

# File lib/quartz_torrent/reactor.rb, line 300
def closed?
  @io.closed?
end
flush() click to toggle source

Flush data.

# File lib/quartz_torrent/reactor.rb, line 290
def flush
  @io.flush
end
read(length) click to toggle source

Read ‘length` bytes.

# File lib/quartz_torrent/reactor.rb, line 230
def read(length)
  data = ''
  while data.length < length
    begin
      toRead = length-data.length
      rateLimited = false
      if @ioInfo.readRateLimit
        avail = @ioInfo.readRateLimit.avail.to_i
        if avail < toRead
          toRead = avail
          rateLimited = true
        end
        @ioInfo.readRateLimit.withdraw toRead
      end
      @logger.debug "IoFacade: must read: #{length} have read: #{data.length}. Reading #{toRead} bytes now" if @logger
      data << @io.read_nonblock(toRead) if toRead > 0
      # If we tried to read more than we are allowed to by rate limiting, yield.
      Fiber.yield if rateLimited
    rescue Errno::EWOULDBLOCK
      # Wait for more data.
      @logger.debug "IoFacade: read would block" if @logger
      Fiber.yield
    rescue Errno::EAGAIN, Errno::EINTR
      # Wait for more data.
      @logger.debug "IoFacade: read was interrupted" if @logger
      Fiber.yield
    rescue
      @logger.debug "IoFacade: read error: #{$!}" if @logger
      # Read failure occurred
      @ioInfo.lastReadError = $!
      if @ioInfo.useErrorhandler
        @ioInfo.state = :error
        Fiber.yield
      else
        raise $!
      end
    end
  end
  data
end
readRateLimit=(rate) click to toggle source
# File lib/quartz_torrent/reactor.rb, line 304
def readRateLimit=(rate)
  raise "The argument must be a RateLimit" if ! rate.nil? && ! rate.is_a?(RateLimit)
  @ioInfo.readRateLimit = rate
end
removeFromIOHash(hash) click to toggle source

Method needed for disposeIo to work without breaking encapsulation of WriteOnlyIoFacade.

# File lib/quartz_torrent/reactor.rb, line 225
def removeFromIOHash(hash)
  hash.delete @io
end
seek(amount, whence) click to toggle source

Seek on the io. @param amount amount to seek. @param whence one of the whence constants from IO::seek.

# File lib/quartz_torrent/reactor.rb, line 285
def seek(amount, whence)
  @io.seek amount, whence if @ioInfo.seekable?
end
write(data) click to toggle source

Write data to the IO.

# File lib/quartz_torrent/reactor.rb, line 272
def write(data)
  # Issue: what about write, read, read on files opened for read/write? Write should happen at offset X, but reads moved to offset N. Since writes
  # are buffered, write may happen after read which means write will happen at the wrong offset N. Can fix by always seeking (if needed) before writes to the
  # position where the write was queued, but this should only be done for files since other fds don't support seek. This is satisfactory for files opened
  # for write only since the file position will be where we expect so we won't need to seek. Same for read only.
  @ioInfo.outputBuffer.append data
  @logger.debug "wrote #{data.length} bytes to the output buffer of IO metainfo=#{@ioInfo.metainfo}" if @logger
  data.length
end
writeRateLimit=(rate) click to toggle source
# File lib/quartz_torrent/reactor.rb, line 309
def writeRateLimit=(rate)
  raise "The argument must be a RateLimit" if ! rate.nil? && !rate.is_a?(RateLimit)
  @ioInfo.writeRateLimit = rate
end