#!ruby # frozen_string_literal: true require_relative "../lib/right_speed/env" require_relative "../lib/right_speed/server" require "getoptlong" module RightSpeed module Command Options = Struct.new( :rackup, :port, :backlog, :workers, :worker_type, keyword_init: true, ) COMMAND_OPTIONS = [ ['--config', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--port', '-p', GetoptLong::REQUIRED_ARGUMENT], ['--backlog', GetoptLong::REQUIRED_ARGUMENT], ['--workers', GetoptLong::REQUIRED_ARGUMENT], ['--worker-type', GetoptLong::REQUIRED_ARGUMENT], ['--help', GetoptLong::NO_ARGUMENT], ] DEFAULT_RACKUP_PATH = 'config.ru' DEFAULT_PORT = Server::DEFAULT_PORT DEFAULT_WORKERS = Env.processors DEFAULT_WORKER_TYPE = Server::DEFAULT_WORKER_TYPE AVAILABLE_WORKER_TYPES = Server::AVAILABLE_WORKER_TYPES.map(&:to_s).join('/') def self.show_help(error: false, error_message: nil) STDERR.puts(error_message, "\n") if error_message STDERR.puts <<~EOS Usage: right_speed [options] OPTIONS --config, -c PATH The path of the rackup configuration file (default: #{DEFAULT_RACKUP_PATH}) --port, -p PORT The port number to listen (default: #{DEFAULT_PORT}) --backlog NUM The number of backlog --workers NUM The number of Ractors (default: CPU cores, #{DEFAULT_WORKERS}) --worker-type TYPE The type of workers (available: #{AVAILABLE_WORKER_TYPES}, default: #{DEFAULT_WORKER_TYPE}) --help Show this message EOS exit(error ? 1 : 0) end def self.integer_value(value, name) Integer(value) rescue show_help(error: true, error_message: "#{name} should be an Integer: #{value}") end def self.parse_command_line_options optparse = GetoptLong.new optparse.set_options(*COMMAND_OPTIONS) options = Options.new( rackup: DEFAULT_RACKUP_PATH, port: DEFAULT_PORT, backlog: nil, workers: DEFAULT_WORKERS, worker_type: DEFAULT_WORKER_TYPE, ) worker_type = :read optparse.each_option do |name, value| case name when '--config' options.rackup = value when '--port' options.port = integer_value(value, "Port number") when '--backlog' options.backlog = integer_value(value, "Backlog") when '--workers' options.workers = integer_value(value, "Workers") when '--worker-type' options.worker_type = value.to_sym when '--help' show_help else show_help(error: true, error_messsage: "Unknown option: #{name}") end end options end def self.start options = parse_command_line_options server = begin RightSpeed::Server.new( port: options.port, app: options.rackup, backlog: options.backlog, workers: options.workers, worker_type: options.worker_type, ) rescue => e show_help(error: true, error_message: "Failed to launch the server, " + e.message) end server.run end end end RightSpeed::Command.start