Class: QuartzTorrent::IoFacade

Inherits:
Object
  • Object
show all
Defined in:
lib/quartz_torrent/reactor.rb

Overview

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.

Direct Known Subclasses

WriteOnlyIoFacade

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ioInfo, logger = nil) ⇒ IoFacade

Returns a new instance of IoFacade.



215
216
217
218
219
# File 'lib/quartz_torrent/reactor.rb', line 215

def initialize(ioInfo, logger = nil)
  @ioInfo = ioInfo
  @io = ioInfo.io
  @logger = logger
end

Instance Attribute Details

#loggerObject

Returns the value of attribute logger.



221
222
223
# File 'lib/quartz_torrent/reactor.rb', line 221

def logger
  @logger
end

Instance Method Details

#closeObject

Close the io.



295
296
297
# File 'lib/quartz_torrent/reactor.rb', line 295

def close
  @io.close
end

#closed?Boolean

Check if the io is closed.

Returns:

  • (Boolean)


300
301
302
# File 'lib/quartz_torrent/reactor.rb', line 300

def closed?
  @io.closed?
end

#flushObject

Flush data.



290
291
292
# File 'lib/quartz_torrent/reactor.rb', line 290

def flush
  @io.flush
end

#read(length) ⇒ Object

Read ‘length` bytes.



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# 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) ⇒ Object



304
305
306
307
# 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) ⇒ Object

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



225
226
227
# File 'lib/quartz_torrent/reactor.rb', line 225

def removeFromIOHash(hash)
  hash.delete @io
end

#seek(amount, whence) ⇒ Object

Seek on the io.

Parameters:

  • amount

    amount to seek.

  • whence

    one of the whence constants from IO::seek.



285
286
287
# File 'lib/quartz_torrent/reactor.rb', line 285

def seek(amount, whence)
  @io.seek amount, whence if @ioInfo.seekable?
end

#write(data) ⇒ Object

Write data to the IO.



272
273
274
275
276
277
278
279
280
# 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) ⇒ Object



309
310
311
312
# 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