diff --git a/twenty-cli/lib/twenty-cli/command/down.rb b/twenty-cli/lib/twenty-cli/command/down.rb index 0695593..33c992c 100644 --- a/twenty-cli/lib/twenty-cli/command/down.rb +++ b/twenty-cli/lib/twenty-cli/command/down.rb @@ -3,6 +3,7 @@ class Twenty::Command::Down < Twenty::Command set_banner usage: "twenty down [OPTIONS]", description: "Stop the twenty web server" + include Twenty::Path prepend Twenty::Command::SQLiteMixin def run @@ -13,6 +14,19 @@ class Twenty::Command::Down < Twenty::Command private def run_command(options) - warn "[twenty] down..." + if File.readable?(pidfile) + Process.kill('SIGINT', Integer(pid)) + else + warn "PID file is not readable." + end + rescue Errno::ESRCH + warn "No such process." + FileUtils.rm(pidfile) + end + + def pid + @pid ||= File + .binread(pidfile) + .gsub(/[^\d]/, '') end end diff --git a/twenty-cli/lib/twenty-cli/command/up.rb b/twenty-cli/lib/twenty-cli/command/up.rb index eb68498..1e7f259 100644 --- a/twenty-cli/lib/twenty-cli/command/up.rb +++ b/twenty-cli/lib/twenty-cli/command/up.rb @@ -12,6 +12,10 @@ class Twenty::Command::Up < Twenty::Command "Listen on PORT (default: 2020)", default: 2020, as: Integer + set_option "-b", + "--background", + "Run the web server in the background", + default: false include CommonOptionMixin prepend Twenty::Command::MigrationMixin @@ -26,7 +30,8 @@ class Twenty::Command::Up < Twenty::Command def run_command(options) server = Twenty::Servlet.server(options) - trap(:SIGINT) { server.shutdown } - server.start + options.background ? server.start! : server.start + rescue Interrupt + server.shutdown end end diff --git a/twenty-server/lib/twenty-server.rb b/twenty-server/lib/twenty-server.rb index f98016b..1527a7e 100644 --- a/twenty-server/lib/twenty-server.rb +++ b/twenty-server/lib/twenty-server.rb @@ -4,24 +4,19 @@ module Twenty require "fileutils" require "webrick" require "active_record" + require_relative "twenty-server/path" require_relative "twenty-server/graphql" require_relative "twenty-server/servlet" require_relative "twenty-server/migration" require_relative "twenty-server/model" extend FileUtils - - ## - # @return [String] - # Returns the directory where twenty stores data. - def self.data_dir - File.join(Dir.home, ".local", "share", "20") - end + extend Path ## # @return [String] # Returns the location of the default SQLite database. def self.default_database - @default_database ||= File.join(data_dir, "database.sqlite") + @default_database ||= File.join(datadir, "database.sqlite") end ## @@ -44,8 +39,8 @@ module Twenty # @return [void] # @api private def self.prepare_dir - return if File.exist?(default_database) - mkdir_p(data_dir) + mkdir_p(datadir) + mkdir_p(tmpdir) touch(default_database) rescue => ex warn "prepare_dir error: #{ex.message} (#{ex.class})" diff --git a/twenty-server/lib/twenty-server/path.rb b/twenty-server/lib/twenty-server/path.rb new file mode 100644 index 0000000..5dda964 --- /dev/null +++ b/twenty-server/lib/twenty-server/path.rb @@ -0,0 +1,23 @@ +module Twenty::Path + ## + # @return [String] + # Returns the directory where twenty stores persistent data. + def datadir + File.join(Dir.home, ".local", "share", "20") + end + + ## + # @return [String] + # Returns the directory where twenty stores temporary data. + def tmpdir + File.join(Dir.tmpdir, "20") + end + + ## + # @return [String] + # Returns the file where twenty can write the PID of + # a web server running in the background. + def pidfile + File.join(tmpdir, "server.pid") + end +end diff --git a/twenty-server/lib/twenty-server/servlet/mixin/server_mixin.rb b/twenty-server/lib/twenty-server/servlet/mixin/server_mixin.rb index 25683d0..8462056 100644 --- a/twenty-server/lib/twenty-server/servlet/mixin/server_mixin.rb +++ b/twenty-server/lib/twenty-server/servlet/mixin/server_mixin.rb @@ -1,6 +1,24 @@ # frozen_string_literal: true module Twenty::Servlet::ServerMixin + ## + # This module extends an instance of WEBrick::HTTPServer + # with daemon support. + module Daemon + include Twenty::Path + + ## + # Starts a webrick server in the background. + # @return [void] + def start! + Process.daemon + File.binwrite(pidfile, Process.pid.to_s) + start + ensure + FileUtils.rm(pidfile) + end + end + ## # @param [Hash] cli_options # CLI options merged into @@ -11,7 +29,7 @@ module Twenty::Servlet::ServerMixin def server(cli_options = {}) server = WEBrick::HTTPServer.new server_options(cli_options) server.mount "/graphql", Twenty::Servlet::GraphQL - server + server.extend(Daemon) end ##