Replace webrick with rack + puma

This commit is contained in:
0x1eef 2024-03-27 18:18:58 -03:00
parent 1eab5c121b
commit 689b650a75
12 changed files with 75 additions and 89 deletions

View file

@ -8,13 +8,14 @@ within your local network. It is both easy to use, and easy to install.
* Provides a command-line utility to start / stop a web server.
* Connect / disconnect a project from the command line.
* Works offline. Binds to `http://localhost:2020` by default.
* Minimal: Ruby, and SQLite3 are the primary runtime dependencies.
* Designed to work offline. Binds to `http://localhost:2020` by default.
* Lightweight stack with Ruby and SQLite3 being the primary runtime dependencies.
* Easy to install, easy to use.
* Optional: nginx support via an unix socket.
## Design
* The server is powered by [ruby/webrick](https://github.com/ruby/webrick):
* The server is powered by [rack](https://github.com/rack/rack) and [puma](https://github.com/puma/puma):
- Accepts GraphQL requests at `/graphql`.
- Serves client (HTML, JS, CSS).
- Dependencies: ActiveRecord, SQLite3, ruby-graphql.

View file

@ -3,3 +3,4 @@ require "bundler/setup"
load "twenty-client/tasks/nanoc.rake"
load "rake/tasks/gem.rake"
load "rake/tasks/rubocop.rake"
load "rake/tasks/server.rake"

11
rake/tasks/server.rake Normal file
View file

@ -0,0 +1,11 @@
desc "Run server"
task :server, [:protocol] do |_, args|
require 'rbconfig'
cli = [RbConfig.ruby, "-rbundler/setup", "twenty-cli/bin/twenty", "up"]
h = args.to_h
if h[:protocol] == "unix"
Process.wait spawn(*cli, "--unix", "/tmp/twenty.freebsd.local")
else
Process.wait spawn(*cli)
end
end

View file

@ -12,12 +12,12 @@ class Twenty::Command::Up < Twenty::Command
"A port to listen on (default: 2020)",
default: 2020,
as: Integer
set_option "-f",
"--fork",
"Run the web server in the background",
default: false
set_option "-u PATH",
"--unix PATH",
"Listen on a UNIX socket"
include CommonOptionMixin
include Twenty::Path
prepend Twenty::Command::MigrationMixin
prepend Twenty::Command::SQLiteMixin
prepend Twenty::Command::RescueMixin
@ -30,9 +30,12 @@ class Twenty::Command::Up < Twenty::Command
private
def run_command(options)
server = Twenty::Servlet.server(options)
options.fork ? server.start! : server.start
File.binwrite(pidfile, Process.pid.to_s)
thr = Twenty::Rack.server(options).start
thr.join
rescue Interrupt
server.shutdown
thr.kill
ensure
FileUtils.rm(pidfile)
end
end

View file

@ -2,11 +2,10 @@
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/rack"
require_relative "twenty-server/migration"
require_relative "twenty-server/model"
extend FileUtils

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Twenty::Rack
require "server"
require_relative "rack/graphql"
##
# @param [Hash] options
# A hash of server options.
#
# @return [Thread]
def self.server(options = {})
Server.dir(Twenty.build, options.to_h)
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
module Twenty::Rack
module GraphQL
##
# Extends {Server::Dir Server::Dir} (a static file
# Rack application) with a /graphql endpoint.
#
# @param [Hash] env
# Environment hash.
#
# @return [Array<Integer, Hash, #each>]
# Returns a response.
def call(env)
req = Rack::Request.new(env)
if req.post? &&
req.path == "/graphql"
params = JSON.parse(req.body.string)
result = Twenty::GraphQL::Schema.execute(
params["query"],
variables: params["variables"],
context: {}
)
[200, {"content-type" => "application/json"}, [result.to_json]]
else
super(env)
end
end
Server::Dir.prepend(self)
end
end

View file

@ -1,12 +0,0 @@
# frozen_string_literal: true
class Twenty::Servlet < WEBrick::HTTPServlet::AbstractServlet
##
# servlets
require_relative "servlet/graphql"
##
# mixins
require_relative "servlet/mixin/server_mixin"
extend ServerMixin
end

View file

@ -1,17 +0,0 @@
# frozen_string_literal: true
class Twenty::Servlet::GraphQL < Twenty::Servlet
##
# POST /servlet/graphql/
def do_POST(req, res)
params = JSON.parse(req.body)
result = Twenty::GraphQL::Schema.execute(
params["query"],
variables: params["variables"],
context: {}
)
res["content_type"] = "application/json"
res.status = 200
res.body = result.to_json
end
end

View file

@ -1,46 +0,0 @@
# 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
# {ServerMixin#server_options ServerMixin#server_options}.
#
# @return [WEBrick::HTTPServer]
# Returns an instance of WEBrick::HTTPServer.
def server(cli_options = {})
server = WEBrick::HTTPServer.new server_options(cli_options)
server.mount "/graphql", Twenty::Servlet::GraphQL
server.extend(Daemon)
end
##
# @return [Hash<Symbol, String>]
# The default server options given to WEBrick::HTTPServer.new.
def server_options(cli_options)
{
DocumentRoot: Twenty.build,
BindAddress: cli_options.bind,
Port: cli_options.port,
Logger: WEBrick::Log.new(File::NULL)
}
end
end

View file

@ -17,8 +17,8 @@ Gem::Specification.new do |gem|
gem.description = gem.summary
gem.add_runtime_dependency "activerecord", "~> 7.1"
gem.add_runtime_dependency "sqlite3", "~> 1.6"
gem.add_runtime_dependency "webrick", "~> 1.8"
gem.add_runtime_dependency "graphql", "~> 2.2"
gem.add_runtime_dependency "server.rb", "~> 0.1"
gem.add_development_dependency "test-unit", "~> 3.5.7"
gem.add_development_dependency "standard", "~> 1.35"
end

View file

@ -17,8 +17,8 @@ Gem::Specification.new do |gem|
gem.description = gem.summary
gem.add_runtime_dependency "activerecord", "~> 7.1"
gem.add_runtime_dependency "sqlite3", "~> 1.6"
gem.add_runtime_dependency "webrick", "~> 1.8"
gem.add_runtime_dependency "graphql", "~> 2.2"
gem.add_runtime_dependency "server.rb", "~> 0.1"
gem.add_development_dependency "test-unit", "~> 3.5.7"
gem.add_development_dependency "standard", "~> 1.35"
end