opal-up 0.0.1 → 0.0.3
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 +4 -4
- data/LICENSE +209 -0
- data/README.md +108 -23
- data/bin/up +5 -22
- data/bin/up_bun +5 -16
- data/bin/up_cluster +12 -0
- data/bin/up_node +12 -0
- data/bin/up_node_cluster +12 -0
- data/bin/up_ruby +4 -0
- data/bin/up_ruby_cluster +4 -0
- data/ext/up_ext/App.h +606 -0
- data/ext/up_ext/AsyncSocket.h +355 -0
- data/ext/up_ext/AsyncSocketData.h +87 -0
- data/ext/up_ext/BloomFilter.h +83 -0
- data/ext/up_ext/ChunkedEncoding.h +236 -0
- data/ext/up_ext/ClientApp.h +36 -0
- data/ext/up_ext/HttpContext.h +502 -0
- data/ext/up_ext/HttpContextData.h +56 -0
- data/ext/up_ext/HttpErrors.h +53 -0
- data/ext/up_ext/HttpParser.h +680 -0
- data/ext/up_ext/HttpResponse.h +578 -0
- data/ext/up_ext/HttpResponseData.h +95 -0
- data/ext/up_ext/HttpRouter.h +380 -0
- data/ext/up_ext/Loop.h +204 -0
- data/ext/up_ext/LoopData.h +112 -0
- data/ext/up_ext/MoveOnlyFunction.h +377 -0
- data/ext/up_ext/PerMessageDeflate.h +315 -0
- data/ext/up_ext/ProxyParser.h +163 -0
- data/ext/up_ext/QueryParser.h +120 -0
- data/ext/up_ext/TopicTree.h +363 -0
- data/ext/up_ext/Utilities.h +66 -0
- data/ext/up_ext/WebSocket.h +381 -0
- data/ext/up_ext/WebSocketContext.h +434 -0
- data/ext/up_ext/WebSocketContextData.h +109 -0
- data/ext/up_ext/WebSocketData.h +86 -0
- data/ext/up_ext/WebSocketExtensions.h +256 -0
- data/ext/up_ext/WebSocketHandshake.h +145 -0
- data/ext/up_ext/WebSocketProtocol.h +506 -0
- data/ext/up_ext/bsd.c +767 -0
- data/ext/up_ext/bsd.h +109 -0
- data/ext/up_ext/context.c +524 -0
- data/ext/up_ext/epoll_kqueue.c +458 -0
- data/ext/up_ext/epoll_kqueue.h +67 -0
- data/ext/up_ext/extconf.rb +5 -0
- data/ext/up_ext/internal.h +224 -0
- data/ext/up_ext/libusockets.h +350 -0
- data/ext/up_ext/libuwebsockets.cpp +1374 -0
- data/ext/up_ext/libuwebsockets.h +260 -0
- data/ext/up_ext/loop.c +386 -0
- data/ext/up_ext/loop_data.h +38 -0
- data/ext/up_ext/socket.c +231 -0
- data/ext/up_ext/up_ext.c +278 -0
- data/lib/up/bun/rack_env.rb +104 -0
- data/lib/up/bun/rack_server.rb +25 -0
- data/lib/up/bun/server.rb +89 -0
- data/lib/up/bun/server_cli.rb +15 -0
- data/lib/up/cli.rb +151 -0
- data/lib/up/node/cluster.rb +39 -0
- data/lib/up/node/cluster_cli.rb +15 -0
- data/lib/up/node/rack_cluster.rb +25 -0
- data/lib/up/node/rack_env.rb +106 -0
- data/lib/up/node/rack_server.rb +25 -0
- data/lib/up/node/server.rb +84 -0
- data/lib/up/node/server_cli.rb +15 -0
- data/lib/up/ruby/cluster_cli.rb +10 -0
- data/lib/up/ruby/rack_cluster.rb +26 -0
- data/lib/up/ruby/rack_env.rb +97 -0
- data/lib/up/ruby/rack_server.rb +26 -0
- data/lib/up/ruby/server_cli.rb +10 -0
- data/lib/up/u_web_socket/cluster.rb +39 -0
- data/lib/up/u_web_socket/cluster_cli.rb +15 -0
- data/lib/up/u_web_socket/rack_cluster.rb +25 -0
- data/lib/up/u_web_socket/rack_env.rb +101 -0
- data/lib/up/u_web_socket/rack_server.rb +25 -0
- data/lib/up/u_web_socket/server.rb +82 -0
- data/lib/up/u_web_socket/server_cli.rb +15 -0
- data/lib/up/version.rb +1 -1
- metadata +96 -29
- data/.gitignore +0 -5
- data/Gemfile +0 -2
- data/example_rack_app/Gemfile +0 -3
- data/example_rack_app/config.ru +0 -6
- data/example_rack_app/rack_app.rb +0 -5
- data/example_roda_app/Gemfile +0 -6
- data/example_roda_app/config.ru +0 -6
- data/example_roda_app/roda_app.rb +0 -35
- data/example_sinatra_app/Gemfile +0 -6
- data/example_sinatra_app/config.ru +0 -6
- data/example_sinatra_app/sinatra_app.rb +0 -7
- data/lib/up/bun.rb +0 -91
- data/lib/up/bun_cli.rb +0 -32
- data/lib/up/bun_rack.rb +0 -19
- data/lib/up/bun_rack_env.rb +0 -102
- data/lib/up/u_web_socket.rb +0 -83
- data/lib/up/u_web_socket_cluster.rb +0 -89
- data/lib/up/uws_cli.rb +0 -32
- data/lib/up/uws_rack.rb +0 -19
- data/lib/up/uws_rack_env.rb +0 -99
- data/lib/up-bun.rb +0 -7
- data/lib/up-node.rb +0 -7
- data/opal-up.gemspec +0 -27
- data/up_logo.svg +0 -256
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# backtick_javascript: true
|
|
2
|
+
require 'up/cli'
|
|
3
|
+
require 'up/bun/rack_env'
|
|
4
|
+
|
|
5
|
+
module Up
|
|
6
|
+
module Bun
|
|
7
|
+
class Server
|
|
8
|
+
def initialize(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil)
|
|
9
|
+
@app = app
|
|
10
|
+
@scheme = scheme || 'http'
|
|
11
|
+
raise "unsupported scheme #{@scheme}" unless %w[http https].include?(@scheme)
|
|
12
|
+
@host = host || 'localhost'
|
|
13
|
+
@port = port&.to_i || 3000
|
|
14
|
+
@config = { handler: self.class.name, engine: "bun/#{`process.version`}", port: port, scheme: scheme, host: host }.freeze
|
|
15
|
+
@ca_file = ca_file
|
|
16
|
+
@cert_file = cert_file
|
|
17
|
+
@key_file = key_file
|
|
18
|
+
@server = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
%x{
|
|
22
|
+
self.handle_headers = function(rack_headers, bun_hdr) {
|
|
23
|
+
if (rack_headers.$$is_hash) {
|
|
24
|
+
var header, k, v;
|
|
25
|
+
for(header of rack_headers) {
|
|
26
|
+
k = header[0];
|
|
27
|
+
if (!k.startsWith('rack.')) {
|
|
28
|
+
v = header[1];
|
|
29
|
+
if (v.$$is_array) {
|
|
30
|
+
v = v.join("\n");
|
|
31
|
+
}
|
|
32
|
+
bun_hdr.set(k, v);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
self.handle_response = function(parts, body) {
|
|
39
|
+
if (parts["$respond_to?"]('each')) {
|
|
40
|
+
// this is not technically correct, just to make things work
|
|
41
|
+
#{`parts`.each { |part| `body = body + part` }}
|
|
42
|
+
} else if (parts["$respond_to?"]('call')) {
|
|
43
|
+
body = parts.$call();
|
|
44
|
+
}
|
|
45
|
+
#{`parts`.close if `parts`.respond_to?(:close)}
|
|
46
|
+
return body;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
def listen
|
|
50
|
+
raise "already running" if @server
|
|
51
|
+
%x{
|
|
52
|
+
const oubr = Opal.Up.Bun.RackEnv;
|
|
53
|
+
const oubs = Opal.Up.Bun.Server;
|
|
54
|
+
|
|
55
|
+
var server_options = {
|
|
56
|
+
port: #@port,
|
|
57
|
+
hostname: #@host,
|
|
58
|
+
development: false,
|
|
59
|
+
fetch(req) {
|
|
60
|
+
const rack_res = #@app.$call(oubr.$new(req, #@config));
|
|
61
|
+
const hdr = new Headers();
|
|
62
|
+
oubs.handle_headers(rack_res[1]);
|
|
63
|
+
var body = '';
|
|
64
|
+
body = oubs.handle_response(rack_res[2], body);
|
|
65
|
+
return new Response(body, {status: rack_res[0], statusText: 'OK', headers: hdr});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
if (#@scheme === 'https') {
|
|
69
|
+
server_options.tls = {
|
|
70
|
+
key: Bun.file(#@key_file),
|
|
71
|
+
cert: Bun.file(#@cert_file),
|
|
72
|
+
ca: Bun.file(#@ca_file)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#@server = Bun.serve(server_options);
|
|
77
|
+
console.log(`Server is running on ${#@scheme}://${#@host}:${#@port}`);
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def stop
|
|
82
|
+
if Up::CLI::stoppable?
|
|
83
|
+
`#@server.stop()`
|
|
84
|
+
@server = nil
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
require 'up/bun/rack_server'
|
|
8
|
+
|
|
9
|
+
module Up
|
|
10
|
+
module CLI
|
|
11
|
+
def self.call
|
|
12
|
+
Up::Bun::RackServer.run(get_app, get_options)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/up/cli.rb
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
require 'up/version'
|
|
3
|
+
|
|
4
|
+
module Up
|
|
5
|
+
module CLI
|
|
6
|
+
class Options < OptionParser
|
|
7
|
+
attr_reader :options
|
|
8
|
+
def initialize
|
|
9
|
+
super
|
|
10
|
+
@options = {}
|
|
11
|
+
self.banner = 'Usage: up [options]'
|
|
12
|
+
separator ''
|
|
13
|
+
on('-h', '--help', 'Show this message') do
|
|
14
|
+
puts self
|
|
15
|
+
exit
|
|
16
|
+
end
|
|
17
|
+
on('-p', '--port PORT', String, 'Port number the server will listen to') do |port|
|
|
18
|
+
options[:port] = port.to_i
|
|
19
|
+
end
|
|
20
|
+
on('-b', '--bind ADDRESS', String, 'Address the server will listen to') do |host|
|
|
21
|
+
options[:host] = host
|
|
22
|
+
end
|
|
23
|
+
on('-s', '--secure', "Use secure sockets.\nWhen using secure sockets, the -a, -c and -k options must be provided") do
|
|
24
|
+
options[:scheme] = 'https'
|
|
25
|
+
end
|
|
26
|
+
on('-a', '--ca-file FILE', String, 'File with CA certs') do |ca_file|
|
|
27
|
+
options[:ca_file] = ca_file
|
|
28
|
+
end
|
|
29
|
+
on('-c', '--cert-file FILE', String, 'File with the servers certificate') do |cert_file|
|
|
30
|
+
options[:cert_file] = cert_file
|
|
31
|
+
end
|
|
32
|
+
on('-k', '--key-file FILE', String, 'File with the servers certificate') do |key_file|
|
|
33
|
+
options[:key_file] = key_file
|
|
34
|
+
end
|
|
35
|
+
on('-v', '--version', 'Show version') do
|
|
36
|
+
puts "Up! v#{Up::VERSION}"
|
|
37
|
+
exit
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def parse!
|
|
42
|
+
super
|
|
43
|
+
if options[:scheme] == 'https'
|
|
44
|
+
if !options[:ca_file] || !options[:cert_file] || !options[:key_file]
|
|
45
|
+
puts "When using -s or --secure the -a,-c- and -k options must be given too!"
|
|
46
|
+
exit 2
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
if RUBY_ENGINE != 'opal'
|
|
54
|
+
def setup_bun
|
|
55
|
+
bun_cmd = `which bun`
|
|
56
|
+
if !bun_cmd || bun_cmd.empty?
|
|
57
|
+
puts "Please install bun first!"
|
|
58
|
+
exit 2
|
|
59
|
+
end
|
|
60
|
+
true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def setup_node
|
|
64
|
+
node_cmd = `which node`
|
|
65
|
+
if !node_cmd || node_cmd.empty?
|
|
66
|
+
puts "Please install node first!"
|
|
67
|
+
exit 2
|
|
68
|
+
end
|
|
69
|
+
true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def setup_u_web_socket
|
|
73
|
+
setup_node
|
|
74
|
+
npm_cmd = `which npm`
|
|
75
|
+
if !npm_cmd || npm_cmd.empty?
|
|
76
|
+
puts "Please install npm first!"
|
|
77
|
+
exit 2
|
|
78
|
+
end
|
|
79
|
+
npm_cmd.chop! if npm_cmd.end_with?("\n")
|
|
80
|
+
have_uws = `npm list|grep uWebSockets.js@20`
|
|
81
|
+
`npm i uNetworking/uWebSockets.js#v20.41.0` if have_uws.empty?
|
|
82
|
+
true
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def get_options
|
|
87
|
+
options = Up::CLI::Options.new
|
|
88
|
+
options.parse!
|
|
89
|
+
options.options
|
|
90
|
+
rescue OptionParser::InvalidOption => e
|
|
91
|
+
$stderr.puts "#{$0}: #{e.message} (-h will show valid options)"
|
|
92
|
+
exit 64
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_gems_for_cmd
|
|
96
|
+
# Opal does not yet support gems, so lets read the Gemfile and simply add each gem
|
|
97
|
+
# to the Opal load path and require it, works for some gems, fails for others
|
|
98
|
+
gems = ""
|
|
99
|
+
if File.exist?("Gemfile")
|
|
100
|
+
lines = File.readlines('Gemfile')
|
|
101
|
+
lines.each do |line|
|
|
102
|
+
m = /gem ['"](\w+)['"]/.match(line)
|
|
103
|
+
gems << " -g #{m[1]} -r #{m[1]}" if m && m[1] != 'opal-up'
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
gems
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def try_file(filename)
|
|
110
|
+
return nil unless File.exist? filename
|
|
111
|
+
::Rack::Builder.parse_file filename
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def get_app(filename = 'config.ru')
|
|
115
|
+
app = nil
|
|
116
|
+
filename ||= 'config.ru'
|
|
117
|
+
app = try_file(filename)
|
|
118
|
+
unless app
|
|
119
|
+
filename = "#{filename}.ru"
|
|
120
|
+
app = try_file(filename)
|
|
121
|
+
end
|
|
122
|
+
raise "Something wrong with #{filename}\n" unless app
|
|
123
|
+
app
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def stoppable?
|
|
127
|
+
sleep 0.1
|
|
128
|
+
puts 'deflating request chain links'
|
|
129
|
+
sleep 0.1
|
|
130
|
+
puts 'optimizing response distortion'
|
|
131
|
+
sleep 0.1
|
|
132
|
+
print 'releasing boost pressure: '
|
|
133
|
+
3.times do
|
|
134
|
+
sleep 0.2
|
|
135
|
+
print '.'
|
|
136
|
+
end
|
|
137
|
+
3.times do
|
|
138
|
+
puts "\n\033[5;31;47mRED ALERT: boost pressure to high, cannot open release valve!1!!!\033[0m"
|
|
139
|
+
sleep 0.1
|
|
140
|
+
print '.'
|
|
141
|
+
sleep 0.1
|
|
142
|
+
end
|
|
143
|
+
puts 'stopping engines failed, for further help see:'
|
|
144
|
+
puts 'https://www.youtube.com/watch?v=ecBco63zvas'
|
|
145
|
+
sleep 0.2
|
|
146
|
+
puts "Just kidding :)"
|
|
147
|
+
true
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# backtick_javascript: true
|
|
2
|
+
require 'up/node/server'
|
|
3
|
+
|
|
4
|
+
%x{
|
|
5
|
+
const cluster = require('node:cluster');
|
|
6
|
+
const num_workers = require('node:os').availableParallelism();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module Up
|
|
10
|
+
module Node
|
|
11
|
+
class Cluster < Up::Node::Server
|
|
12
|
+
def initialize(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil, workers: nil)
|
|
13
|
+
super(app: app, host: host, port: port, scheme: scheme, ca_file: ca_file, cert_file: cert_file, key_file: key_file)
|
|
14
|
+
@workers = workers || `num_workers`
|
|
15
|
+
@members = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def listen
|
|
19
|
+
raise "already running" unless @members.empty?
|
|
20
|
+
%x{
|
|
21
|
+
if (cluster.isPrimary) {
|
|
22
|
+
for (let i = 0; i < #@workers; i++) {
|
|
23
|
+
#@members.push(cluster.fork());
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
#{super}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def stop
|
|
32
|
+
if Up::CLI::stoppable?
|
|
33
|
+
@members.each { |m| `m.kill()` }
|
|
34
|
+
@members.clear
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
require 'up/node/rack_cluster'
|
|
8
|
+
|
|
9
|
+
module Up
|
|
10
|
+
module CLI
|
|
11
|
+
def self.call
|
|
12
|
+
Up::Node::RackCluster.run(get_app, get_options)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'up/node/cluster'
|
|
2
|
+
|
|
3
|
+
module Up
|
|
4
|
+
module Node
|
|
5
|
+
module RackCluster
|
|
6
|
+
def self.run(app, options = {})
|
|
7
|
+
raise "already running" if @server
|
|
8
|
+
@server = Up::Node::Cluster.new(app: app, **options).listen
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.shutdown
|
|
13
|
+
@server&.stop
|
|
14
|
+
@server = nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
ENV['RACK_HANDLER'] ||= 'up'
|
|
21
|
+
|
|
22
|
+
begin
|
|
23
|
+
::Rackup::Handler.register('up', Up::Node::RackCluster) if defined?(::Rackup::Handler)
|
|
24
|
+
rescue StandardError
|
|
25
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# backtick_javascript: true
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
require 'up/version'
|
|
5
|
+
|
|
6
|
+
module Up
|
|
7
|
+
module Node
|
|
8
|
+
class RackEnv < ::Hash
|
|
9
|
+
RACK_VARS = %w[rack.errors rack.hijack rack.hijack? rack.input rack.logger
|
|
10
|
+
rack.multipart.buffer_size rack.multipart.tempfile_factory
|
|
11
|
+
rack.response_finished
|
|
12
|
+
rack.session rack.upgrade rack.upgrade? rack.url_scheme
|
|
13
|
+
HTTP_ACCEPT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE
|
|
14
|
+
HTTP_CONNECTION HTTP_HOST HTTP_USER_AGENT HTTP_VERSION PATH_INFO QUERY_STRING REQUEST_METHOD
|
|
15
|
+
SCRIPT_NAME SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE]
|
|
16
|
+
def initialize(req, config)
|
|
17
|
+
@req = req
|
|
18
|
+
@config = config
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def [](key)
|
|
22
|
+
return super(key) if key?(key)
|
|
23
|
+
self[key] = case key
|
|
24
|
+
when 'rack.errors'
|
|
25
|
+
STDERR
|
|
26
|
+
when 'rack.hijack'
|
|
27
|
+
nil
|
|
28
|
+
when 'rack.hijack?'
|
|
29
|
+
false
|
|
30
|
+
when 'rack.input'
|
|
31
|
+
::IO.new
|
|
32
|
+
when 'rack.logger'
|
|
33
|
+
::Logger.new(self['rack.errors'])
|
|
34
|
+
when 'rack.multipart.buffer_size'
|
|
35
|
+
4096
|
|
36
|
+
when 'rack.multipart.tempfile_factory'
|
|
37
|
+
proc { |_filename, _content_type| File.new }
|
|
38
|
+
when 'rack.response_finished'
|
|
39
|
+
[]
|
|
40
|
+
when 'rack.session'
|
|
41
|
+
{}
|
|
42
|
+
when 'rack.upgrade'
|
|
43
|
+
nil
|
|
44
|
+
when 'rack.upgrade?'
|
|
45
|
+
nil
|
|
46
|
+
when 'rack.url_scheme'
|
|
47
|
+
@config[:scheme]
|
|
48
|
+
when 'HTTP_VERSION'
|
|
49
|
+
`#@req.httpVersion`
|
|
50
|
+
when 'PATH_INFO'
|
|
51
|
+
`#@req.url`
|
|
52
|
+
when 'QUERY_STRING'
|
|
53
|
+
nil
|
|
54
|
+
when 'RACK_ERRORS'
|
|
55
|
+
self['rack.errors']
|
|
56
|
+
when 'RACK_LOGGER'
|
|
57
|
+
self['rack.logger']
|
|
58
|
+
when 'REQUEST_METHOD'
|
|
59
|
+
`#@req.method`
|
|
60
|
+
when 'SCRIPT_NAME'
|
|
61
|
+
""
|
|
62
|
+
when 'SERVER_NAME'
|
|
63
|
+
@config[:host]
|
|
64
|
+
when 'SERVER_PORT'
|
|
65
|
+
@config[:port].to_s
|
|
66
|
+
when 'SERVER_PROTOCOL'
|
|
67
|
+
""
|
|
68
|
+
when 'SERVER_SOFTWARE'
|
|
69
|
+
"#{@config[:handler]}/#{Up::VERSION} #{@config[:engine]}"
|
|
70
|
+
else
|
|
71
|
+
if key.start_with?('HTTP_')
|
|
72
|
+
key = key[5..].gsub(/_/, '-')
|
|
73
|
+
`#@req.headers[key.toLowerCase()]`
|
|
74
|
+
else
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def req_headers
|
|
81
|
+
h = {}
|
|
82
|
+
%x{
|
|
83
|
+
var hdr, hds = #@req.headers;
|
|
84
|
+
for (hdr in hds) { h.set(hdr, hdrs[hdr]); }
|
|
85
|
+
}
|
|
86
|
+
h
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def each
|
|
90
|
+
unless @got_them_all
|
|
91
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
|
92
|
+
@got_them_all = true
|
|
93
|
+
end
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def to_s
|
|
98
|
+
unless @got_them_all
|
|
99
|
+
RACK_VARS.each { |k| self[k] unless self.key?(k) }
|
|
100
|
+
@got_them_all = true
|
|
101
|
+
end
|
|
102
|
+
super
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'up/node/server'
|
|
2
|
+
|
|
3
|
+
module Up
|
|
4
|
+
module Node
|
|
5
|
+
module RackServer
|
|
6
|
+
def self.run(app, options = {})
|
|
7
|
+
raise "already running" if @server
|
|
8
|
+
@server = Up::Node::Server.new(app: app, **options).listen
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.shutdown
|
|
13
|
+
@server&.stop
|
|
14
|
+
@server = nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
ENV['RACK_HANDLER'] ||= 'up'
|
|
21
|
+
|
|
22
|
+
begin
|
|
23
|
+
::Rackup::Handler.register('up', Up::Node::RackServer) if defined?(::Rackup::Handler)
|
|
24
|
+
rescue StandardError
|
|
25
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# backtick_javascript: true
|
|
2
|
+
require 'up/cli'
|
|
3
|
+
require 'up/node/rack_env'
|
|
4
|
+
|
|
5
|
+
%x{
|
|
6
|
+
module.paths.push(process.cwd() + '/node_modules');
|
|
7
|
+
const http = require('node:http');
|
|
8
|
+
const https = require('node:https');
|
|
9
|
+
const fs = require('node:fs');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module Up
|
|
13
|
+
module Node
|
|
14
|
+
class Server
|
|
15
|
+
def initialize(app:, host: 'localhost', port: 3000, scheme: 'http', ca_file: nil, cert_file: nil, key_file: nil)
|
|
16
|
+
@app = app
|
|
17
|
+
@scheme = scheme || 'http'
|
|
18
|
+
raise "unsupported scheme #{@scheme}" unless %w[http https].include?(@scheme)
|
|
19
|
+
@host = host || 'localhost'
|
|
20
|
+
@port = port&.to_i || 3000
|
|
21
|
+
@config = { handler: self.class.name, engine: "node/#{`process.version`}", port: port, scheme: scheme, host: host }.freeze
|
|
22
|
+
@ca_file = ca_file
|
|
23
|
+
@cert_file = cert_file
|
|
24
|
+
@key_file = key_file
|
|
25
|
+
@server = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
%x{
|
|
29
|
+
self.handle_headers = function(rack_headers, srv_res) {
|
|
30
|
+
if (rack_headers.$$is_hash) {
|
|
31
|
+
var header, k, v;
|
|
32
|
+
for(header of rack_headers) {
|
|
33
|
+
k = header[0];
|
|
34
|
+
if (!k.startsWith('rack.')) {
|
|
35
|
+
v = header[1];
|
|
36
|
+
if (v.$$is_array) {
|
|
37
|
+
v = v.join("\n");
|
|
38
|
+
}
|
|
39
|
+
srv_res.setHeader(k, v);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
self.handle_response = function(parts, srv_res) {
|
|
46
|
+
if (parts["$respond_to?"]('each')) {
|
|
47
|
+
#{`parts`.each { |part| `srv_res.write(part)` }}
|
|
48
|
+
} else if (parts["$respond_to?"]('call')) {
|
|
49
|
+
srv_res.write(parts.$call());
|
|
50
|
+
}
|
|
51
|
+
#{`parts`.close if `parts`.respond_to?(:close)}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
def listen
|
|
56
|
+
raise "already running" if @server
|
|
57
|
+
%x{
|
|
58
|
+
const ounr = Opal.Up.Node.RackEnv;
|
|
59
|
+
const ouns = Opal.Up.Node.Server;
|
|
60
|
+
function handler(req, res) {
|
|
61
|
+
const rack_res = #@app.$call(ounr.$new(req, #@config));
|
|
62
|
+
res.statusCode = rack_res[0];
|
|
63
|
+
ouns.handle_headers(rack_res[1], res);
|
|
64
|
+
ouns.handle_response(rack_res[2], res);
|
|
65
|
+
res.end();
|
|
66
|
+
}
|
|
67
|
+
if (#@scheme == 'https') {
|
|
68
|
+
#@server = https.createServer({ ca: fs.readFileSync(#@ca_file), cert: fs.readFileSync(#@cert_file), key: fs.readFileSync(#@key_file) }, handler);
|
|
69
|
+
} else {
|
|
70
|
+
#@server = http.createServer(handler);
|
|
71
|
+
}
|
|
72
|
+
#@server.listen(#@port, #@host, () => { console.log(`Server is running on ${#@scheme}://${#@host}:${#@port}`)});
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def stop
|
|
77
|
+
if Up::CLI::stoppable?
|
|
78
|
+
`#@server.close()`
|
|
79
|
+
@server = nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
require 'up/node/rack_server'
|
|
8
|
+
|
|
9
|
+
module Up
|
|
10
|
+
module CLI
|
|
11
|
+
def self.call
|
|
12
|
+
Up::Node::RackServer.run(get_app, get_options)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'up/ruby/rack_env'
|
|
2
|
+
require 'up_ext'
|
|
3
|
+
|
|
4
|
+
module Up
|
|
5
|
+
module Ruby
|
|
6
|
+
module RackCluster
|
|
7
|
+
def self.run(app, options = {})
|
|
8
|
+
raise "already running" if @server
|
|
9
|
+
@server = Up::Ruby::Cluster.new(app: app, **options).listen
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.shutdown
|
|
14
|
+
@server&.stop
|
|
15
|
+
@server = nil
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
ENV['RACK_HANDLER'] ||= 'up'
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
::Rackup::Handler.register('up', Up::Ruby::RackCluster) if defined?(::Rackup::Handler)
|
|
25
|
+
rescue StandardError
|
|
26
|
+
end
|