class Tubeclip::ChainIO

Stream wrapper that reads IOs in succession. Can be fed to Net::HTTP as post body stream. We use it internally to stream file content instead of reading whole video files into memory. Strings passed to the constructor will be wrapped in StringIOs. By default it will auto-close file handles when they have been read completely to prevent our uploader from leaking file handles

chain = ChainIO.new(File.open(__FILE__), File.open('/etc/passwd'), “abcd”)

Attributes

autoclose[RW]

Public Class Methods

new(*any_ios) click to toggle source
# File lib/tubeclip/chain_io.rb, line 12
def initialize(*any_ios)
  @autoclose = true
  @chain = any_ios.flatten.map{|e| e.respond_to?(:read)  ? e : StringIO.new(e.to_s) }
end

Public Instance Methods

expected_length() click to toggle source

Predict the length of all embedded IOs. Will automatically send file size.

# File lib/tubeclip/chain_io.rb, line 39
def expected_length
  @chain.inject(0) do | len, io |
    if io.respond_to?(:length)
      len + (io.length - io.pos)
    elsif io.is_a?(File)
      len + File.size(io.path) - io.pos
    else
      raise "Cannot predict length of #{io.inspect}"
    end
  end
end
read(buffer_size = 1024) click to toggle source
# File lib/tubeclip/chain_io.rb, line 17
def read(buffer_size = 1024)
  # Read off the first element in the stack
  current_io = @chain.shift
  return false if !current_io

  buf = current_io.read(buffer_size)
  if !buf && @chain.empty? # End of streams
    release_handle(current_io) if @autoclose
    false
  elsif !buf # This IO is depleted, but next one is available
    release_handle(current_io) if @autoclose
    read(buffer_size)
  elsif buf.length < buffer_size # This IO is depleted, but we were asked for more
    release_handle(current_io) if @autoclose
    buf + (read(buffer_size - buf.length) || '') # and recurse
  else # just return the buffer
    @chain.unshift(current_io) # put the current back
    buf
  end
end

Private Instance Methods

release_handle(io) click to toggle source
# File lib/tubeclip/chain_io.rb, line 52
def release_handle(io)
  io.close if io.respond_to?(:close)
end