diff --git a/lib/puma.rb b/lib/puma.rb index 8e359bfa..88e8b18e 100644 --- a/lib/puma.rb +++ b/lib/puma.rb @@ -13,7 +13,6 @@ require 'puma/gems' require 'thread' # Ruby Puma -require 'puma/configurator' require 'puma/const' require 'puma/server' require 'puma/utils' diff --git a/lib/puma/cli.rb b/lib/puma/cli.rb index 4acee9bc..c6cf5ece 100644 --- a/lib/puma/cli.rb +++ b/lib/puma/cli.rb @@ -1,7 +1,7 @@ require 'optparse' require 'uri' -require 'puma/configurator' +require 'puma/server' require 'puma/const' module Puma @@ -9,13 +9,23 @@ module Puma DefaultTCPHost = "0.0.0.0" DefaultTCPPort = 3000 - def initialize(argv, stdout=STDOUT) + def initialize(argv, stdout=STDOUT, stderr=STDERR) @argv = argv @stdout = stdout + @stderr = stderr setup_options end + def log(str) + @stdout.puts str + end + + def error(str) + @stderr.puts "ERROR: #{str}" + exit 1 + end + def setup_options @options = { :concurrency => 16 @@ -36,7 +46,7 @@ module Puma @parser.banner = "puma " @parser.on_tail "-h", "--help", "Show help" do - @stdout.puts @parser + log @parser exit 1 end end @@ -64,10 +74,10 @@ module Puma server = Puma::Server.new @app, @options[:concurrency] - @stdout.puts "Puma #{Puma::Const::PUMA_VERSION} starting..." + log "Puma #{Puma::Const::PUMA_VERSION} starting..." if @options[:Host] - @stdout.puts "Listening on tcp://#{@options[:Host]}:#{@options[:Port]}" + log "Listening on tcp://#{@options[:Host]}:#{@options[:Port]}" server.add_tcp_listener @options[:Host], @options[:Port] end @@ -75,10 +85,10 @@ module Puma uri = URI.parse str case uri.scheme when "tcp" - @stdout.puts "Listening on #{str}" + log "Listening on #{str}" server.add_tcp_listener uri.host, uri.port when "unix" - @stdout.puts "Listening on #{str}" + log "Listening on #{str}" if uri.host path = "#{uri.host}/#{uri.path}" else @@ -87,12 +97,11 @@ module Puma server.add_unix_listener path else - @stdout.puts "Invalid URI: #{str}" - exit 1 + error "Invalid URI: #{str}" end end - @stdout.puts "Use Ctrl-C to stop" + log "Use Ctrl-C to stop" server.run.join end diff --git a/lib/puma/configurator.rb b/lib/puma/configurator.rb deleted file mode 100644 index 278d30c1..00000000 --- a/lib/puma/configurator.rb +++ /dev/null @@ -1,180 +0,0 @@ -require 'etc' - -require 'rubygems' -require 'rack/builder' - -require 'puma/server' - -module Puma - # Implements a simple DSL for configuring a Puma server for your - # purposes. - # - # It is used like this: - # - # require 'puma' - # config = Puma::Configurator.new :host => "127.0.0.1" do - # listener :port => 3000 do - # uri "/app", :handler => Puma::DirHandler.new(".", load_mime_map("mime.yaml")) - # end - # run - # end - # - # This will setup a simple DirHandler at the current directory and load additional - # mime types from mimy.yaml. The :host => "127.0.0.1" is actually not - # specific to the servers but just a hash of default parameters that all - # server or uri calls receive. - # - # When you are inside the block after Puma::Configurator.new you can simply - # call functions that are part of Configurator (like server, uri, daemonize, etc) - # without having to refer to anything else. You can also call these functions on - # the resulting object directly for additional configuration. - # - # A major thing about Configurator is that it actually lets you configure - # multiple listeners for any hosts and ports you want. These are kept in a - # map config.listeners so you can get to them. - # - # * :pid_file => Where to write the process ID. - class Configurator - attr_reader :listeners - attr_reader :defaults - - # You pass in initial defaults and then a block to continue configuring. - def initialize(defaults={}, &block) - @listener = nil - @listener_name = nil - @listeners = [] - @defaults = defaults - - if block - yield self - end - end - - # Change privileges of the process to specified user and group. - def change_privilege(user, group) - begin - uid, gid = Process.euid, Process.egid - target_uid = Etc.getpwnam(user).uid if user - target_gid = Etc.getgrnam(group).gid if group - - if uid != target_uid or gid != target_gid - log "Initiating groups for #{user.inspect}:#{group.inspect}." - Process.initgroups(user, target_gid) - - log "Changing group to #{group.inspect}." - Process::GID.change_privilege(target_gid) - - log "Changing user to #{user.inspect}." - Process::UID.change_privilege(target_uid) - end - rescue Errno::EPERM => e - log "Couldn't change user and group to #{user.inspect}:#{group.inspect}: #{e.to_s}." - log "Puma failed to start." - exit 1 - end - end - - # This will resolve the given options against the defaults. - # Normally just used internally. - def resolve_defaults(options) - options.merge(@defaults) - end - - # Starts a listener block. - # - # It expects the following options (or defaults): - # - # * :host => Host name to bind. - # * :port => Port to bind. - # - def listener(options={}) - raise "Cannot call listener inside another listener block." if (@listener or @listener_name) - ops = resolve_defaults(options) - - @listener = Puma::Server.new(ops[:host], ops[:port].to_i, ops[:concurrency].to_i) - @listener_name = "#{ops[:host]}:#{ops[:port]}" - @listeners << @listener - - if ops[:user] and ops[:group] - change_privilege(ops[:user], ops[:group]) - end - - yield self if block_given? - - # all done processing this listener setup, reset implicit variables - @listener = nil - @listener_name = nil - end - - def load_rackup(file) - app, options = Rack::Builder.parse_file file - - @listener.app = app - # Do something with options? - end - - # Works like a meta run method which goes through all the - # configured listeners. Use the Configurator.join method - # to prevent Ruby from exiting until each one is done. - def run - @listeners.each { |s| s.run } - end - - # Calls .stop on all the configured listeners so they - # stop processing requests (gracefully). By default it - # assumes that you don't want to restart. - def stop(synchronous=false) - @listeners.each do |s| - s.stop(synchronous) - end - end - - - # This method should actually be called *outside* of the - # Configurator block so that you can control it. In other words - # do it like: config.join. - def join - @listeners.each { |s| s.acceptor.join } - end - - # Used to allow you to let users specify their own configurations - # inside your Configurator setup. You pass it a script name and - # it reads it in and does an eval on the contents passing in the right - # binding so they can put their own Configurator statements. - def run_config(script) - open(script) {|f| eval(f.read, proc {self}.binding) } - end - - # Sets up the standard signal handlers that are used on most Ruby - # It only configures if the platform is not win32 and doesn't do - # a HUP signal since this is typically framework specific. - # - # This command is safely ignored if the platform is win32 (with a warning) - def setup_signals(options={}) - ops = resolve_defaults(options) - - # forced shutdown, even if previously restarted (actually just like TERM - # but for CTRL-C) - # - trap("INT") { log "INT signal received."; stop(false) } - - unless RbConfig::CONFIG['host_os'] =~ /mingw|mswin/ - # graceful shutdown - trap("TERM") { log "TERM signal received."; stop } - trap("USR1") { log "USR1 received, toggling $puma_debug_client to #{!$puma_debug_client}"; $puma_debug_client = !$puma_debug_client } - # restart - trap("USR2") { log "USR2 signal received."; stop(true) } - - log "Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart)." - else - log "Signals ready. INT => stop (no restart)." - end - end - - # Logs a simple message to STDERR (or the puma log if in daemon mode). - def log(msg) - STDERR.print "** ", msg, "\n" - end - - end -end diff --git a/lib/puma/server.rb b/lib/puma/server.rb index 0d972d00..0fcc4e81 100644 --- a/lib/puma/server.rb +++ b/lib/puma/server.rb @@ -1,3 +1,4 @@ +require 'rubygems' require 'rack' require 'stringio' @@ -320,7 +321,7 @@ module Puma def stop(sync=false) @notify << STOP_COMMAND - @acceptor.join if sync + @acceptor.join if @acceptor && sync end end end