class Falcon::Controller::Virtual

A virtual host is an application bound to a specific authority (essentially a hostname). The virtual controller manages multiple hosts and allows a single server to host multiple applications easily.
Spawns instances of {Proxy} and {Redirect} to handle incoming requests.
A controller which mananages several virtual hosts.

def assume_privileges(path)

@parameter path [String] The path to the application directory.
Drop privileges according to the user and group of the specified path.
def assume_privileges(path)
	stat = File.stat(path)
	
	Process::GID.change_privilege(stat.gid)
	Process::UID.change_privilege(stat.uid)
	
	home = Etc.getpwuid(stat.uid).dir
	
	return {
		'HOME' => home,
	}
end

def falcon_path

@returns [String]
The path to the falcon executable from this gem.
def falcon_path
	File.expand_path("../../../bin/falcon", __dir__)
end

def initialize(command, **options)

@parameter command [Command::Virtual] The user-specified command-line options.
Initialize the virtual controller.
def initialize(command, **options)
	@command = command
	
	super(**options)
	
	trap(SIGHUP, &self.method(:reload))
end

def setup(container)

@parameter container [Async::Container::Generic]
These processes are gracefully restarted if they are already running.
Setup the container with {Redirect} and {Proxy} child processes.
def setup(container)
	if proxy = container[:proxy]
		proxy.kill(:HUP)
	end
	
	if redirect = container[:redirect]
		redirect.kill(:HUP)
	end
	
	container.reload do
		@command.resolved_paths do |path|
			path = File.expand_path(path)
			root = File.dirname(path)
			
			spawn(path, container, chdir: root)
		end
		
		container.spawn(name: "Falcon Redirector", restart: true, key: :redirect) do |instance|
			instance.exec(falcon_path, "redirect",
				"--bind", @command.bind_insecure,
				"--timeout", @command.timeout.to_s,
				"--redirect", @command.bind_secure,
				*@command.paths, ready: false
			)
		end
		
		container.spawn(name: "Falcon Proxy", restart: true, key: :proxy) do |instance|
			instance.exec(falcon_path, "proxy",
				"--bind", @command.bind_secure,
				"--timeout", @command.timeout.to_s,
				*@command.paths, ready: false
			)
		end
	end
end

def spawn(path, container, **options)

@parameter options [Options] The options which are passed to `exec`.
@parameter container [Async::Container::Generic] The container to spawn into.
@parameter path [String] The path to the application directory.
Spawn an application instance from the specified path.
def spawn(path, container, **options)
	container.spawn(name: "Falcon Application", restart: true, key: path) do |instance|
		env = assume_privileges(path)
		
		instance.exec(env,
			"bundle", "exec", "--keep-file-descriptors",
			path, ready: false, **options)
	end
end