Class: YouTubeIt::ChainIO

Inherits:
Object
  • Object
show all
Defined in:
lib/youtube_it/chain_io.rb

Overview

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”)

Direct Known Subclasses

GreedyChainIO

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (ChainIO) initialize(*any_ios)

Returns a new instance of ChainIO



12
13
14
15
# File 'lib/youtube_it/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

Instance Attribute Details

- (Object) autoclose

Returns the value of attribute autoclose



10
11
12
# File 'lib/youtube_it/chain_io.rb', line 10

def autoclose
  @autoclose
end

Instance Method Details

- (Object) expected_length

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



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/youtube_it/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

- (Object) read(buffer_size = 1024)



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/youtube_it/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