#!/usr/bin/env ruby

require 'drb'

# This file includes an experimental gateway CGI implementation. It will work
# only on platforms which support both fork and sockets.
#
# To enable it edit public/.htaccess and replace dispatch.cgi with gateway.cgi.
#
# Next, create the directory log/drb_gateway and grant the apache user rw access
# to said directory.
#
# On the next request to your server, the gateway tracker should start up, along
# with a few listener processes. This setup should provide you with much better
# speeds than dispatch.cgi.
#
# Keep in mind that the first request made to the server will be slow, as the
# tracker and listeners will have to load. Also, the tracker and listeners will
# shutdown after a period if inactivity. You can set this value below -- the
# default is 90 seconds.

TrackerSocket = File.expand_path(File.join(File.dirname(__FILE__), '../log/drb_gateway/tracker.sock'))
DieAfter = 90 # Seconds
Listeners = 3

def message(s)
  $stderr.puts "gateway.cgi: #{s}" if ENV && ENV["DEBUG_GATEWAY"]
end

def listener_socket(number)
  File.expand_path(File.join(File.dirname(__FILE__), "../log/drb_gateway/listener_#{number}.sock"))
end

unless File.exist? TrackerSocket
  message "Starting tracker and #{Listeners} listeners"
  fork do
    Process.setsid
    STDIN.reopen "/dev/null"
    STDOUT.reopen "/dev/null", "a"

    root = File.expand_path(File.dirname(__FILE__) + '/..')

    message "starting tracker"
    fork do
      ARGV.clear
      ARGV << TrackerSocket << Listeners.to_s << DieAfter.to_s
      load File.join(root, 'script', 'tracker')
    end

    message "starting listeners"
    require File.join(root, 'config/environment.rb')
    Listeners.times do |number|
      fork do
        ARGV.clear
        ARGV << listener_socket(number) << DieAfter.to_s
        load File.join(root, 'script', 'listener')
      end
    end
  end

  message "waiting for tracker and listener to arise..."
  ready = false
  10.times do
    sleep 0.5
    break if (ready = File.exist?(TrackerSocket) && File.exist?(listener_socket(0)))
  end

  if ready
    message "tracker and listener are ready"
  else
    message "Waited 5 seconds, listener and tracker not ready... dropping request"
    Kernel.exit 1
  end
end

DRb.start_service

message "connecting to tracker"
tracker = DRbObject.new_with_uri("drbunix:#{TrackerSocket}")

input = $stdin.read
$stdin.close

env = ENV.inspect

output = nil
tracker.with_listener do |number|
  message "connecting to listener #{number}"
  socket = listener_socket(number)
  listener = DRbObject.new_with_uri("drbunix:#{socket}")
  output = listener.process(env, input)
  message "listener #{number} has finished, writing output"
end

$stdout.write output
$stdout.flush
$stdout.close