Add packages/ruby/server.rb as a git submodule
This commit is contained in:
parent
d71267970f
commit
337a2460e3
22 changed files with 81 additions and 386 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +1,6 @@
|
|||
[submodule "submodules/surah-name-glyphs"]
|
||||
path = submodules/surah-name-glyphs
|
||||
url = https://github.com/ReflectsLight/surah-name-glyphs
|
||||
[submodule "packages/ruby/server.rb"]
|
||||
path = packages/ruby/server.rb
|
||||
url = https://github.com/0x1eef/server.rb
|
||||
|
|
1
packages/ruby/server.rb
Submodule
1
packages/ruby/server.rb
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit bf94e6f20c1f48ec002611912a53e0bf746f076f
|
8
packages/ruby/server/.gitignore
vendored
8
packages/ruby/server/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
build/
|
||||
tmp/
|
||||
node_modules/
|
||||
.bundle/
|
||||
*.log
|
||||
*.sh
|
||||
*.core
|
||||
Gemfile.lock
|
|
@ -1,40 +0,0 @@
|
|||
##
|
||||
# Plugins
|
||||
require:
|
||||
- standard
|
||||
|
||||
##
|
||||
# Defaults: standard-rb
|
||||
inherit_gem:
|
||||
standard: config/base.yml
|
||||
|
||||
##
|
||||
# All cops
|
||||
AllCops:
|
||||
TargetRubyVersion: 3.2
|
||||
Include:
|
||||
- lib/*.rb
|
||||
- lib/**/*.rb
|
||||
- test/*_test.rb
|
||||
|
||||
##
|
||||
# Enabled
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: true
|
||||
|
||||
##
|
||||
# Disabled
|
||||
Layout/ArgumentAlignment:
|
||||
Enabled: false
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Enabled: false
|
||||
Layout/EmptyLineBetweenDefs:
|
||||
Enabled: false
|
||||
Style/TrivialAccessors:
|
||||
Enabled: false
|
||||
Lint/NestedMethodDefinition:
|
||||
Exclude:
|
||||
- test/server_dir_test.rb
|
||||
Style/SingleLineMethods:
|
||||
Exclude:
|
||||
- test/server_dir_test.rb
|
|
@ -1,4 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
gemspec
|
77
packages/ruby/server/Gemfile.lock
Normal file
77
packages/ruby/server/Gemfile.lock
Normal file
|
@ -0,0 +1,77 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
server.rb (0.1.0)
|
||||
json (= 2.6.1)
|
||||
puma (~> 6.3)
|
||||
racc (= 1.6.0)
|
||||
rack (~> 3.0)
|
||||
set (= 1.0.2)
|
||||
stringio (= 3.0.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
ast (2.4.2)
|
||||
json (2.6.1)
|
||||
language_server-protocol (3.17.0.3)
|
||||
lint_roller (1.0.0)
|
||||
nio4r (2.5.9)
|
||||
parallel (1.23.0)
|
||||
parser (3.2.2.3)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
power_assert (2.0.3)
|
||||
puma (6.3.0)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.6.0)
|
||||
rack (3.0.8)
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rainbow (3.1.1)
|
||||
regexp_parser (2.8.1)
|
||||
rexml (3.2.5)
|
||||
rubocop (1.52.1)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.2.2.3)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.28.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.29.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-performance (1.18.0)
|
||||
rubocop (>= 1.7.0, < 2.0)
|
||||
rubocop-ast (>= 0.4.0)
|
||||
ruby-progressbar (1.13.0)
|
||||
set (1.0.2)
|
||||
standard (1.29.0)
|
||||
language_server-protocol (~> 3.17.0.2)
|
||||
lint_roller (~> 1.0)
|
||||
rubocop (~> 1.52.0)
|
||||
standard-custom (~> 1.0.0)
|
||||
standard-performance (~> 1.1.0)
|
||||
standard-custom (1.0.1)
|
||||
lint_roller (~> 1.0)
|
||||
standard-performance (1.1.0)
|
||||
lint_roller (~> 1.0)
|
||||
rubocop-performance (~> 1.18.0)
|
||||
stringio (3.0.1)
|
||||
test-unit (3.6.1)
|
||||
power_assert
|
||||
unicode-display_width (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-openbsd
|
||||
|
||||
DEPENDENCIES
|
||||
rack-test (~> 2.1)
|
||||
server.rb!
|
||||
standard (~> 1.24)
|
||||
test-unit (~> 3.5)
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.26
|
|
@ -1,15 +0,0 @@
|
|||
Copyright (C) 2023 by 0x1eef <0x1eef@protonmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this
|
||||
software for any purpose with or without fee is hereby
|
||||
granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
|
||||
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
||||
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
OF THIS SOFTWARE.
|
|
@ -1,40 +0,0 @@
|
|||
## About
|
||||
|
||||
server.rb implements a static file web server
|
||||
by using the fast performing Ruby web server
|
||||
[Puma](https://github.com/puma/puma)
|
||||
and a small
|
||||
[Rack](https://github.com/rack/rack)
|
||||
application.
|
||||
|
||||
## Examples
|
||||
|
||||
### Server.for_dir
|
||||
|
||||
The `Server.for_dir` method returns a Server instance
|
||||
that serves the contents of a directory. `Server#start` spawns
|
||||
a new thread to listen for requests, and afterwards returns
|
||||
the thread. `Thread#join` can block execution at that point,
|
||||
or execution can continue as normal by not calling `Thread#join`:
|
||||
|
||||
```ruby
|
||||
require "server"
|
||||
|
||||
##
|
||||
# Create a Server instance for the contents of a directory
|
||||
server = Server.for_dir("./build/website/")
|
||||
|
||||
##
|
||||
# Start listening for connections
|
||||
thr = server.start
|
||||
|
||||
##
|
||||
# Prevent the main thread from exiting
|
||||
thr.join
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[BSD Zero Clause](https://choosealicense.com/licenses/0bsd/).
|
||||
<br>
|
||||
See [LICENSE](./LICENSE).
|
|
@ -1,52 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Server
|
||||
require "rack"
|
||||
require_relative "server/puma"
|
||||
require_relative "server/gzip"
|
||||
require_relative "server/etag"
|
||||
require_relative "server/dir"
|
||||
|
||||
def self.app(path)
|
||||
Rack::Builder.app do
|
||||
use Server::ETag
|
||||
run Server::Dir.new(path)
|
||||
end
|
||||
end
|
||||
|
||||
def self.for_dir(path, options = {})
|
||||
host = options.delete(:host) || "127.0.0.1"
|
||||
port = options.delete(:port) || 7777
|
||||
unix = options.delete(:unix) || false
|
||||
new app(path), options.merge!(
|
||||
binds: [unix ? "unix://#{unix}" : "tcp://#{host}:#{port}"]
|
||||
)
|
||||
end
|
||||
|
||||
def initialize(app, options = {})
|
||||
@app = app
|
||||
@options = default_options.merge!(options)
|
||||
@events = Puma::Events.new
|
||||
@server = Puma::Server.new(@app, @events, @options)
|
||||
end
|
||||
|
||||
def start(block: false)
|
||||
@server.binder.parse(@options[:binds])
|
||||
thr = @server.run
|
||||
block ? thr.join : thr
|
||||
end
|
||||
|
||||
def stop
|
||||
@server.stop
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_options
|
||||
{
|
||||
min_threads: 1,
|
||||
max_threads: 5,
|
||||
workers: 1
|
||||
}
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# A rack application that serves the contents
|
||||
# of a directory over HTTP.
|
||||
class Server::Dir
|
||||
prepend Server::Gzip
|
||||
|
||||
def initialize(root)
|
||||
@root = File.realpath(root)
|
||||
@mime_types = {".ttf" => "font/ttf"}.freeze
|
||||
end
|
||||
|
||||
def call(env)
|
||||
finish Rack::Request.new(env)
|
||||
rescue Errno::EPERM, Errno::EACCES
|
||||
body = "Permission denied"
|
||||
[403, {"content-length" => body.bytesize, "content-type" => "text/plain"}, [body]]
|
||||
rescue Errno::ENOENT
|
||||
body = "The requested URL was not found"
|
||||
[404, {"content-length" => body.bytesize, "content-type" => "text/plain"}, [body]]
|
||||
rescue => ex
|
||||
body = "Internal server error (#{ex.class})"
|
||||
[500, {"content-length" => body.bytesize, "content-type" => "text/plain"}, [body]]
|
||||
end
|
||||
|
||||
def finish(request)
|
||||
path = find_path(request)
|
||||
body = File.binread(path)
|
||||
extn = File.extname(path)
|
||||
[
|
||||
200,
|
||||
{"content-type" => mime_types[extn] || Rack::Mime.mime_type(extn),
|
||||
"content-length" => body.bytesize},
|
||||
body.each_line.to_a
|
||||
]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :root, :mime_types
|
||||
|
||||
def find_path(request)
|
||||
path = File.join root, File.expand_path(request.path)
|
||||
File.directory?(path) ? File.join(path, "index.html") : path
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Server::ETag < Rack::ETag
|
||||
ETAGS = {}
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = super(env)
|
||||
if headers["etag"] && headers["etag"] == env["HTTP_IF_NONE_MATCH"]
|
||||
[304, headers, [""]]
|
||||
else
|
||||
[status, headers, body]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
##
|
||||
# A mixin module that serves a compressed version of
|
||||
# a file when the file is found to exist on disk,
|
||||
# and has a ".gz" file extension.
|
||||
module Server::Gzip
|
||||
def finish(request)
|
||||
path = gzip_path(request)
|
||||
if path
|
||||
body = File.binread(path)
|
||||
extn = File.extname(path[0..-4])
|
||||
[
|
||||
200,
|
||||
{"content-type" => mime_types[extn] || Rack::Mime.mime_type(extn),
|
||||
"content-encoding" => "gzip",
|
||||
"content-length" => body.bytesize},
|
||||
body.each_line
|
||||
]
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def gzip_path(request)
|
||||
return unless request.get_header("accept-encoding")
|
||||
&.include?("gzip")
|
||||
path = "#{find_path(request)}.gz"
|
||||
File.exist?(path) ? path : nil
|
||||
end
|
||||
end
|
|
@ -1,8 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "puma"
|
||||
require "puma/events"
|
||||
|
||||
class Puma::Server
|
||||
public :binder
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = "server.rb"
|
||||
gem.authors = ["0x1eef"]
|
||||
gem.email = ["0x1eef@protonmail.com"]
|
||||
gem.homepage = "https://github.com/0x1eef/server.rb#readme"
|
||||
gem.version = "0.1.0"
|
||||
gem.licenses = ["0BSD"]
|
||||
gem.files = Dir["lib/*", "lib/**/*.rb"]
|
||||
gem.require_paths = ["lib"]
|
||||
gem.summary = "A static file web server"
|
||||
gem.description = gem.summary
|
||||
|
||||
gem.add_runtime_dependency "puma", "~> 6.3"
|
||||
gem.add_runtime_dependency "rack", "~> 3.0"
|
||||
gem.add_development_dependency "standard", "~> 1.24"
|
||||
gem.add_development_dependency "rack-test", "~> 2.1"
|
||||
gem.add_development_dependency "test-unit", "~> 3.5"
|
||||
end
|
|
@ -1,87 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "setup"
|
||||
require "rack/test"
|
||||
|
||||
class ServerDirTest < Test::Unit::TestCase
|
||||
include Rack::Test::Methods
|
||||
|
||||
def test_index
|
||||
get "/"
|
||||
assert_equal 200, last_response.status
|
||||
assert_equal "text/html", last_response.content_type
|
||||
assert_equal bytesize("./test/webroot/index.html"), last_response.content_length
|
||||
end
|
||||
|
||||
def test_ttf_font
|
||||
get "/fonts/roboto-mono-regular.ttf"
|
||||
assert_equal 200, last_response.status
|
||||
assert_equal "font/ttf", last_response.content_type
|
||||
assert_equal bytesize("./test/webroot/fonts/roboto-mono-regular.ttf"),
|
||||
last_response.content_length
|
||||
end
|
||||
|
||||
def test_js_file
|
||||
get "/js/index.js"
|
||||
assert_equal 200, last_response.status
|
||||
assert_equal "application/javascript", last_response.content_type
|
||||
assert_equal bytesize("./test/webroot/js/index.js"),
|
||||
last_response.content_length
|
||||
end
|
||||
|
||||
def test_png_file
|
||||
get "/images/0x1eef.png"
|
||||
assert_equal 200, last_response.status
|
||||
assert_equal "image/png", last_response.content_type
|
||||
assert_equal bytesize("./test/webroot/images/0x1eef.png"),
|
||||
last_response.content_length
|
||||
end
|
||||
|
||||
def test_json_file
|
||||
get "/json/1.json"
|
||||
assert_equal 200, last_response.status
|
||||
assert_equal "application/json", last_response.content_type
|
||||
assert_equal bytesize("./test/webroot/json/1.json"),
|
||||
last_response.content_length
|
||||
end
|
||||
|
||||
def test_internal_server_error
|
||||
def app.finish(request) raise "test" end
|
||||
get "/"
|
||||
assert_equal 500, last_response.status
|
||||
assert_equal "text/plain", last_response.content_type
|
||||
assert_equal "Internal server error (RuntimeError)".bytesize,
|
||||
last_response.content_length
|
||||
assert_equal "Internal server error (RuntimeError)",
|
||||
last_response.body
|
||||
end
|
||||
|
||||
def test_permission_denied
|
||||
File.chmod 0, "./test/webroot/permission_denied.html"
|
||||
get "/permission_denied.html"
|
||||
assert_equal 403, last_response.status
|
||||
assert_equal "text/plain", last_response.content_type
|
||||
assert_equal "Permission denied".bytesize, last_response.content_length
|
||||
assert_equal "Permission denied", last_response.body
|
||||
ensure
|
||||
File.chmod 0o440, "./test/webroot/permission_denied.html"
|
||||
end
|
||||
|
||||
def test_page_not_found
|
||||
get "/foobarbaz"
|
||||
assert_equal 404, last_response.status
|
||||
assert_equal "text/plain", last_response.content_type
|
||||
assert_equal "The requested URL was not found".bytesize, last_response.content_length
|
||||
assert_equal "The requested URL was not found", last_response.body
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def app
|
||||
@app ||= Server.app("./test/webroot/")
|
||||
end
|
||||
|
||||
def bytesize(path)
|
||||
File.binread(path).bytesize
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
require "bundler/setup"
|
||||
require "test/unit"
|
||||
require "server"
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB |
|
@ -1,8 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>/index.html</title>
|
||||
</head>
|
||||
<body>
|
||||
<b>/index.html</b>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +0,0 @@
|
|||
(function() {
|
||||
console.log("Hello world");
|
||||
})();
|
|
@ -1 +0,0 @@
|
|||
[{"id":"1","place_of_revelation":"makkah","transliterated_name":"Al-Fatihah","translated_name":"The Opener","verse_count":7,"slug":"al-fatihah","codepoints":[1575,1604,1601,1575,1578,1581,1577]},[1,"بِسْمِ اللَّهِ الرَّحْمَـٰنِ الرَّحِيمِ"],[2,"الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ"],[3,"الرَّحْمَـٰنِ الرَّحِيمِ"],[4,"مَالِكِ يَوْمِ الدِّينِ"],[5,"إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ"],[6,"اهْدِنَا الصِّرَاطَ الْمُسْتَقِيمَ"],[7,"صِرَاطَ الَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ الْمَغْضُوبِ عَلَيْهِمْ وَلَا الضَّالِّينَ"]]
|
Loading…
Reference in a new issue