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