opal-up 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +51 -0
- data/bin/up +29 -0
- data/bin/up_bun +23 -0
- data/example_rack_app/Gemfile +3 -0
- data/example_rack_app/config.ru +6 -0
- data/example_rack_app/rack_app.rb +5 -0
- data/example_roda_app/Gemfile +6 -0
- data/example_roda_app/config.ru +6 -0
- data/example_roda_app/roda_app.rb +35 -0
- data/example_sinatra_app/Gemfile +6 -0
- data/example_sinatra_app/config.ru +6 -0
- data/example_sinatra_app/sinatra_app.rb +7 -0
- data/lib/up/bun.rb +91 -0
- data/lib/up/bun_cli.rb +32 -0
- data/lib/up/bun_rack.rb +19 -0
- data/lib/up/bun_rack_env.rb +102 -0
- data/lib/up/rack_builder_patch.rb +17 -0
- data/lib/up/u_web_socket.rb +83 -0
- data/lib/up/u_web_socket_cluster.rb +89 -0
- data/lib/up/uws_cli.rb +32 -0
- data/lib/up/uws_rack.rb +19 -0
- data/lib/up/uws_rack_env.rb +99 -0
- data/lib/up/version.rb +3 -0
- data/lib/up-bun.rb +7 -0
- data/lib/up-node.rb +7 -0
- data/opal-up.gemspec +27 -0
- data/up_logo.svg +256 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: fd1f3da03559ae97160438ac56cab04162d985d069f73fdbb228e18a83f21757
|
4
|
+
data.tar.gz: 880e5c28a44a8aba0d160c07994d4ca69b5b15051e0fd9948e7aa5b0696a9b82
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '0491776446d5623ebe8ccacde009d9e448778bff5c5803ebfa4f30ea70b0178454fe5d9b39ba8f9e8d0e54be20a607a81e854f758c64aea5dc9cc4d7ae495821'
|
7
|
+
data.tar.gz: 25659ca070cc81c078599f2281f2f52c4862f10ebadf284257d9c420380319d98708b77233cd6fb684b064d931c58e50bc893aaedf763f2c5c42d35b81392f51
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Jan Biedermann
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
<img src="https://raw.githubusercontent.com/janbiedermann/up/master/up_logo.svg" alt="UP Logo">
|
2
|
+
<small>Original Image by <a href="https://www.freepik.com/free-vector/colorful-arrows_715199.htm#query=up&position=3&from_view=search&track=sph&uuid=63f9eddf-02a6-4e5c-8178-8cfa507ee33d">Freepik</a>, modified though</small>
|
3
|
+
|
4
|
+
# UP
|
5
|
+
|
6
|
+
A high performance Rack server for Opal Ruby, Tech Demo
|
7
|
+
|
8
|
+
## Let Numbers speak first
|
9
|
+
|
10
|
+
```
|
11
|
+
Requests per second:
|
12
|
+
Puma: 6391.01 req/s
|
13
|
+
Iodine: 18645.58 req/s
|
14
|
+
Up!: 20258.46 req/s <<< fastest
|
15
|
+
|
16
|
+
Time per Request, mean, across all concurrent requests:
|
17
|
+
Puma: 0.156ms
|
18
|
+
Iodine: 0.054ms
|
19
|
+
Up!: 0.049ms <<< fastest
|
20
|
+
```
|
21
|
+
running on linux with:
|
22
|
+
ruby 3.3.0, YJit enabled
|
23
|
+
Opal 1.8.2 with node v2011.0
|
24
|
+
Puma 6.4.2, 4 workers, 4 threads
|
25
|
+
Iodine 0.7.57, 4 workers, 4 threads
|
26
|
+
Up! 0.0.1, 1 worker, no threads
|
27
|
+
|
28
|
+
running the example_rack_app from this repo, benchmarked with:
|
29
|
+
`ab -n 100000 -c 10 http://localhost:3000/`
|
30
|
+
|
31
|
+
## Introduction
|
32
|
+
|
33
|
+
This is currently mainly a technical demonstration, demonstrating the speed of the Opal Ruby implementation employing Node and UWebSocketJs as runtime. Its not yet a generic, all purpose Reck server, but good for further experimentation, research and open for improvement.
|
34
|
+
|
35
|
+
## Getting started
|
36
|
+
|
37
|
+
To start experimenting:
|
38
|
+
- clone this repo
|
39
|
+
- cd into it, bundle install
|
40
|
+
- cd example_rack_app
|
41
|
+
- bundle install
|
42
|
+
- bundle exec up
|
43
|
+
|
44
|
+
You may want to change the `gem 'up'` line in the Gemfile to use up from rubygems, if you want to run your app outside of the cloned repo.
|
45
|
+
|
46
|
+
## Roda, Sinatra, others ...
|
47
|
+
|
48
|
+
... currently do not work! Just basic Rack apps with a few dependencies.
|
49
|
+
|
50
|
+
Example apps for Roda and Sinatra are provided, for convenience of developing and expanding the capabilities of Opal.
|
51
|
+
|
data/bin/up
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if RUBY_ENGINE == 'opal'
|
4
|
+
require 'up-node'
|
5
|
+
Up::CLI.call
|
6
|
+
else
|
7
|
+
# check for commands
|
8
|
+
node_cmd = `which node`
|
9
|
+
npm_cmd = `which npm`
|
10
|
+
raise "Please install node first!" if !node_cmd || node_cmd.empty?
|
11
|
+
raise "Please install npm first!" if !npm_cmd || npm_cmd.empty?
|
12
|
+
node_cmd.chop! if node_cmd.end_with?("\n")
|
13
|
+
npm_cmd.chop! if npm_cmd.end_with?("\n")
|
14
|
+
got_uws = `npm list|grep uWebSockets.js@20`
|
15
|
+
`npm i uNetworking/uWebSockets.js#v20.41.0` if got_uws.empty?
|
16
|
+
lib_dir = File.expand_path("#{__dir__}/../lib")
|
17
|
+
|
18
|
+
# Opal does not yet support gems, so lets read the Gemfile and simply add each gem
|
19
|
+
# to the Opal load path and require it, works for some gems, fails for others
|
20
|
+
gems = ""
|
21
|
+
if File.exist?("Gemfile")
|
22
|
+
lines = File.readlines('Gemfile')
|
23
|
+
lines.each do |line|
|
24
|
+
m = /gem ['"](\w+)['"]/.match(line)
|
25
|
+
gems << " -g #{m[1]} -r #{m[1]}" if m && m[1] != 'up'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Kernel.exec("opal -Rnodejs -E -I. -I#{lib_dir} -g rack #{gems} #{__FILE__}")
|
29
|
+
end
|
data/bin/up_bun
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if RUBY_ENGINE == 'opal'
|
4
|
+
require 'up-bun'
|
5
|
+
Up::CLI.call
|
6
|
+
else
|
7
|
+
# check for commands
|
8
|
+
bun_cmd = `which bun`
|
9
|
+
raise "Please install bun first!" if !bun_cmd || bun_cmd.empty?
|
10
|
+
bun_cmd.chop! if bun_cmd.end_with?("\n")
|
11
|
+
lib_dir = File.expand_path("#{__dir__}/../lib")
|
12
|
+
# Opal does not yet support gems, so lets read the Gemfile and simply add each gem
|
13
|
+
# to the Opal load path and require it, works for some gems, fails for others
|
14
|
+
gems = ""
|
15
|
+
if File.exist?("Gemfile")
|
16
|
+
lines = File.readlines('Gemfile')
|
17
|
+
lines.each do |line|
|
18
|
+
m = /gem ['"](\w+)['"]/.match(line)
|
19
|
+
gems << " -g #{m[1]} -r #{m[1]}" if m && m[1] != 'up'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
Kernel.exec("opal -Rbun -E -I. -I#{lib_dir} -g rack #{gems} #{__FILE__}")
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "roda"
|
2
|
+
|
3
|
+
class RodaApp < Roda
|
4
|
+
route do |r|
|
5
|
+
# GET / request
|
6
|
+
r.root do
|
7
|
+
r.redirect "/hello"
|
8
|
+
end
|
9
|
+
|
10
|
+
# /hello branch
|
11
|
+
r.on "hello" do
|
12
|
+
# Set variable for all routes in /hello branch
|
13
|
+
@greeting = 'Hello'
|
14
|
+
|
15
|
+
# GET /hello/world request
|
16
|
+
r.get "world" do
|
17
|
+
"#{@greeting} world!"
|
18
|
+
end
|
19
|
+
|
20
|
+
# /hello request
|
21
|
+
r.is do
|
22
|
+
# GET /hello request
|
23
|
+
r.get do
|
24
|
+
"#{@greeting}!"
|
25
|
+
end
|
26
|
+
|
27
|
+
# POST /hello request
|
28
|
+
r.post do
|
29
|
+
puts "Someone said #{@greeting}!"
|
30
|
+
r.redirect
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/up/bun.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# backtick_javascript: true
|
2
|
+
|
3
|
+
require 'up/bun_rack_env'
|
4
|
+
|
5
|
+
module Up
|
6
|
+
module Bun
|
7
|
+
def self.listen(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil)
|
8
|
+
port = port&.to_i
|
9
|
+
scheme ||= 'http'
|
10
|
+
host ||= 'localhost'
|
11
|
+
port ||= 3000
|
12
|
+
config = { handler: self.name, engine: "bun/#{`process.version`}", port: port, scheme: scheme, host: host }
|
13
|
+
%x{
|
14
|
+
if (scheme !== 'http' && scheme !== 'https') {
|
15
|
+
#{raise "unsupported scheme #{scheme}"}
|
16
|
+
}
|
17
|
+
|
18
|
+
var server_options = {
|
19
|
+
port: port,
|
20
|
+
hostname: host,
|
21
|
+
development: false,
|
22
|
+
fetch(req) {
|
23
|
+
const rack_res = app.$call(Opal.Up.BunRackEnv.$new(req, config));
|
24
|
+
const hdr = new Headers();
|
25
|
+
const headers = rack_res[1];
|
26
|
+
if (headers.$$is_hash) {
|
27
|
+
var header, k, v;
|
28
|
+
for(header of headers) {
|
29
|
+
k = header[0];
|
30
|
+
v = header[1];
|
31
|
+
if (!k.startsWith('rack.')) {
|
32
|
+
if (v.$$is_array) {
|
33
|
+
v = v.join("\n");
|
34
|
+
}
|
35
|
+
hdr.set(k, v);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
var body = '';
|
40
|
+
|
41
|
+
#{
|
42
|
+
parts = `rack_res[2]`
|
43
|
+
if parts.respond_to?(:each)
|
44
|
+
parts.each do |part|
|
45
|
+
# this is not technically correct, just to make htings work
|
46
|
+
`body = body + part`
|
47
|
+
end
|
48
|
+
elsif parts.respond_to?(:call)
|
49
|
+
`body = parts.$call()`
|
50
|
+
end
|
51
|
+
parts.close if parts.respond_to?(:close)
|
52
|
+
}
|
53
|
+
|
54
|
+
return new Response(body, {status: rack_res[0], statusText: 'OK', headers: hdr});
|
55
|
+
}
|
56
|
+
};
|
57
|
+
if (scheme === 'https') {
|
58
|
+
server_options.tls = {
|
59
|
+
key: Bun.file(key_file),
|
60
|
+
cert: Bun.file(cert_file),
|
61
|
+
ca: Bun.file(ca_file)
|
62
|
+
};
|
63
|
+
}
|
64
|
+
|
65
|
+
Bun.serve(server_options);
|
66
|
+
console.log(`Server is running on http://${host}:${port}`);
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.stop
|
71
|
+
sleep 0.1
|
72
|
+
puts 'deflating request chain links'
|
73
|
+
sleep 0.1
|
74
|
+
puts 'optimizing response distortion'
|
75
|
+
sleep 0.1
|
76
|
+
print 'releasing boost pressure: '
|
77
|
+
3.times do
|
78
|
+
sleep 0.2
|
79
|
+
print '.'
|
80
|
+
end
|
81
|
+
3.times do
|
82
|
+
puts "\nRED ALERT: boost pressure to high, cannot open release valve!1!!!"
|
83
|
+
sleep 0.1
|
84
|
+
print '.'
|
85
|
+
sleep 0.1
|
86
|
+
end
|
87
|
+
puts 'stopping engines failed, for further help see:'
|
88
|
+
puts 'https://www.youtube.com/watch?v=ecBco63zvas'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/up/bun_cli.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'opal/platform'
|
2
|
+
require 'bun/file'
|
3
|
+
require 'nodejs/require'
|
4
|
+
require 'opal-parser'
|
5
|
+
require 'rack/builder'
|
6
|
+
require 'up/rack_builder_patch'
|
7
|
+
|
8
|
+
module Up
|
9
|
+
module CLI
|
10
|
+
def self.try_file(filename)
|
11
|
+
return nil unless File.exist? filename
|
12
|
+
::Rack::Builder.parse_file filename
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_app(filename = 'config.ru')
|
16
|
+
app = nil
|
17
|
+
filename ||= 'config.ru'
|
18
|
+
app = try_file filename
|
19
|
+
if File.exist?("#{filename}.ru")
|
20
|
+
filename = "#{filename}.ru"
|
21
|
+
app ||= try_file filename
|
22
|
+
end
|
23
|
+
raise "Something wrong with #{filename}\n" unless app
|
24
|
+
app
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.call
|
28
|
+
app = get_app
|
29
|
+
Up::BunRack.run(app)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/up/bun_rack.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Up
|
2
|
+
module BunRack
|
3
|
+
def self.run(app, options = {})
|
4
|
+
Up::Bun.listen(app: app, port: options[:port], host: options[:host])
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.shutdown
|
9
|
+
Up::Bun.stop
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV['RACK_HANDLER'] ||= 'up'
|
15
|
+
|
16
|
+
begin
|
17
|
+
::Rackup::Handler.register('up', Up::BunRack) if defined?(::Rackup::Handler)
|
18
|
+
rescue StandardError
|
19
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# backtick_javascript: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'up/version'
|
5
|
+
|
6
|
+
module Up
|
7
|
+
class BunRackEnv < ::Hash
|
8
|
+
RACK_VARS = %w[rack.errors rack.hijack rack.hijack? rack.input rack.logger
|
9
|
+
rack.multipart.buffer_size rack.multipart.tempfile_factory
|
10
|
+
rack.response_finished
|
11
|
+
rack.session rack.upgrade rack.upgrade? rack.url_scheme
|
12
|
+
HTTP_ACCEPT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
|
13
|
+
HTTP_CONNECTION HTTP_HOST HTTP_USER_AGENT PATH_INFO QUERY_STRING REQUEST_METHOD
|
14
|
+
SCRIPT_NAME SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE]
|
15
|
+
def initialize(req, config)
|
16
|
+
@req = req
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
return super(key) if key?(key)
|
22
|
+
self[key] = case key
|
23
|
+
when 'rack.errors'
|
24
|
+
STDERR
|
25
|
+
when 'rack.hijack'
|
26
|
+
nil
|
27
|
+
when 'rack.hijack?'
|
28
|
+
false
|
29
|
+
when 'rack.input'
|
30
|
+
::IO.new
|
31
|
+
when 'rack.logger'
|
32
|
+
::Logger.new(self['rack.errors'])
|
33
|
+
when 'rack.multipart.buffer_size'
|
34
|
+
4096
|
35
|
+
when 'rack.multipart.tempfile_factory'
|
36
|
+
proc { |_filename, _content_type| File.new }
|
37
|
+
when 'rack.response_finished'
|
38
|
+
[]
|
39
|
+
when 'rack.session'
|
40
|
+
{}
|
41
|
+
when 'rack.upgrade'
|
42
|
+
nil
|
43
|
+
when 'rack.upgrade?'
|
44
|
+
nil
|
45
|
+
when 'rack.url_scheme'
|
46
|
+
@config[:scheme]
|
47
|
+
when 'PATH_INFO'
|
48
|
+
`#@req.url`
|
49
|
+
when 'QUERY_STRING'
|
50
|
+
""
|
51
|
+
when 'RACK_ERRORS'
|
52
|
+
self['rack.errors']
|
53
|
+
when 'RACK_LOGGER'
|
54
|
+
self['rack.logger']
|
55
|
+
when 'REQUEST_METHOD'
|
56
|
+
`#@req.method`
|
57
|
+
when 'SCRIPT_NAME'
|
58
|
+
""
|
59
|
+
when 'SERVER_NAME'
|
60
|
+
@config[:host]
|
61
|
+
when 'SERVER_PORT'
|
62
|
+
@config[:port].to_s
|
63
|
+
when 'SERVER_PROTOCOL'
|
64
|
+
""
|
65
|
+
when 'SERVER_SOFTWARE'
|
66
|
+
"#{@config[:handler]}/#{Up::VERSION} #{@config[:engine]}"
|
67
|
+
else
|
68
|
+
if key.start_with?('HTTP_')
|
69
|
+
key = key[5..].gsub(/_/, '-')
|
70
|
+
`#@req.headers.get(key.toLowerCase())`
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def req_headers
|
78
|
+
h = {}
|
79
|
+
%x{
|
80
|
+
var hdr, hds = #@req.headers;
|
81
|
+
for (hdr in hds) { h.set(hdr[0], hdr[1]); }
|
82
|
+
}
|
83
|
+
h
|
84
|
+
end
|
85
|
+
|
86
|
+
def each
|
87
|
+
unless @got_them_all
|
88
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
89
|
+
@got_them_all = true
|
90
|
+
end
|
91
|
+
super
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
unless @got_them_all
|
96
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
97
|
+
@got_them_all = true
|
98
|
+
end
|
99
|
+
super
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rack
|
2
|
+
class Builder
|
3
|
+
def self.load_file(path, **options)
|
4
|
+
config = ::File.read(path)
|
5
|
+
|
6
|
+
# config = config.slice(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8
|
7
|
+
|
8
|
+
if config[/^#\\(.*)/]
|
9
|
+
fail "Parsing options from the first comment line is no longer supported: #{path}"
|
10
|
+
end
|
11
|
+
|
12
|
+
config = config.sub(/^__END__\n.*\Z/m, '')
|
13
|
+
|
14
|
+
return new_from_string(config, path, **options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# backtick_javascript: true
|
2
|
+
|
3
|
+
%x{
|
4
|
+
module.paths.push(process.cwd() + '/node_modules');
|
5
|
+
const uws = require('uWebSockets.js');
|
6
|
+
const cluster = require('node:cluster');
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'up/uws_rack_env'
|
10
|
+
|
11
|
+
module Up
|
12
|
+
module UWebSocket
|
13
|
+
def self.listen(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil)
|
14
|
+
port = port&.to_i
|
15
|
+
scheme ||= 'http'
|
16
|
+
host ||= 'localhost'
|
17
|
+
port ||= 3000
|
18
|
+
config = { handler: self.name, engine: "node/#{`process.version`}", port: port, scheme: scheme, host: host }
|
19
|
+
%x{
|
20
|
+
let server;
|
21
|
+
if (scheme == 'http') {
|
22
|
+
server = uws.App();
|
23
|
+
} else if (scheme == 'https') {
|
24
|
+
server = uws.SSLApp({ ca_file_name: ca_file, cert_file_name: cert_file, key_file_name: key_file });
|
25
|
+
} else {
|
26
|
+
#{raise "unsupported scheme #{scheme}"}
|
27
|
+
}
|
28
|
+
server.get('/*', (res, req) => {
|
29
|
+
const rack_res = app.$call(Opal.Up.UwsRackEnv.$new(req, config));
|
30
|
+
res.writeStatus(`${rack_res[0].toString()} OK`);
|
31
|
+
const headers = rack_res[1];
|
32
|
+
if (headers.$$is_hash) {
|
33
|
+
var header, k, v;
|
34
|
+
for(header of headers) {
|
35
|
+
k = header[0];
|
36
|
+
v = header[1];
|
37
|
+
if (!k.startsWith('rack.')) {
|
38
|
+
if (v.$$is_array) {
|
39
|
+
v = v.join("\n");
|
40
|
+
}
|
41
|
+
res.writeHeader(k, v);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
#{
|
46
|
+
parts = `rack_res[2]`
|
47
|
+
if parts.respond_to?(:each)
|
48
|
+
parts.each do |part|
|
49
|
+
`res.write(part)`
|
50
|
+
end
|
51
|
+
elsif parts.respond_to?(:call)
|
52
|
+
`res.write(parts.$call())`
|
53
|
+
end
|
54
|
+
parts.close if parts.respond_to?(:close)
|
55
|
+
}
|
56
|
+
res.end();
|
57
|
+
});
|
58
|
+
server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`)});
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.stop
|
63
|
+
sleep 0.1
|
64
|
+
puts 'deflating request chain links'
|
65
|
+
sleep 0.1
|
66
|
+
puts 'optimizing response distortion'
|
67
|
+
sleep 0.1
|
68
|
+
print 'releasing boost pressure: '
|
69
|
+
3.times do
|
70
|
+
sleep 0.2
|
71
|
+
print '.'
|
72
|
+
end
|
73
|
+
3.times do
|
74
|
+
puts "\nRED ALERT: boost pressure to high, cannot open release valve!1!!!"
|
75
|
+
sleep 0.1
|
76
|
+
print '.'
|
77
|
+
sleep 0.1
|
78
|
+
end
|
79
|
+
puts 'stopping engines failed, for further help see:'
|
80
|
+
puts 'https://www.youtube.com/watch?v=ecBco63zvas'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# backtick_javascript: true
|
2
|
+
|
3
|
+
%x{
|
4
|
+
module.paths.push(process.cwd() + '/node_modules');
|
5
|
+
const uws = require('uWebSockets.js');
|
6
|
+
const cluster = require('node:cluster');
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'up/uws_rack_env'
|
10
|
+
|
11
|
+
module Up
|
12
|
+
module UWebSocket
|
13
|
+
def self.listen(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil, workers: 4)
|
14
|
+
port = port&.to_i
|
15
|
+
scheme ||= 'http'
|
16
|
+
host ||= 'localhost'
|
17
|
+
port ||= 3000
|
18
|
+
config = { handler: self.name, engine: "node/#{`process.version`}", port: port, scheme: scheme, host: host }
|
19
|
+
%x{
|
20
|
+
if (cluster.isPrimary) {
|
21
|
+
for (let i = 0; i < workers; i++) {
|
22
|
+
cluster.fork();
|
23
|
+
}
|
24
|
+
} else {
|
25
|
+
let server;
|
26
|
+
if (scheme == 'http') {
|
27
|
+
server = uws.App();
|
28
|
+
} else if (scheme == 'https') {
|
29
|
+
server = uws.SSLApp({ ca_file_name: ca_file, cert_file_name: cert_file, key_file_name: key_file });
|
30
|
+
} else {
|
31
|
+
#{raise "unsupported scheme #{scheme}"}
|
32
|
+
}
|
33
|
+
server.get('/*', (res, req) => {
|
34
|
+
const rack_res = app.$call(Opal.Up.UwsRackEnv.$new(req, config));
|
35
|
+
res.writeStatus(`${rack_res[0].toString()} OK`);
|
36
|
+
const headers = rack_res[1];
|
37
|
+
if (headers.$$is_hash) {
|
38
|
+
var header, k, v;
|
39
|
+
for(header of headers) {
|
40
|
+
k = header[0];
|
41
|
+
v = header[1];
|
42
|
+
if (!k.startsWith('rack.')) {
|
43
|
+
if (v.$$is_array) {
|
44
|
+
v = v.join("\n");
|
45
|
+
}
|
46
|
+
res.writeHeader(k, v);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
#{
|
51
|
+
parts = `rack_res[2]`
|
52
|
+
if parts.respond_to?(:each)
|
53
|
+
parts.each do |part|
|
54
|
+
`res.write(part)`
|
55
|
+
end
|
56
|
+
elsif parts.respond_to?(:call)
|
57
|
+
`res.write(parts.$call())`
|
58
|
+
end
|
59
|
+
parts.close if parts.respond_to?(:close)
|
60
|
+
}
|
61
|
+
res.end();
|
62
|
+
});
|
63
|
+
server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`)});
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.stop
|
69
|
+
sleep 0.1
|
70
|
+
puts 'deflating request chain links'
|
71
|
+
sleep 0.1
|
72
|
+
puts 'optimizing response distortion'
|
73
|
+
sleep 0.1
|
74
|
+
print 'releasing boost pressure: '
|
75
|
+
3.times do
|
76
|
+
sleep 0.2
|
77
|
+
print '.'
|
78
|
+
end
|
79
|
+
3.times do
|
80
|
+
puts "\nRED ALERT: boost pressure to high, cannot open release valve!1!!!"
|
81
|
+
sleep 0.1
|
82
|
+
print '.'
|
83
|
+
sleep 0.1
|
84
|
+
end
|
85
|
+
puts 'stopping engines failed, for further help see:'
|
86
|
+
puts 'https://www.youtube.com/watch?v=ecBco63zvas'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/up/uws_cli.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'opal/platform'
|
2
|
+
require 'nodejs/file'
|
3
|
+
require 'nodejs/require'
|
4
|
+
require 'opal-parser'
|
5
|
+
require 'rack/builder'
|
6
|
+
require 'up/rack_builder_patch'
|
7
|
+
|
8
|
+
module Up
|
9
|
+
module CLI
|
10
|
+
def self.try_file(filename)
|
11
|
+
return nil unless File.exist? filename
|
12
|
+
::Rack::Builder.parse_file filename
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.get_app(filename = 'config.ru')
|
16
|
+
app = nil
|
17
|
+
filename ||= 'config.ru'
|
18
|
+
app = try_file filename
|
19
|
+
if File.exist?("#{filename}.ru")
|
20
|
+
filename = "#{filename}.ru"
|
21
|
+
app ||= try_file filename
|
22
|
+
end
|
23
|
+
raise "Something wrong with #{filename}\n" unless app
|
24
|
+
app
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.call
|
28
|
+
app = get_app
|
29
|
+
Up::UwsRack.run(app)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/up/uws_rack.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Up
|
2
|
+
module UwsRack
|
3
|
+
def self.run(app, options = {})
|
4
|
+
Up::UWebSocket.listen(app: app, port: options[:port], host: options[:host])
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.shutdown
|
9
|
+
Up::UWebSocket.stop
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
ENV['RACK_HANDLER'] ||= 'up'
|
15
|
+
|
16
|
+
begin
|
17
|
+
::Rackup::Handler.register('up', Up::UwsRack) if defined?(::Rackup::Handler)
|
18
|
+
rescue StandardError
|
19
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# backtick_javascript: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'up/version'
|
5
|
+
|
6
|
+
module Up
|
7
|
+
class UwsRackEnv < ::Hash
|
8
|
+
RACK_VARS = %w[rack.errors rack.hijack rack.hijack? rack.input rack.logger
|
9
|
+
rack.multipart.buffer_size rack.multipart.tempfile_factory
|
10
|
+
rack.response_finished
|
11
|
+
rack.session rack.upgrade rack.upgrade? rack.url_scheme
|
12
|
+
HTTP_ACCEPT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
|
13
|
+
HTTP_CONNECTION HTTP_HOST HTTP_USER_AGENT PATH_INFO QUERY_STRING REQUEST_METHOD
|
14
|
+
SCRIPT_NAME SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE]
|
15
|
+
def initialize(req, config)
|
16
|
+
@req = req
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
return super(key) if key?(key)
|
22
|
+
self[key] = case key
|
23
|
+
when 'rack.errors'
|
24
|
+
STDERR
|
25
|
+
when 'rack.hijack'
|
26
|
+
nil
|
27
|
+
when 'rack.hijack?'
|
28
|
+
false
|
29
|
+
when 'rack.input'
|
30
|
+
::IO.new
|
31
|
+
when 'rack.logger'
|
32
|
+
::Logger.new(self['rack.errors'])
|
33
|
+
when 'rack.multipart.buffer_size'
|
34
|
+
4096
|
35
|
+
when 'rack.multipart.tempfile_factory'
|
36
|
+
proc { |_filename, _content_type| File.new }
|
37
|
+
when 'rack.response_finished'
|
38
|
+
[]
|
39
|
+
when 'rack.session'
|
40
|
+
{}
|
41
|
+
when 'rack.upgrade'
|
42
|
+
nil
|
43
|
+
when 'rack.upgrade?'
|
44
|
+
nil
|
45
|
+
when 'rack.url_scheme'
|
46
|
+
@config[:scheme]
|
47
|
+
when 'PATH_INFO'
|
48
|
+
`#@req.getUrl()`
|
49
|
+
when 'QUERY_STRING'
|
50
|
+
`#@req.getQuery()`
|
51
|
+
when 'RACK_ERRORS'
|
52
|
+
self['rack.errors']
|
53
|
+
when 'RACK_LOGGER'
|
54
|
+
self['rack.logger']
|
55
|
+
when 'REQUEST_METHOD'
|
56
|
+
`#@req.getMethod().toUpperCase()`
|
57
|
+
when 'SCRIPT_NAME'
|
58
|
+
""
|
59
|
+
when 'SERVER_NAME'
|
60
|
+
@config[:host]
|
61
|
+
when 'SERVER_PORT'
|
62
|
+
@config[:port].to_s
|
63
|
+
when 'SERVER_PROTOCOL'
|
64
|
+
`#@req.getHeader('protocol')`
|
65
|
+
when 'SERVER_SOFTWARE'
|
66
|
+
"#{@config[:handler]}/#{Up::VERSION} #{@config[:engine]}"
|
67
|
+
else
|
68
|
+
if key.start_with?('HTTP_')
|
69
|
+
key = key[5..].gsub(/_/, '-')
|
70
|
+
`#@req.getHeader(key.toLowerCase())`
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def req_headers
|
78
|
+
h = {}
|
79
|
+
`#@req.forEach((k, v) => { h.set(k, v); })`
|
80
|
+
h
|
81
|
+
end
|
82
|
+
|
83
|
+
def each
|
84
|
+
unless @got_them_all
|
85
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
86
|
+
@got_them_all = true
|
87
|
+
end
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
unless @got_them_all
|
93
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
94
|
+
@got_them_all = true
|
95
|
+
end
|
96
|
+
super
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/up/version.rb
ADDED
data/lib/up-bun.rb
ADDED
data/lib/up-node.rb
ADDED
data/opal-up.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require_relative 'lib/up/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'opal-up'
|
7
|
+
spec.version = Up::VERSION
|
8
|
+
spec.authors = ['Jan Biedermann']
|
9
|
+
spec.email = ['jan@kursator.de']
|
10
|
+
|
11
|
+
spec.summary = 'Rack server for Opal'
|
12
|
+
spec.description = 'High performance Rack server for Opal Ruby'
|
13
|
+
spec.homepage = ''
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test_app|test|spec|features)/}) }
|
16
|
+
spec.bindir = 'bin'
|
17
|
+
spec.executables = %w[up up_bun]
|
18
|
+
spec.require_paths = %w[lib]
|
19
|
+
|
20
|
+
spec.add_dependency 'logger', '~> 1.6.0'
|
21
|
+
spec.add_dependency 'opal', '>= 1.8.2', '< 3.0.0'
|
22
|
+
spec.add_dependency 'rack', '~> 3.0.9'
|
23
|
+
spec.add_dependency 'rackup', '>= 0.2.2', '< 3.0.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'rake', '~> 13.1.0'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.12.0'
|
27
|
+
end
|
data/up_logo.svg
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
3
|
+
|
4
|
+
<svg
|
5
|
+
version="1.1"
|
6
|
+
id="Capa_1"
|
7
|
+
x="0px"
|
8
|
+
y="0px"
|
9
|
+
viewBox="0 0 799.92104 945.28792"
|
10
|
+
xml:space="preserve"
|
11
|
+
width="799.92102"
|
12
|
+
height="945.2879"
|
13
|
+
xmlns="http://www.w3.org/2000/svg"
|
14
|
+
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
15
|
+
id="defs65"><rect
|
16
|
+
x="222.77943"
|
17
|
+
y="327.29486"
|
18
|
+
width="357.86758"
|
19
|
+
height="243.77267"
|
20
|
+
id="rect66" /><rect
|
21
|
+
x="27.871536"
|
22
|
+
y="730.54065"
|
23
|
+
width="778.40509"
|
24
|
+
height="77.992775"
|
25
|
+
id="rect65" /></defs>
|
26
|
+
<rect
|
27
|
+
y="0"
|
28
|
+
style="clip-rule:evenodd;fill:#a0dbfa;fill-rule:evenodd;stroke-width:1.08707"
|
29
|
+
width="799.91998"
|
30
|
+
height="945.2879"
|
31
|
+
id="rect1"
|
32
|
+
x="0.001" />
|
33
|
+
<polygon
|
34
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
35
|
+
points="658.991,136.939 654.959,136.939 654.959,377.684 646.655,377.684 646.655,136.939 642.378,136.939 650.684,125.153 "
|
36
|
+
id="polygon1"
|
37
|
+
transform="translate(0.001,145.36792)" />
|
38
|
+
<path
|
39
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
40
|
+
d="m 51.406,361.61492 -10.996,-15.601 -11.853,16.817 v -77.905 H 43.49 l -28.997,-41.142 -14.492,20.562 v 680.942 c 287.066,0 608.08,0 799.92,0 v -667.871 l -23.525,33.38 h 13.71 v 49.736 l -9.558,-13.56 -8.285,11.756 v -97.417 h 14.933 l -28.997,-41.143 -28.998,41.143 h 14.075 v 32.453 l -6.645,-9.426 -19.901,28.237 h 9.66 v 31.023 l -11.389,-16.159 -12.573,17.839 v -58.049 h 14.933 l -28.997,-41.143 -28.997,41.143 h 14.075 v 48.193 l -11.716,-16.623 -28.996,41.143 h 14.074 v 33.128 l -10.901,-15.468 -12.667,17.972 v -82.428 h 14.933 l -28.997,-41.143 -28.997,41.143 h 14.075 v 23.414 l -10.996,-15.601 -11.853,16.818 v -77.905 h 14.933 l -28.997,-41.143 -28.997,41.143 h 14.075 v 48.954 l -9.197,-13.05 -28.244,40.074 h 13.709 v 49.736 l -9.557,-13.56 -8.285,11.756 v -97.417 h 14.932 l -28.997,-41.142 -28.996,41.142 h 14.074 v 32.453 l -6.643,-9.426 -19.901,28.237 h 9.66 v 31.023 l -11.389,-16.159 -12.573,17.839 v -58.049 h 14.933 l -28.997,-41.142 -28.997,41.142 h 14.075 v 48.193 l -11.716,-16.623 -28.997,41.142 h 14.075 v 29.21 l -11.853,-16.817 -11.715,16.623 v -75.811 h 14.932 l -28.997,-41.142 -28.996,41.142 h 14.075 v 23.414 l -10.996,-15.601 -11.853,16.817 v -77.905 h 14.932 l -28.997,-41.143 -28.997,41.143 h 14.075 v 23.9 l -9.197,-13.05 -28.244,40.074 h 13.71 v 49.736 l -9.557,-13.56 -8.286,11.756 v -137.781 h 14.933 l -28.997,-41.142 -28.996,41.142 h 14.075 v 72.818 l -6.644,-9.426 -19.902,28.237 h 9.66 v 31.023 l -11.389,-16.159 -12.573,17.839 v -58.049 h 14.933 l -28.997,-41.142 -28.996,41.142 h 14.075 v 48.193 l -11.715,-16.623 -28.997,41.142 h 14.075 v 22.63 l -12.349,-17.521 -11.22,15.92 v -67.824 h 14.933 l -28.997,-41.142 -29.001,41.143 h 14.075 z"
|
41
|
+
id="path1" />
|
42
|
+
<polygon
|
43
|
+
style="clip-rule:evenodd;fill:#0073a2;fill-rule:evenodd"
|
44
|
+
points="154.962,396.856 130.926,396.856 130.926,784.116 81.428,784.116 81.428,396.856 55.928,396.856 105.445,326.598 "
|
45
|
+
id="polygon2"
|
46
|
+
transform="translate(0.001,145.36792)" />
|
47
|
+
<polygon
|
48
|
+
style="clip-rule:evenodd;fill:#f4b200;fill-rule:evenodd"
|
49
|
+
points="114.003,487.786 89.967,487.786 89.967,784.116 40.468,784.116 40.468,487.786 14.968,487.786 64.485,417.528 "
|
50
|
+
id="polygon3"
|
51
|
+
transform="translate(0.001,145.36792)" />
|
52
|
+
<polygon
|
53
|
+
style="clip-rule:evenodd;fill:#e95818;fill-rule:evenodd"
|
54
|
+
points="89.967,487.786 89.967,784.116 81.428,784.116 81.428,441.566 114.003,487.786 "
|
55
|
+
id="polygon4"
|
56
|
+
transform="translate(0.001,145.36792)" />
|
57
|
+
<polygon
|
58
|
+
style="clip-rule:evenodd;fill:#dd0031;fill-rule:evenodd"
|
59
|
+
points="195.102,525.469 171.067,525.469 171.067,784.116 121.568,784.116 121.568,525.469 96.068,525.469 145.585,455.211 "
|
60
|
+
id="polygon5"
|
61
|
+
transform="translate(0.001,145.36792)" />
|
62
|
+
<polygon
|
63
|
+
style="clip-rule:evenodd;fill:#6f3969;fill-rule:evenodd"
|
64
|
+
points="130.926,784.116 121.568,784.116 121.568,525.469 96.068,525.469 130.926,476.01 "
|
65
|
+
id="polygon6"
|
66
|
+
transform="translate(0.001,145.36792)" />
|
67
|
+
<polygon
|
68
|
+
style="clip-rule:evenodd;fill:#a1ba24;fill-rule:evenodd"
|
69
|
+
points="236.166,307.834 212.13,307.834 212.13,784.116 162.631,784.116 162.631,307.834 137.132,307.834 186.649,237.576 "
|
70
|
+
id="polygon7"
|
71
|
+
transform="translate(0.001,145.36792)" />
|
72
|
+
<polygon
|
73
|
+
style="clip-rule:evenodd;fill:#bf5c2a;fill-rule:evenodd"
|
74
|
+
points="171.067,525.469 171.067,784.116 162.631,784.116 162.631,479.396 195.102,525.469 "
|
75
|
+
id="polygon8"
|
76
|
+
transform="translate(0.001,145.36792)" />
|
77
|
+
<polygon
|
78
|
+
style="clip-rule:evenodd;fill:#801d88;fill-rule:evenodd"
|
79
|
+
points="277.229,222.627 253.193,222.627 253.193,784.116 203.694,784.116 203.694,222.627 178.195,222.627 227.712,152.37 "
|
80
|
+
id="polygon9"
|
81
|
+
transform="translate(0.001,145.36792)" />
|
82
|
+
<polygon
|
83
|
+
style="clip-rule:evenodd;fill:#916c56;fill-rule:evenodd"
|
84
|
+
points="212.13,307.834 212.13,784.116 203.694,784.116 203.694,261.761 236.166,307.834 "
|
85
|
+
id="polygon10"
|
86
|
+
transform="translate(0.001,145.36792)" />
|
87
|
+
<polygon
|
88
|
+
style="clip-rule:evenodd;fill:#ed6500;fill-rule:evenodd"
|
89
|
+
points="319.225,360.012 295.189,360.012 295.189,784.116 245.69,784.116 245.69,360.012 220.19,360.012 269.707,289.754 "
|
90
|
+
id="polygon11"
|
91
|
+
transform="translate(0.001,145.36792)" />
|
92
|
+
<polygon
|
93
|
+
style="clip-rule:evenodd;fill:#b74144;fill-rule:evenodd"
|
94
|
+
points="253.193,784.116 245.69,784.116 245.69,360.012 220.19,360.012 253.193,313.185 "
|
95
|
+
id="polygon12"
|
96
|
+
transform="translate(0.001,145.36792)" />
|
97
|
+
<polygon
|
98
|
+
style="clip-rule:evenodd;fill:#0073a2;fill-rule:evenodd"
|
99
|
+
points="360.754,438.811 336.719,438.811 336.719,784.116 287.22,784.116 287.22,438.811 261.72,438.811 311.237,368.553 "
|
100
|
+
id="polygon13"
|
101
|
+
transform="translate(0.001,145.36792)" />
|
102
|
+
<polygon
|
103
|
+
style="clip-rule:evenodd;fill:#766c51;fill-rule:evenodd"
|
104
|
+
points="287.22,784.116 287.22,438.811 261.72,438.811 295.189,391.323 295.189,784.116 "
|
105
|
+
id="polygon14"
|
106
|
+
transform="translate(0.001,145.36792)" />
|
107
|
+
<polygon
|
108
|
+
style="clip-rule:evenodd;fill:#f4b200;fill-rule:evenodd"
|
109
|
+
points="402.284,289.731 378.248,289.731 378.248,784.116 328.749,784.116 328.749,289.731 303.249,289.731 352.767,219.473 "
|
110
|
+
id="polygon15"
|
111
|
+
transform="translate(0.001,145.36792)" />
|
112
|
+
<polygon
|
113
|
+
style="clip-rule:evenodd;fill:#7a9350;fill-rule:evenodd"
|
114
|
+
points="336.719,438.811 336.719,784.116 328.749,784.116 328.749,393.4 360.754,438.811 "
|
115
|
+
id="polygon16"
|
116
|
+
transform="translate(0.001,145.36792)" />
|
117
|
+
<polygon
|
118
|
+
style="clip-rule:evenodd;fill:#c5007e;fill-rule:evenodd"
|
119
|
+
points="443.813,385.568 419.777,385.568 419.777,784.116 370.278,784.116 370.278,385.568 344.779,385.568 394.296,315.311 "
|
120
|
+
id="polygon17"
|
121
|
+
transform="translate(0.001,145.36792)" />
|
122
|
+
<polygon
|
123
|
+
style="clip-rule:evenodd;fill:#dd593e;fill-rule:evenodd"
|
124
|
+
points="378.248,784.116 370.278,784.116 370.278,385.568 344.779,385.568 378.248,338.08 "
|
125
|
+
id="polygon18"
|
126
|
+
transform="translate(0.001,145.36792)" />
|
127
|
+
<polygon
|
128
|
+
style="clip-rule:evenodd;fill:#801d88;fill-rule:evenodd"
|
129
|
+
points="462.372,784.116 412.873,784.116 412.873,494.185 387.373,494.185 436.891,423.926 486.407,494.185 462.372,494.185 "
|
130
|
+
id="polygon19"
|
131
|
+
transform="translate(0.001,145.36792)" />
|
132
|
+
<polygon
|
133
|
+
style="clip-rule:evenodd;fill:#a30e83;fill-rule:evenodd"
|
134
|
+
points="419.777,784.116 412.873,784.116 412.873,494.185 387.373,494.185 419.777,448.207 "
|
135
|
+
id="polygon20"
|
136
|
+
transform="translate(0.001,145.36792)" />
|
137
|
+
<polygon
|
138
|
+
style="clip-rule:evenodd;fill:#dd0031;fill-rule:evenodd"
|
139
|
+
points="530.066,585.762 506.03,585.762 506.03,784.116 456.532,784.116 456.532,585.762 431.032,585.762 480.55,515.504 "
|
140
|
+
id="polygon21"
|
141
|
+
transform="translate(0.001,145.36792)" />
|
142
|
+
<polygon
|
143
|
+
style="clip-rule:evenodd;fill:#af0e5c;fill-rule:evenodd"
|
144
|
+
points="456.532,784.116 456.532,585.762 431.032,585.762 462.372,541.295 462.372,784.116 "
|
145
|
+
id="polygon22"
|
146
|
+
transform="translate(0.001,145.36792)" />
|
147
|
+
<polygon
|
148
|
+
style="clip-rule:evenodd;fill:#ed6500;fill-rule:evenodd"
|
149
|
+
points="572.661,424.968 548.625,424.968 548.625,784.116 499.126,784.116 499.126,424.968 473.627,424.968 523.144,354.71 "
|
150
|
+
id="polygon23"
|
151
|
+
transform="translate(0.001,145.36792)" />
|
152
|
+
<polygon
|
153
|
+
style="clip-rule:evenodd;fill:#e53218;fill-rule:evenodd"
|
154
|
+
points="506.03,585.762 506.03,784.116 499.126,784.116 499.126,541.861 530.066,585.762 "
|
155
|
+
id="polygon24"
|
156
|
+
transform="translate(0.001,145.36792)" />
|
157
|
+
<polygon
|
158
|
+
style="clip-rule:evenodd;fill:#0073a2;fill-rule:evenodd"
|
159
|
+
points="615.255,327.001 591.22,327.001 591.22,784.116 541.721,784.116 541.721,327.001 516.221,327.001 565.738,256.743 "
|
160
|
+
id="polygon25"
|
161
|
+
transform="translate(0.001,145.36792)" />
|
162
|
+
<polygon
|
163
|
+
style="clip-rule:evenodd;fill:#766c51;fill-rule:evenodd"
|
164
|
+
points="548.625,424.968 548.625,784.116 541.721,784.116 541.721,381.068 572.661,424.968 "
|
165
|
+
id="polygon26"
|
166
|
+
transform="translate(0.001,145.36792)" />
|
167
|
+
<polygon
|
168
|
+
style="clip-rule:evenodd;fill:#f4b200;fill-rule:evenodd"
|
169
|
+
points="657.85,472.887 633.813,472.887 633.813,784.116 584.315,784.116 584.315,472.887 558.815,472.887 608.332,402.629 "
|
170
|
+
id="polygon27"
|
171
|
+
transform="translate(0.001,145.36792)" />
|
172
|
+
<polygon
|
173
|
+
style="clip-rule:evenodd;fill:#7a9350;fill-rule:evenodd"
|
174
|
+
points="584.315,784.116 584.315,472.887 558.815,472.887 591.22,426.909 591.22,784.116 "
|
175
|
+
id="polygon28"
|
176
|
+
transform="translate(0.001,145.36792)" />
|
177
|
+
<polygon
|
178
|
+
style="clip-rule:evenodd;fill:#801d88;fill-rule:evenodd"
|
179
|
+
points="701.509,571.919 677.473,571.919 677.473,784.116 627.974,784.116 627.974,571.919 602.475,571.919 651.991,501.66 "
|
180
|
+
id="polygon29"
|
181
|
+
transform="translate(0.001,145.36792)" />
|
182
|
+
<polygon
|
183
|
+
style="clip-rule:evenodd;fill:#ba6744;fill-rule:evenodd"
|
184
|
+
points="633.813,784.116 627.974,784.116 627.974,571.919 602.475,571.919 633.813,527.452 "
|
185
|
+
id="polygon30"
|
186
|
+
transform="translate(0.001,145.36792)" />
|
187
|
+
<polygon
|
188
|
+
style="clip-rule:evenodd;fill:#a1ba24;fill-rule:evenodd"
|
189
|
+
points="744.102,399.412 720.067,399.412 720.067,784.116 670.568,784.116 670.568,399.412 645.068,399.412 694.586,329.153 "
|
190
|
+
id="polygon31"
|
191
|
+
transform="translate(0.001,145.36792)" />
|
192
|
+
<polygon
|
193
|
+
style="clip-rule:evenodd;fill:#916c56;fill-rule:evenodd"
|
194
|
+
points="677.473,571.919 677.473,784.116 670.568,784.116 670.568,528.018 701.509,571.919 "
|
195
|
+
id="polygon32"
|
196
|
+
transform="translate(0.001,145.36792)" />
|
197
|
+
<polygon
|
198
|
+
style="clip-rule:evenodd;fill:#dd0031;fill-rule:evenodd"
|
199
|
+
points="786.697,511.222 762.661,511.222 762.661,784.116 713.162,784.116 713.162,511.222 687.662,511.222 737.18,440.964 "
|
200
|
+
id="polygon33"
|
201
|
+
transform="translate(0.001,145.36792)" />
|
202
|
+
<polygon
|
203
|
+
style="clip-rule:evenodd;fill:#bf5c2a;fill-rule:evenodd"
|
204
|
+
points="713.162,784.116 713.162,511.222 687.662,511.222 720.067,465.244 720.067,784.116 "
|
205
|
+
id="polygon34"
|
206
|
+
transform="translate(0.001,145.36792)" />
|
207
|
+
<path
|
208
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
209
|
+
d="m 140.554,690.37292 28.997,-41.143 28.997,41.143 h -14.075 v 64.45 l 10.996,-15.602 28.997,41.143 h -14.075 v 23.414 l 10.996,-15.602 11.852,16.817 v -77.905 h -14.932 l 28.997,-41.142 28.997,41.142 h -14.075 v 48.954 l 9.197,-13.05 28.245,40.075 h -13.71 v 49.735 l 9.557,-13.56 8.286,11.757 v -97.417 h -14.933 l 28.997,-41.142 28.997,41.142 h -14.075 v 32.453 l 6.644,-9.427 19.901,28.238 h -9.66 v 31.022 l 11.389,-16.159 12.573,17.839 v -58.049 h -14.933 l 28.997,-41.143 28.997,41.143 H 402.62 v 48.193 l 11.716,-16.623 21.46416,30.45686 5.31084,-6.92086 11.716,16.622 v -45.81 h -14.933 l 28.997,-41.142 28.997,41.142 h -14.075 v 23.414 l 10.996,-15.601 11.853,16.817 v -77.905 h -14.933 l 28.997,-41.143 28.997,41.143 h -14.075 v 23.899 l 9.198,-13.05 28.243,40.075 H 557.38 v 49.735 l 9.557,-13.56 8.286,11.757 v -137.78 H 560.29 l 28.997,-41.142 28.997,41.142 h -14.075 v 72.818 l 6.644,-9.427 19.901,28.238 h -9.66 v 31.022 l 11.39,-16.159 12.572,17.839 v -58.049 h -14.933 l 28.997,-41.143 28.997,41.143 h -14.075 v 48.193 l 11.716,-16.623 22.43456,30.47358 4.83644,-6.22158 11.22,15.92 v -45.824 h -14.932 l 28.997,-41.142 28.996,41.142 h -14.074 v 23.414 l 10.995,-15.601 11.852,16.817 v -77.905 l -11.98653,-0.65137 26.05053,-40.49163 9.773,13.867 v 208.42 H 0 v -195.348 l 28.244,40.074 h -13.71 v 49.735 l 9.557,-13.56 8.286,11.756 v -97.416 H 17.446 l 28.997,-41.143 28.997,41.143 H 61.365 v 32.452 l 6.644,-9.426 19.901,28.237 h -9.66 v 31.022 l 11.389,-16.159 12.573,17.839 v -58.049 H 87.279 l 28.997,-41.142 28.997,41.142 h -14.075 v 48.193 l 11.716,-16.622 12.573,17.839 v -113.481 z"
|
210
|
+
id="path34" />
|
211
|
+
|
212
|
+
<polygon
|
213
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
214
|
+
points="73.967,118.991 69.935,118.991 69.935,359.736 61.631,359.736 61.631,118.991 57.354,118.991 65.66,107.205 "
|
215
|
+
id="polygon60"
|
216
|
+
transform="translate(0.001,145.36792)" />
|
217
|
+
<polygon
|
218
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
219
|
+
points="156.145,37.469 152.112,37.469 152.112,278.214 143.809,278.214 143.809,37.469 139.531,37.469 147.837,25.683 "
|
220
|
+
id="polygon61"
|
221
|
+
transform="translate(0.001,145.36792)" />
|
222
|
+
<polygon
|
223
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
224
|
+
points="653.848,606.583 649.815,606.583 649.815,756.577 641.512,756.577 641.512,606.583 637.234,606.583 645.541,594.797 "
|
225
|
+
id="polygon62"
|
226
|
+
transform="translate(0.001,145.36792)" />
|
227
|
+
<polygon
|
228
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
229
|
+
points="132.417,541.98 128.384,541.98 128.384,691.976 120.081,691.976 120.081,541.98 115.803,541.98 124.109,530.194 "
|
230
|
+
id="polygon63"
|
231
|
+
transform="translate(0.001,145.36792)" />
|
232
|
+
<polygon
|
233
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
234
|
+
points="752.289,592.739 748.256,592.739 748.256,742.734 739.953,742.734 739.953,592.739 735.675,592.739 743.981,580.953 "
|
235
|
+
id="polygon64"
|
236
|
+
transform="translate(0.001,145.36792)" />
|
237
|
+
<polygon
|
238
|
+
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd"
|
239
|
+
points="471.004,75.805 466.972,75.805 466.972,316.55 458.668,316.55 458.668,75.805 454.391,75.805 462.697,64.019 "
|
240
|
+
id="polygon65"
|
241
|
+
transform="translate(0.001,145.36792)" />
|
242
|
+
<text
|
243
|
+
xml:space="preserve"
|
244
|
+
id="text65"
|
245
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:53.3333px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;white-space:pre;shape-inside:url(#rect65);fill:#000000"
|
246
|
+
transform="translate(-11.999,133.36792)"><tspan
|
247
|
+
x="27.871094"
|
248
|
+
y="778.58122"
|
249
|
+
id="tspan1">UNEXPECTED PROMPTITUDE</tspan></text><text
|
250
|
+
xml:space="preserve"
|
251
|
+
id="text66"
|
252
|
+
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:192px;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;white-space:pre;shape-inside:url(#rect66);fill:#000000"
|
253
|
+
transform="translate(20.13016,-317.87561)"><tspan
|
254
|
+
x="222.7793"
|
255
|
+
y="500.23977"
|
256
|
+
id="tspan2">UP!</tspan></text></svg>
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opal-up
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jan Biedermann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-02-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logger
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: opal
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.2
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 3.0.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.8.2
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.0.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rack
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.0.9
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.0.9
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rackup
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.2.2
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 3.0.0
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.2.2
|
78
|
+
- - "<"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 3.0.0
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 13.1.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 13.1.0
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 3.12.0
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 3.12.0
|
109
|
+
description: High performance Rack server for Opal Ruby
|
110
|
+
email:
|
111
|
+
- jan@kursator.de
|
112
|
+
executables:
|
113
|
+
- up
|
114
|
+
- up_bun
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE
|
121
|
+
- README.md
|
122
|
+
- bin/up
|
123
|
+
- bin/up_bun
|
124
|
+
- example_rack_app/Gemfile
|
125
|
+
- example_rack_app/config.ru
|
126
|
+
- example_rack_app/rack_app.rb
|
127
|
+
- example_roda_app/Gemfile
|
128
|
+
- example_roda_app/config.ru
|
129
|
+
- example_roda_app/roda_app.rb
|
130
|
+
- example_sinatra_app/Gemfile
|
131
|
+
- example_sinatra_app/config.ru
|
132
|
+
- example_sinatra_app/sinatra_app.rb
|
133
|
+
- lib/up-bun.rb
|
134
|
+
- lib/up-node.rb
|
135
|
+
- lib/up/bun.rb
|
136
|
+
- lib/up/bun_cli.rb
|
137
|
+
- lib/up/bun_rack.rb
|
138
|
+
- lib/up/bun_rack_env.rb
|
139
|
+
- lib/up/rack_builder_patch.rb
|
140
|
+
- lib/up/u_web_socket.rb
|
141
|
+
- lib/up/u_web_socket_cluster.rb
|
142
|
+
- lib/up/uws_cli.rb
|
143
|
+
- lib/up/uws_rack.rb
|
144
|
+
- lib/up/uws_rack_env.rb
|
145
|
+
- lib/up/version.rb
|
146
|
+
- opal-up.gemspec
|
147
|
+
- up_logo.svg
|
148
|
+
homepage: ''
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubygems_version: 3.5.3
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: Rack server for Opal
|
171
|
+
test_files: []
|