aboutsummaryrefslogblamecommitdiffstats
path: root/railties/bin/listener
blob: 493ac9dca4446431082fdbef0a9dee56d14139b0 (plain) (tree)
1
2
3
4
5



                                                            
                  























































































                                                                             



                                                                              





                      
require "drb"
ENV["RAILS_ENV"] = 'production'
require "#{File.dirname(__FILE__)}/../config/environment.rb"
require 'fcgi_handler'
require 'rbconfig'

VERBOSE = false

class Listener
  include DRbUndumped
  attr_accessor :tracker
  
  def initialize(timeout = nil)
    @timeout = timeout
    @mutex = Mutex.new
    @active = false
    
    @handler = RailsFCGIHandler.new
    @handler.extend DRbUndumped
    @output = FakeOut.new
    $stdout = @output
  end
  
  def inform_up(tracker_uri)
    return unless tracker_uri
    tracker = DRbObject.new_with_uri(tracker_uri)
    tracker.register_listener self
    @tracker = tracker
  end
  def inform_down
    @tracker.remove_listener(self) if @tracker
  end

  def run(on_uri, tracker_uri)
    on_uri ||= "drbunix:"
    DRb.start_service(on_uri, self) # Start a server for us
    inform_up tracker_uri
    @handler.process!(self)
  end
  
  def die!
    inform_down
    Kernel.exit 0
  end 
  
  def process(input)
    $stderr.puts "listener: received request -- obtaining lock" if VERBOSE 
    @mutex.synchronize do
      @active = true
      
      $stderr.puts "listener: obtained -- swaping stdin" if VERBOSE
      $stdin = input
      cgi = CGI.new
      
      $stderr.puts "listener: yielding to FCGI handler..." if VERBOSE
      @cgi_block.call cgi
      $stderr.puts "listener: handler finished, releasing control" if VERBOSE
      
      return @output.read!
    end
  end
  
  def each_cgi(&block)
    @cgi_block = block
    loop do
      @timeout ? sleep(@timeout) : sleep
      die! unless @active
      @active = false
    end
  end
end

class FakeOut < Struct.new(:contents)
  def initialize
    super("")
  end
  def write(str)
    contents << str
  end
  def read!
    c = contents
    self.contents = ''
    return c
  end
end

if ARGV.shift == 'start-listeners'
  tracker = ARGV.shift
  number = (ARGV.shift || '1').to_i
  exit(0) if number.zero?
  
  if number > 1
    fork do
      exec(
        File.join(Config::CONFIG['bin_dir'], Config::CONFIG['RUBY_SO_NAME']), 
        __FILE__, 'start-listeners', tracker, (number - 1).to_s
      )
    end
  end
  
  l = Listener.new(90)
  l.run(nil, tracker)
end