#!/usr/bin/env ruby
# An application preloader which doesn't actually preload anything
# and executes the requested start command.

DIR = File.expand_path(File.dirname(__FILE__))
require File.expand_path("#{DIR}/../../lib/phusion_passenger")
PhusionPassenger.locate_directories
PhusionPassenger.require_passenger_lib 'native_support'
require 'socket'

STDOUT.sync = true
STDERR.sync = true
puts "!> I have control 1.0"
abort "Invalid initialization header" if STDIN.readline != "You have control 1.0\n"

options = {}
while (line = STDIN.readline) != "\n"
  name, value = line.strip.split(/: */, 2)
  options[name] = value
end

socket_filename = "/tmp/placebo-preloader.sock.#{Process.pid}"
server = UNIXServer.new(socket_filename)
puts "!> Ready"
puts "!> socket: unix:#{socket_filename}"
puts "!> "

def process_client_command(server, client, command)
  if command == "spawn\n"
    options = {}
    while (line = client.readline) != "\n"
      name, value = line.strip.split(/: */, 2)
      options[name] = value
    end

    command = options["start_command"].split("\t")
    process_title = options["process_title"]
    process_title = command[0] if !process_title || process_title.empty?
    command[0] = [command[0], process_title]

    pid = fork do
      begin
        STDIN.reopen(client)
        STDOUT.reopen(client)
        STDOUT.sync = true
        server.close
        client.close
        puts "OK"
        puts Process.pid
        exec(*command)
      rescue Exception => e
        STDERR.puts "*** ERROR: #{e}\n#{e.backtrace.join("\n")}"
      ensure
        STDERR.flush
        exit!(1)
      end
    end
    Process.detach(pid)
  elsif command == "pid\n"
    client.write("#{Process.pid}\n")
  else
    client.write("unknown request\n")
  end
end

begin
  exit if ARGV[0] == "exit-immediately"
  while true
    ios = select([server, STDIN])[0]
    if ios.include?(server)
      client = server.accept
      begin
        process_client_command(server, client, client.readline)
      ensure
        client.close
      end
    end
    if ios.include?(STDIN)
      begin
        STDIN.readline
      rescue EOFError
        exit
      end
    end
  end
ensure
  File.unlink(socket_filename) rescue nil
end
