123456789_123456789_123456789_123456789_123456789_

Class: EventMachine::FileStreamer

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, Deferrable
Inherits: Object
Defined in: lib/em/streamer.rb

Overview

Streams a file over a given connection. Streaming begins once the object is instantiated. Typically FileStreamer instances are not reused.

Streaming uses buffering for files larger than 16K and uses so-called fast file reader (a C++ extension) if available (it is part of eventmachine gem itself).

Examples:

module FileSender
  def post_init
    streamer = EventMachine::FileStreamer.new(self, '/tmp/bigfile.tar')
    streamer.callback{
      # file was sent successfully
      close_connection_after_writing
    }
  end
end

Author:

  • Francis Cianfrocca

Constant Summary

Deferrable - Included

Pool

Class Method Summary

Instance Method Summary

Deferrable - Included

#callback

Specify a block to be executed if and when the Deferrable object receives a status of :succeeded.

#cancel_callback

Cancels an outstanding callback to &block if any.

#cancel_errback

Cancels an outstanding errback to &block if any.

#cancel_timeout

Cancels an outstanding timeout if any.

#errback

Specify a block to be executed if and when the Deferrable object receives a status of :failed.

#fail

Sugar for set_deferred_status(:failed, ...).

#set_deferred_failure

Alias for Deferrable#fail.

#set_deferred_status

Sets the "disposition" (status) of the Deferrable object.

#set_deferred_success
#succeed

Sugar for set_deferred_status(:succeeded, ...).

#timeout

Setting a timeout on a Deferrable causes it to go into the failed state after the Timeout expires (passing no arguments to the object's errbacks).

Constructor Details

.new(connection, filename, args = {}) ⇒ FileStreamer

Parameters:

  • connection (EventMachine::Connection)
  • filename (String)

    File path

  • args (Hash) (defaults to: {})

    a customizable set of options

Options Hash (args):

  • :http_chunks (Boolean) — default: false

    Use HTTP 1.1 style chunked-encoding semantics.

[ GitHub ]

  
# File 'lib/em/streamer.rb', line 36

def initialize connection, filename, args = {}
  @connection = connection
  @http_chunks = args[:http_chunks]

  if File.exist?(filename)
    @size = File.size(filename)
    if @size <= MappingThreshold
      stream_without_mapping filename
    else
      stream_with_mapping filename
    end
  else
    fail "file not found"
  end
end

Instance Method Details

#ensure_mapping_extension_is_present (private)

This method is for internal use only.

We use an outboard extension class to get memory-mapped files. It's outboard to avoid polluting the core distro, but that means there's a "hidden" dependency on it. The first time we get here in any run, try to load up the dependency extension. User code will see a LoadError if it's not available, but code that doesn't require mapped files will work fine without it. This is a somewhat difficult compromise between usability and proper modularization.

[ GitHub ]

  
# File 'lib/em/streamer.rb', line 112

def ensure_mapping_extension_is_present
  @@fastfilereader ||= (require 'fastfilereaderext')
end

#stream_one_chunk

This method is for internal use only.

Used internally to stream one chunk at a time over multiple reactor ticks

[ GitHub ]

  
# File 'lib/em/streamer.rb', line 77

def stream_one_chunk
  loop {
    if @position < @size
      if @connection.get_outbound_data_size > BackpressureLevel
        EventMachine::next_tick {stream_one_chunk}
        break
      else
        len = @size - @position
        len = ChunkSize if (len > ChunkSize)

        @connection.send_data( "#{len.to_s(16)}\r\n" ) if @http_chunks
        @connection.send_data( @mapping.get_chunk( @position, len ))
        @connection.send_data("\r\n") if @http_chunks

        @position += len
      end
    else
      @connection.send_data "0\r\n\r\n" if @http_chunks
      @mapping.close
      succeed
      break
    end
  }
end

#stream_with_mapping(filename) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/em/streamer.rb', line 66

def stream_with_mapping filename
  ensure_mapping_extension_is_present

  @position = 0
  @mapping = EventMachine::FastFileReader::Mapper.new filename
  stream_one_chunk
end

#stream_without_mapping(filename) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/em/streamer.rb', line 53

def stream_without_mapping filename
  if @http_chunks
    @connection.send_data "#{@size.to_s(16)}\r\n"
    @connection.send_file_data filename
    @connection.send_data "\r\n0\r\n\r\n"
  else
    @connection.send_file_data filename
  end
  succeed
end