tipi 0.30 → 0.31
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/CHANGELOG.md +6 -0
- data/Gemfile.lock +4 -4
- data/README.md +9 -3
- data/bin/tipi +9 -8
- data/docs/tipi-logo.png +0 -0
- data/examples/hello.ru +9 -0
- data/examples/http_server_forked.rb +1 -1
- data/examples/https_server_forked.rb +2 -2
- data/examples/rack_server.rb +1 -1
- data/examples/websocket_client.rb +65 -0
- data/examples/websocket_demo.rb +84 -0
- data/examples/websocket_server.rb +2 -1
- data/lib/tipi.rb +1 -0
- data/lib/tipi/configuration.rb +56 -0
- data/lib/tipi/handler.rb +35 -0
- data/lib/tipi/rack_adapter.rb +33 -22
- data/lib/tipi/version.rb +1 -1
- data/lib/tipi/websocket.rb +0 -2
- data/test/helper.rb +1 -1
- data/test/test_http_server.rb +2 -9
- data/tipi.gemspec +1 -1
- metadata +11 -6
- data/docs/summary.md +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8eb4db3e433119acc5b10688d6a558de425f8f4b390bbd280055bd9429acde60
|
4
|
+
data.tar.gz: 90f6dfc0ba6b99acb8b3d251845774f146641bbc922cd5b25658a7bf3fc97ef1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80aa5c2464a8812b79dc6fa15c0230dde2bb839f66737b1fac03f8c7d51fbf1bc6ba3f7f1ad1bc6882f6ad8184ecb614b44dd43cdc67a403ae30dac541137579
|
7
|
+
data.tar.gz: 8e77ba6c910898761ef63f435ad70e8bcd0f3f7ff14f5e86be2ea675c9387affa191a6ccc0c5f44565b6b8d1ea661606eb2e8a5c4cbb0ac4ed9119fa26828e27
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tipi (0.
|
4
|
+
tipi (0.31)
|
5
5
|
http-2 (~> 0.10.0)
|
6
6
|
http_parser.rb (~> 0.6.0)
|
7
|
-
polyphony (~> 0.
|
7
|
+
polyphony (~> 0.44)
|
8
8
|
rack (>= 2.0.8, < 2.3.0)
|
9
9
|
websocket (~> 1.2.8)
|
10
10
|
|
@@ -16,7 +16,7 @@ GEM
|
|
16
16
|
docile (1.3.2)
|
17
17
|
http-2 (0.10.2)
|
18
18
|
http_parser.rb (0.6.0)
|
19
|
-
json (2.1
|
19
|
+
json (2.3.1)
|
20
20
|
localhost (1.1.4)
|
21
21
|
minitest (5.11.3)
|
22
22
|
minitest-reporters (1.4.2)
|
@@ -24,7 +24,7 @@ GEM
|
|
24
24
|
builder
|
25
25
|
minitest (>= 5.0)
|
26
26
|
ruby-progressbar
|
27
|
-
polyphony (0.
|
27
|
+
polyphony (0.44.0)
|
28
28
|
rack (2.2.3)
|
29
29
|
rake (12.3.3)
|
30
30
|
ruby-progressbar (1.10.1)
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
<p align="center"><img src="docs/tipi-logo.png" /></p>
|
2
|
+
|
1
3
|
# Tipi - the All-in-one Web Server for Ruby Apps
|
2
4
|
|
3
5
|
[](http://rubygems.org/gems/tipi)
|
@@ -14,9 +16,13 @@ reverse-proxy such as Nginx.
|
|
14
16
|
|
15
17
|
## Features
|
16
18
|
|
17
|
-
*
|
18
|
-
|
19
|
-
|
19
|
+
* High-performance, highly concurrent web server based on
|
20
|
+
[Polyphony](https://github.com/digital-fabric/polyphony)
|
21
|
+
* Full support for HTTP, HTTP/2, WebSocket protocols
|
22
|
+
* Built-in SSL termination for secure, encrypted connections
|
23
|
+
* Automatic ALPN protocol selection
|
24
|
+
* Request and response body streaming for efficient downloads and uploads
|
25
|
+
* Full support for Rack-based apps
|
20
26
|
|
21
27
|
## Documentation
|
22
28
|
|
data/bin/tipi
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require File.expand_path('../lib/tipi/configuration', __dir__)
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
opts = { reuse_addr: true, dont_linger: true }
|
7
|
+
config = {}
|
8
|
+
#config[:forked] = 4
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
configuration_manager = spin { Tipi::Configuration.supervise_config }
|
11
|
+
|
12
|
+
configuration_manager << config
|
13
|
+
configuration_manager.await
|
data/docs/tipi-logo.png
ADDED
Binary file
|
data/examples/hello.ru
ADDED
@@ -13,7 +13,7 @@ opts = {
|
|
13
13
|
secure_context: authority.server_context
|
14
14
|
}
|
15
15
|
|
16
|
-
server =
|
16
|
+
server = Tipi.listen('0.0.0.0', 1234, opts)
|
17
17
|
|
18
18
|
puts 'Listening on port 1234'
|
19
19
|
|
@@ -29,4 +29,4 @@ child_pids = []
|
|
29
29
|
child_pids << pid
|
30
30
|
end
|
31
31
|
|
32
|
-
child_pids.each { |pid| Thread.current.
|
32
|
+
child_pids.each { |pid| Thread.current.backend.waitpid(pid) }
|
data/examples/rack_server.rb
CHANGED
@@ -4,7 +4,7 @@ require 'bundler/setup'
|
|
4
4
|
require 'tipi'
|
5
5
|
|
6
6
|
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
7
|
-
app =
|
7
|
+
app = Tipi::RackAdapter.load(app_path)
|
8
8
|
opts = { reuse_addr: true, dont_linger: true }
|
9
9
|
|
10
10
|
puts 'listening on port 1234'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'websocket'
|
6
|
+
|
7
|
+
::Exception.__disable_sanitized_backtrace__ = true
|
8
|
+
|
9
|
+
class WebsocketClient
|
10
|
+
def initialize(url, headers = {})
|
11
|
+
@socket = TCPSocket.new('127.0.0.1', 1234)
|
12
|
+
do_handshake(url, headers)
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_handshake(url, headers)
|
16
|
+
handshake = WebSocket::Handshake::Client.new(url: url, headers: headers)
|
17
|
+
@socket << handshake.to_s
|
18
|
+
@socket.read_loop do |data|
|
19
|
+
handshake << data
|
20
|
+
break if handshake.finished?
|
21
|
+
end
|
22
|
+
raise 'Websocket handshake failed' unless handshake.valid?
|
23
|
+
@version = handshake.version
|
24
|
+
|
25
|
+
@reader = WebSocket::Frame::Incoming::Client.new(version: @version)
|
26
|
+
end
|
27
|
+
|
28
|
+
def receive
|
29
|
+
loop do
|
30
|
+
data = @socket.readpartial(8192)
|
31
|
+
@reader << data
|
32
|
+
parsed = @reader.next
|
33
|
+
return parsed if parsed
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def send(data)
|
38
|
+
frame = WebSocket::Frame::Outgoing::Client.new(
|
39
|
+
version: @version,
|
40
|
+
data: data,
|
41
|
+
type: :text
|
42
|
+
)
|
43
|
+
@socket << frame.to_s
|
44
|
+
end
|
45
|
+
alias_method :<<, :send
|
46
|
+
|
47
|
+
def close
|
48
|
+
@socket.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
(1..3).each do |i|
|
54
|
+
spin do
|
55
|
+
client = WebsocketClient.new('ws://127.0.0.1:1234/', { Cookie: "SESSIONID=#{i * 10}" })
|
56
|
+
(1..3).each do |j|
|
57
|
+
sleep rand(0.2..0.5)
|
58
|
+
client.send "Hello from client #{i} (#{j})"
|
59
|
+
puts "server reply: #{client.receive}"
|
60
|
+
end
|
61
|
+
client.close
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
suspend
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/inline'
|
4
|
+
|
5
|
+
gemfile do
|
6
|
+
source 'https://rubygems.org'
|
7
|
+
gem 'polyphony', '~> 0.44'
|
8
|
+
gem 'tipi', '~> 0.31'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'tipi/websocket'
|
12
|
+
|
13
|
+
class WebsocketClient
|
14
|
+
def initialize(url, headers = {})
|
15
|
+
@socket = TCPSocket.new('127.0.0.1', 1234)
|
16
|
+
do_handshake(url, headers)
|
17
|
+
end
|
18
|
+
|
19
|
+
def do_handshake(url, headers)
|
20
|
+
handshake = WebSocket::Handshake::Client.new(url: url, headers: headers)
|
21
|
+
@socket << handshake.to_s
|
22
|
+
@socket.read_loop do |data|
|
23
|
+
handshake << data
|
24
|
+
break if handshake.finished?
|
25
|
+
end
|
26
|
+
raise 'Websocket handshake failed' unless handshake.valid?
|
27
|
+
@version = handshake.version
|
28
|
+
|
29
|
+
@reader = WebSocket::Frame::Incoming::Client.new(version: @version)
|
30
|
+
end
|
31
|
+
|
32
|
+
def receive
|
33
|
+
loop do
|
34
|
+
data = @socket.readpartial(8192)
|
35
|
+
@reader << data
|
36
|
+
parsed = @reader.next
|
37
|
+
return parsed if parsed
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def send(data)
|
42
|
+
frame = WebSocket::Frame::Outgoing::Client.new(
|
43
|
+
version: @version,
|
44
|
+
data: data,
|
45
|
+
type: :text
|
46
|
+
)
|
47
|
+
@socket << frame.to_s
|
48
|
+
end
|
49
|
+
alias_method :<<, :send
|
50
|
+
|
51
|
+
def close
|
52
|
+
@socket.close
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
server = spin do
|
57
|
+
websocket_handler = Tipi::Websocket.handler do |conn|
|
58
|
+
while (msg = conn.recv)
|
59
|
+
conn << "you said: #{msg}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
opts = { upgrade: { websocket: websocket_handler } }
|
64
|
+
puts 'Listening on port http://127.0.0.1:1234/'
|
65
|
+
Tipi.serve('0.0.0.0', 1234, opts) do |req|
|
66
|
+
req.respond("Hello world!\n")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
sleep 0.01 # wait for server to start
|
71
|
+
|
72
|
+
clients = (1..3).map do |i|
|
73
|
+
spin do
|
74
|
+
client = WebsocketClient.new('ws://127.0.0.1:1234/', { Cookie: "SESSIONID=#{i * 10}" })
|
75
|
+
(1..3).each do |j|
|
76
|
+
sleep rand(0.2..0.5)
|
77
|
+
client.send "Hello from client #{i} (#{j})"
|
78
|
+
puts "server reply: #{client.receive}"
|
79
|
+
end
|
80
|
+
client.close
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Fiber.await(*clients)
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'tipi'
|
5
|
+
require 'tipi/websocket'
|
5
6
|
|
6
7
|
def ws_handler(conn)
|
7
8
|
while (msg = conn.recv)
|
@@ -13,7 +14,7 @@ opts = {
|
|
13
14
|
reuse_addr: true,
|
14
15
|
dont_linger: true,
|
15
16
|
upgrade: {
|
16
|
-
websocket:
|
17
|
+
websocket: Tipi::Websocket.handler(&method(:ws_handler))
|
17
18
|
}
|
18
19
|
}
|
19
20
|
|
data/lib/tipi.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './handler'
|
4
|
+
|
5
|
+
module Tipi
|
6
|
+
module Configuration
|
7
|
+
class << self
|
8
|
+
def supervise_config
|
9
|
+
current_runner = nil
|
10
|
+
while (config = receive)
|
11
|
+
old_runner, current_runner = current_runner, spin { run(config) }
|
12
|
+
old_runner&.stop
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(config)
|
17
|
+
start_listeners(config)
|
18
|
+
config[:forked] ? forked_supervise(config) : simple_supervise(config)
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_listeners(config)
|
22
|
+
puts "listening on port 1234"
|
23
|
+
@server = Polyphony::Net.tcp_listen('0.0.0.0', 1234, { reuse_addr: true, dont_linger: true })
|
24
|
+
end
|
25
|
+
|
26
|
+
def simple_supervise(config)
|
27
|
+
virtual_hosts = setup_virtual_hosts(config)
|
28
|
+
start_acceptors(config, virtual_hosts)
|
29
|
+
suspend
|
30
|
+
# supervise(restart: true)
|
31
|
+
end
|
32
|
+
|
33
|
+
def forked_supervise(config)
|
34
|
+
config[:forked].times do
|
35
|
+
spin { Polyphony.watch_process { simple_supervise(config) } }
|
36
|
+
end
|
37
|
+
suspend
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup_virtual_hosts(config)
|
41
|
+
{
|
42
|
+
'*': Tipi::DefaultHandler.new(config)
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_acceptors(config, virtual_hosts)
|
47
|
+
spin do
|
48
|
+
puts "pid: #{Process.pid}"
|
49
|
+
while (connection = @server.accept)
|
50
|
+
spin { virtual_hosts[:'*'].call(connection) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/tipi/handler.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './rack_adapter'
|
4
|
+
require_relative './http1_adapter'
|
5
|
+
require_relative './http2_adapter'
|
6
|
+
|
7
|
+
module Tipi
|
8
|
+
class DefaultHandler
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
|
12
|
+
app_path = ARGV.first || './config.ru'
|
13
|
+
@app = Tipi::RackAdapter.load(app_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(socket)
|
17
|
+
socket.no_delay if socket.respond_to?(:no_delay)
|
18
|
+
adapter = protocol_adapter(socket, {})
|
19
|
+
adapter.each(&@app)
|
20
|
+
ensure
|
21
|
+
socket.close
|
22
|
+
end
|
23
|
+
|
24
|
+
ALPN_PROTOCOLS = %w[h2 http/1.1].freeze
|
25
|
+
H2_PROTOCOL = 'h2'
|
26
|
+
|
27
|
+
def protocol_adapter(socket, opts)
|
28
|
+
use_http2 = socket.respond_to?(:alpn_protocol) &&
|
29
|
+
socket.alpn_protocol == H2_PROTOCOL
|
30
|
+
|
31
|
+
klass = use_http2 ? HTTP2Adapter : HTTP1Adapter
|
32
|
+
klass.new(socket, opts)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/tipi/rack_adapter.rb
CHANGED
@@ -31,30 +31,41 @@ module Tipi
|
|
31
31
|
src = IO.read(path)
|
32
32
|
instance_eval(src, path, 1)
|
33
33
|
end
|
34
|
+
|
35
|
+
RACK_ENV = {
|
36
|
+
'SCRIPT_NAME' => '',
|
37
|
+
'rack.version' => Rack::VERSION,
|
38
|
+
'SERVER_PORT' => '80', # ?
|
39
|
+
'rack.url_scheme' => 'http', # ?
|
40
|
+
'rack.errors' => STDERR, # ?
|
41
|
+
'rack.multithread' => false,
|
42
|
+
'rack.run_once' => false,
|
43
|
+
'rack.hijack?' => false,
|
44
|
+
'rack.hijack' => nil,
|
45
|
+
'rack.hijack_io' => nil,
|
46
|
+
'rack.session' => nil,
|
47
|
+
'rack.logger' => nil,
|
48
|
+
'rack.multipart.buffer_size' => nil,
|
49
|
+
'rack.multipar.tempfile_factory' => nil
|
50
|
+
}
|
34
51
|
|
35
52
|
def env(request)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
'rack.session' => nil,
|
53
|
-
'rack.logger' => nil,
|
54
|
-
'rack.multipart.buffer_size' => nil,
|
55
|
-
'rack.multipar.tempfile_factory' => nil
|
56
|
-
}.tap do |env|
|
57
|
-
request.headers.each { |k, v| env["HTTP_#{k.upcase}"] = v }
|
53
|
+
Hash.new do |h, k|
|
54
|
+
h[k] = env_value_from_request(request, k)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
HTTP_HEADER_RE = /^HTTP_(.+)$/.freeze
|
59
|
+
|
60
|
+
def env_value_from_request(request, key)
|
61
|
+
case key
|
62
|
+
when 'REQUEST_METHOD' then request.method
|
63
|
+
when 'PATH_INFO' then request.path
|
64
|
+
when 'QUERY_STRING' then request.query_string || ''
|
65
|
+
when 'SERVER_NAME' then request.headers['Host']
|
66
|
+
when 'rack.input' then InputStream.new(request)
|
67
|
+
when HTTP_HEADER_RE then request.headers[$1.downcase]
|
68
|
+
else RACK_ENV[key]
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
data/lib/tipi/version.rb
CHANGED
data/lib/tipi/websocket.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/test_http_server.rb
CHANGED
@@ -210,7 +210,6 @@ class HTTP1ServerTest < MiniTest::Test
|
|
210
210
|
opts = {
|
211
211
|
upgrade: {
|
212
212
|
echo: lambda do |conn, _headers|
|
213
|
-
p :echo1
|
214
213
|
conn << <<~HTTP.http_lines
|
215
214
|
HTTP/1.1 101 Switching Protocols
|
216
215
|
Upgrade: echo
|
@@ -218,13 +217,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
218
217
|
|
219
218
|
HTTP
|
220
219
|
|
221
|
-
|
222
|
-
data = conn.readpartial(8192)
|
223
|
-
conn << data
|
224
|
-
snooze
|
225
|
-
rescue EOFError
|
226
|
-
break
|
227
|
-
end
|
220
|
+
conn.read_loop { |data| conn << data }
|
228
221
|
done = true
|
229
222
|
end
|
230
223
|
}
|
@@ -277,7 +270,7 @@ class HTTP1ServerTest < MiniTest::Test
|
|
277
270
|
connection.close
|
278
271
|
assert !done
|
279
272
|
|
280
|
-
|
273
|
+
12.times { snooze }
|
281
274
|
assert done
|
282
275
|
end
|
283
276
|
|
data/tipi.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
|
20
20
|
s.executables = ['tipi']
|
21
21
|
|
22
|
-
s.add_runtime_dependency 'polyphony', '~>0.
|
22
|
+
s.add_runtime_dependency 'polyphony', '~>0.44'
|
23
23
|
|
24
24
|
s.add_runtime_dependency 'http_parser.rb', '~>0.6.0'
|
25
25
|
s.add_runtime_dependency 'http-2', '~>0.10.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tipi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.31'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: polyphony
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: '0.44'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: '0.44'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: http_parser.rb
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -175,9 +175,10 @@ files:
|
|
175
175
|
- TODO.md
|
176
176
|
- bin/tipi
|
177
177
|
- docs/README.md
|
178
|
-
- docs/
|
178
|
+
- docs/tipi-logo.png
|
179
179
|
- examples/cuba.ru
|
180
180
|
- examples/hanami-api.ru
|
181
|
+
- examples/hello.ru
|
181
182
|
- examples/http_server.js
|
182
183
|
- examples/http_server.rb
|
183
184
|
- examples/http_server_forked.rb
|
@@ -192,11 +193,15 @@ files:
|
|
192
193
|
- examples/rack_server.rb
|
193
194
|
- examples/rack_server_https.rb
|
194
195
|
- examples/rack_server_https_forked.rb
|
196
|
+
- examples/websocket_client.rb
|
197
|
+
- examples/websocket_demo.rb
|
195
198
|
- examples/websocket_secure_server.rb
|
196
199
|
- examples/websocket_server.rb
|
197
200
|
- examples/ws_page.html
|
198
201
|
- examples/wss_page.html
|
199
202
|
- lib/tipi.rb
|
203
|
+
- lib/tipi/configuration.rb
|
204
|
+
- lib/tipi/handler.rb
|
200
205
|
- lib/tipi/http1_adapter.rb
|
201
206
|
- lib/tipi/http2_adapter.rb
|
202
207
|
- lib/tipi/http2_stream.rb
|
@@ -234,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
234
239
|
- !ruby/object:Gem::Version
|
235
240
|
version: '0'
|
236
241
|
requirements: []
|
237
|
-
rubygems_version: 3.
|
242
|
+
rubygems_version: 3.1.2
|
238
243
|
signing_key:
|
239
244
|
specification_version: 4
|
240
245
|
summary: Tipi - the All-in-one Web Server for Ruby Apps
|
data/docs/summary.md
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
# Table of contents
|
2
|
-
|
3
|
-
* [Polyphony - Easy Concurrency for Ruby](../README.md)
|
4
|
-
|
5
|
-
## Getting Started
|
6
|
-
|
7
|
-
* [Installing](getting-started/installing.md)
|
8
|
-
* [Tutorial](getting-started/tutorial.md)
|
9
|
-
|
10
|
-
## Technical overview
|
11
|
-
|
12
|
-
* [Design Principles](technical-overview/design-principles.md)
|
13
|
-
* [Concurrency the Easy Way](technical-overview/concurrency.md)
|
14
|
-
* [How Fibers are Scheduled](technical-overview/fiber-scheduling.md)
|
15
|
-
* [Exception Handling](technical-overview/exception-handling.md)
|
16
|
-
* [Frequently Asked Questions](technical-overview/faq.md)
|
17
|
-
|
18
|
-
## How To
|
19
|
-
|
20
|
-
* [Make an echo server](howto/echo-server.md)
|
21
|
-
* [Make an HTTP server](howto/http-server.md)
|
22
|
-
* [Make a Websocket server](howto/websocket-server.md)
|
23
|
-
* [Use timers](howto/timers.md)
|
24
|
-
* [Throttle recurrent operations](howto/throttle.md)
|
25
|
-
* [Cancel ongoing operations](howto/cancel.md)
|
26
|
-
* [Control coprocesses](howto/coprocesses.md)
|
27
|
-
* [Synchronize concurrent operations](howto/synchronize.md)
|
28
|
-
* [Perform CPU-bound operations](howto/cpu-bound.md)
|
29
|
-
* [Control backpressure](howto/backpressure.md)
|
30
|
-
* [Fork worker processes](howto/worker-processes.md)
|
31
|
-
|
32
|
-
## Polyphony extensions
|
33
|
-
|
34
|
-
* [Postgresql](extensions/pg)
|
35
|
-
* [Redis](extensions/redis)
|
36
|
-
* [IRB](extensions/irb)
|
37
|
-
* [Throttlers](#)
|
38
|
-
* [Resource Pools](#)
|
39
|
-
* [Synchronisation](#)
|
40
|
-
* [Web Server](user-guide/web-server.md)
|
41
|
-
* [Websocket Server](#)
|
42
|
-
* [Reactor API](#)
|
43
|
-
|
44
|
-
## API Reference
|
45
|
-
|
46
|
-
* [Polyphony::CancelScope](#)
|
47
|
-
* [Polyphony::Coprocess](#)
|
48
|
-
* [Gyro](#)
|
49
|
-
* [Gyro::Async](#)
|
50
|
-
* [Gyro::Child](#)
|
51
|
-
* [Gyro::IO](#)
|
52
|
-
* [Gyro::Timer](#)
|
53
|
-
* [Kernel](#)
|
54
|
-
* [Polyphony](#)
|
55
|
-
* [Polyphony::Mutex](#)
|
56
|
-
* [Polyphony::Pulser](#)
|
57
|
-
* [Polyphony::ResourcePool](#)
|
58
|
-
* [Polyphony::Throttler](#)
|
59
|
-
|
60
|
-
## [Contributing to Polyphony](contributing.md)
|