tipi 0.40 → 0.45

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/test.yml +3 -1
  4. data/.gitignore +5 -1
  5. data/CHANGELOG.md +35 -0
  6. data/Gemfile +7 -1
  7. data/Gemfile.lock +55 -29
  8. data/README.md +184 -8
  9. data/Rakefile +1 -3
  10. data/benchmarks/bm_http1_parser.rb +85 -0
  11. data/bin/benchmark +37 -0
  12. data/bin/h1pd +6 -0
  13. data/bin/tipi +3 -21
  14. data/bm.png +0 -0
  15. data/df/agent.rb +1 -1
  16. data/df/sample_agent.rb +2 -2
  17. data/df/server.rb +16 -102
  18. data/df/server_utils.rb +175 -0
  19. data/examples/full_service.rb +13 -0
  20. data/examples/hello.rb +5 -0
  21. data/examples/http1_parser.rb +55 -0
  22. data/examples/http_server.js +1 -1
  23. data/examples/http_server.rb +15 -3
  24. data/examples/http_server_graceful.rb +1 -1
  25. data/examples/http_server_static.rb +6 -18
  26. data/examples/https_server.rb +41 -15
  27. data/examples/rack_server_forked.rb +26 -0
  28. data/examples/rack_server_https_forked.rb +1 -1
  29. data/examples/servername_cb.rb +37 -0
  30. data/examples/websocket_demo.rb +1 -1
  31. data/lib/tipi/acme.rb +315 -0
  32. data/lib/tipi/cli.rb +93 -0
  33. data/lib/tipi/config_dsl.rb +13 -13
  34. data/lib/tipi/configuration.rb +2 -2
  35. data/{e → lib/tipi/controller/bare_polyphony.rb} +0 -0
  36. data/lib/tipi/controller/bare_stock.rb +10 -0
  37. data/lib/tipi/controller/stock_http1_adapter.rb +15 -0
  38. data/lib/tipi/controller/web_polyphony.rb +351 -0
  39. data/lib/tipi/controller/web_stock.rb +631 -0
  40. data/lib/tipi/controller.rb +12 -0
  41. data/lib/tipi/digital_fabric/agent.rb +10 -8
  42. data/lib/tipi/digital_fabric/agent_proxy.rb +26 -12
  43. data/lib/tipi/digital_fabric/executive.rb +7 -3
  44. data/lib/tipi/digital_fabric/protocol.rb +19 -4
  45. data/lib/tipi/digital_fabric/request_adapter.rb +0 -4
  46. data/lib/tipi/digital_fabric/service.rb +84 -56
  47. data/lib/tipi/handler.rb +2 -2
  48. data/lib/tipi/http1_adapter.rb +86 -125
  49. data/lib/tipi/http2_adapter.rb +29 -16
  50. data/lib/tipi/http2_stream.rb +52 -56
  51. data/lib/tipi/rack_adapter.rb +2 -53
  52. data/lib/tipi/response_extensions.rb +2 -2
  53. data/lib/tipi/supervisor.rb +75 -0
  54. data/lib/tipi/version.rb +1 -1
  55. data/lib/tipi/websocket.rb +3 -3
  56. data/lib/tipi.rb +8 -5
  57. data/test/coverage.rb +2 -2
  58. data/test/helper.rb +60 -12
  59. data/test/test_http_server.rb +14 -41
  60. data/test/test_request.rb +2 -29
  61. data/tipi.gemspec +12 -8
  62. metadata +88 -28
  63. data/examples/automatic_certificate.rb +0 -193
@@ -4,69 +4,18 @@ require 'rack'
4
4
 
5
5
  module Tipi
6
6
  module RackAdapter
7
- # Implements a rack input stream:
8
- # https://www.rubydoc.info/github/rack/rack/master/file/SPEC#label-The+Input+Stream
9
- class InputStream
10
- def initialize(request)
11
- @request = request
12
- end
13
-
14
- def gets; end
15
-
16
- def read(length = nil, outbuf = nil); end
17
-
18
- def each(&block)
19
- @request.each_chunk(&block)
20
- end
21
-
22
- def rewind; end
23
- end
24
-
25
7
  class << self
26
8
  def run(app)
27
9
  ->(req) { respond(req, app.(env(req))) }
28
10
  end
29
-
11
+
30
12
  def load(path)
31
13
  src = IO.read(path)
32
14
  instance_eval(src, path, 1)
33
15
  end
34
16
 
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
- }
51
-
52
17
  def env(request)
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]
69
- end
18
+ Qeweney.rack_env_from_request(request)
70
19
  end
71
20
 
72
21
  def respond(request, (status_code, headers, body))
@@ -8,8 +8,8 @@ module Tipi
8
8
 
9
9
  def serve_io(io, opts)
10
10
  if !opts[:stat] || opts[:stat].size >= SPLICE_CHUNKS_SIZE_THRESHOLD
11
- @adapter.respond_from_io(self, io, opts[:headers])
12
- else
11
+ @adapter.respond_from_io(self, io, opts[:headers], opts[:chunk_size] || 2**14)
12
+ else
13
13
  respond(io.read, opts[:headers] || {})
14
14
  end
15
15
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'polyphony'
4
+ require 'json'
5
+
6
+ module Tipi
7
+ module Supervisor
8
+ class << self
9
+ def run(opts)
10
+ puts "Start supervisor pid: #{Process.pid}"
11
+ @opts = opts
12
+ @controller_watcher = start_controller_watcher
13
+ supervise_loop
14
+ end
15
+
16
+ def start_controller_watcher
17
+ spin do
18
+ cmd = controller_cmd
19
+ puts "Starting controller..."
20
+ pid = Kernel.spawn(*cmd)
21
+ @controller_pid = pid
22
+ puts "Controller pid: #{pid}"
23
+ _pid, status = Polyphony.backend_waitpid(pid)
24
+ puts "Controller has terminated with status: #{status.inspect}"
25
+ terminated = true
26
+ ensure
27
+ if pid && !terminated
28
+ puts "Terminate controller #{pid.inspect}"
29
+ Polyphony::Process.kill_process(pid)
30
+ end
31
+ Fiber.current.parent << pid
32
+ end
33
+ end
34
+
35
+ def controller_cmd
36
+ [
37
+ 'ruby',
38
+ File.join(__dir__, 'controller.rb'),
39
+ @opts.to_json
40
+ ]
41
+ end
42
+
43
+ def supervise_loop
44
+ this_fiber = Fiber.current
45
+ trap('SIGUSR2') { this_fiber << :replace_controller }
46
+ loop do
47
+ case (msg = receive)
48
+ when :replace_controller
49
+ replace_controller
50
+ when Integer
51
+ pid = msg
52
+ if pid == @controller_pid
53
+ puts 'Detected dead controller. Restarting...'
54
+ exit!
55
+ @controller_watcher.restart
56
+ end
57
+ else
58
+ raise "Invalid message received: #{msg.inspect}"
59
+ end
60
+ end
61
+ end
62
+
63
+ def replace_controller
64
+ puts "Replacing controller"
65
+ old_watcher = @controller_watcher
66
+ @controller_watcher = start_controller_watcher
67
+
68
+ # TODO: we'll want to get some kind of signal from the new controller once it's ready
69
+ sleep 1
70
+
71
+ old_watcher.terminate(true)
72
+ end
73
+ end
74
+ end
75
+ end
data/lib/tipi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tipi
4
- VERSION = '0.40'
4
+ VERSION = '0.45'
5
5
  end
@@ -20,12 +20,12 @@ module Tipi
20
20
  @version = headers['sec-websocket-version'].to_i
21
21
  @reader = ::WebSocket::Frame::Incoming::Server.new(version: @version)
22
22
  end
23
-
23
+
24
24
  def recv
25
25
  if (msg = @reader.next)
26
26
  return msg.to_s
27
27
  end
28
-
28
+
29
29
  @conn.recv_loop do |data|
30
30
  @reader << data
31
31
  if (msg = @reader.next)
@@ -48,7 +48,7 @@ module Tipi
48
48
  end
49
49
  end
50
50
  end
51
-
51
+
52
52
  OutgoingFrame = ::WebSocket::Frame::Outgoing::Server
53
53
 
54
54
  def send(data)
data/lib/tipi.rb CHANGED
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'polyphony'
4
+
4
5
  require_relative './tipi/http1_adapter'
5
6
  require_relative './tipi/http2_adapter'
6
7
  require_relative './tipi/configuration'
7
8
  require_relative './tipi/response_extensions'
9
+ require_relative './tipi/acme'
10
+
8
11
  require 'qeweney/request'
9
12
 
10
13
  class Qeweney::Request
@@ -14,7 +17,7 @@ end
14
17
  module Tipi
15
18
  ALPN_PROTOCOLS = %w[h2 http/1.1].freeze
16
19
  H2_PROTOCOL = 'h2'
17
-
20
+
18
21
  class << self
19
22
  def serve(host, port, opts = {}, &handler)
20
23
  opts[:alpn_protocols] = ALPN_PROTOCOLS
@@ -23,7 +26,7 @@ module Tipi
23
26
  ensure
24
27
  server&.close
25
28
  end
26
-
29
+
27
30
  def listen(host, port, opts = {})
28
31
  opts[:alpn_protocols] = ALPN_PROTOCOLS
29
32
  Polyphony::Net.tcp_listen(host, port, opts).tap do |socket|
@@ -32,7 +35,7 @@ module Tipi
32
35
  end
33
36
  end
34
37
  end
35
-
38
+
36
39
  def accept_loop(server, opts, &handler)
37
40
  server.accept_loop do |client|
38
41
  spin { client_loop(client, opts, &handler) }
@@ -40,7 +43,7 @@ module Tipi
40
43
  # disregard
41
44
  end
42
45
  end
43
-
46
+
44
47
  def client_loop(client, opts, &handler)
45
48
  client.no_delay if client.respond_to?(:no_delay)
46
49
  adapter = protocol_adapter(client, opts)
@@ -48,7 +51,7 @@ module Tipi
48
51
  ensure
49
52
  client.close rescue nil
50
53
  end
51
-
54
+
52
55
  def protocol_adapter(socket, opts)
53
56
  use_http2 = socket.respond_to?(:alpn_protocol) &&
54
57
  socket.alpn_protocol == H2_PROTOCOL
data/test/coverage.rb CHANGED
@@ -26,10 +26,10 @@ module Coverage
26
26
  @result = {}
27
27
  trace = TracePoint.new(:line) do |tp|
28
28
  next if tp.path =~ /\(/
29
-
29
+
30
30
  absolute = File.expand_path(tp.path)
31
31
  next unless LIB_FILES.include?(absolute)# =~ /^#{LIB_DIR}/
32
-
32
+
33
33
  @result[absolute] ||= relevant_lines_for_filename(absolute)
34
34
  @result[absolute][tp.lineno - 1] = 1
35
35
  end
data/test/helper.rb CHANGED
@@ -8,32 +8,29 @@ require_relative './eg'
8
8
  require_relative './coverage' if ENV['COVERAGE']
9
9
 
10
10
  require 'minitest/autorun'
11
- require 'minitest/reporters'
12
11
 
13
12
  require 'polyphony'
14
13
 
15
14
  ::Exception.__disable_sanitized_backtrace__ = true
16
15
 
17
- Minitest::Reporters.use! [
18
- Minitest::Reporters::SpecReporter.new
19
- ]
20
-
21
16
  class MiniTest::Test
22
17
  def setup
23
- # puts "* setup #{self.name}"
24
- if Fiber.current.children.size > 0
25
- puts "Children left: #{Fiber.current.children.inspect}"
26
- exit!
27
- end
18
+ # trace "* setup #{self.name}"
28
19
  Fiber.current.setup_main_fiber
29
20
  Fiber.current.instance_variable_set(:@auto_watcher, nil)
21
+ Thread.current.backend.finalize
30
22
  Thread.current.backend = Polyphony::Backend.new
31
23
  sleep 0
32
24
  end
33
25
 
34
26
  def teardown
35
- # puts "* teardown #{self.name.inspect} Fiber.current: #{Fiber.current.inspect}"
27
+ # trace "* teardown #{self.name}"
36
28
  Fiber.current.shutdown_all_children
29
+ if Fiber.current.children.size > 0
30
+ puts "Children left after #{self.name}: #{Fiber.current.children.inspect}"
31
+ exit!
32
+ end
33
+ Fiber.current.instance_variable_set(:@auto_watcher, nil)
37
34
  rescue => e
38
35
  puts e
39
36
  puts e.backtrace.join("\n")
@@ -47,4 +44,55 @@ module Kernel
47
44
  rescue Exception => e
48
45
  e
49
46
  end
50
- end
47
+
48
+ def trace(*args)
49
+ STDOUT.orig_write(format_trace(args))
50
+ end
51
+
52
+ def format_trace(args)
53
+ if args.first.is_a?(String)
54
+ if args.size > 1
55
+ format("%s: %p\n", args.shift, args)
56
+ else
57
+ format("%s\n", args.first)
58
+ end
59
+ else
60
+ format("%p\n", args.size == 1 ? args.first : args)
61
+ end
62
+ end
63
+ end
64
+
65
+ class IO
66
+ # Creates two mockup sockets for simulating server-client communication
67
+ def self.server_client_mockup
68
+ server_in, client_out = IO.pipe
69
+ client_in, server_out = IO.pipe
70
+
71
+ server_connection = mockup_connection(server_in, server_out, client_out)
72
+ client_connection = mockup_connection(client_in, client_out, server_out)
73
+
74
+ [server_connection, client_connection]
75
+ end
76
+
77
+ def self.mockup_connection(input, output, output2)
78
+ eg(
79
+ __parser_read_method__: ->() { :readpartial },
80
+ read: ->(*args) { input.read(*args) },
81
+ read_loop: ->(*args, &block) { input.read_loop(*args, &block) },
82
+ recv_loop: ->(*args, &block) { input.read_loop(*args, &block) },
83
+ readpartial: ->(*args) { input.readpartial(*args) },
84
+ recv: ->(*args) { input.readpartial(*args) },
85
+ '<<': ->(*args) { output.write(*args) },
86
+ write: ->(*args) { output.write(*args) },
87
+ close: -> { output.close },
88
+ eof?: -> { output2.closed? }
89
+ )
90
+ end
91
+ end
92
+
93
+ module Minitest::Assertions
94
+ def assert_in_range exp_range, act
95
+ msg = message(msg) { "Expected #{mu_pp(act)} to be in range #{mu_pp(exp_range)}" }
96
+ assert exp_range.include?(act), msg
97
+ end
98
+ end
@@ -4,38 +4,11 @@ require_relative 'helper'
4
4
  require 'tipi'
5
5
 
6
6
  class String
7
- def http_lines
7
+ def crlf_lines
8
8
  gsub "\n", "\r\n"
9
9
  end
10
10
  end
11
11
 
12
- class IO
13
- # Creates two mockup sockets for simulating server-client communication
14
- def self.server_client_mockup
15
- server_in, client_out = IO.pipe
16
- client_in, server_out = IO.pipe
17
-
18
- server_connection = mockup_connection(server_in, server_out, client_out)
19
- client_connection = mockup_connection(client_in, client_out, server_out)
20
-
21
- [server_connection, client_connection]
22
- end
23
-
24
- def self.mockup_connection(input, output, output2)
25
- eg(
26
- :read => ->(*args) { input.read(*args) },
27
- :read_loop => ->(*args, &block) { input.read_loop(*args, &block) },
28
- :recv_loop => ->(*args, &block) { input.read_loop(*args, &block) },
29
- :readpartial => ->(*args) { input.readpartial(*args) },
30
- :recv => ->(*args) { input.readpartial(*args) },
31
- :<< => ->(*args) { output.write(*args) },
32
- :write => ->(*args) { output.write(*args) },
33
- :close => -> { output.close },
34
- :eof? => -> { output2.closed? }
35
- )
36
- end
37
- end
38
-
39
12
  class HTTP1ServerTest < MiniTest::Test
40
13
  def teardown
41
14
  @server&.interrupt if @server&.alive?
@@ -60,7 +33,7 @@ class HTTP1ServerTest < MiniTest::Test
60
33
  connection << "GET / HTTP/1.0\r\n\r\n"
61
34
 
62
35
  response = connection.readpartial(8192)
63
- expected = <<~HTTP.chomp.http_lines.chomp
36
+ expected = <<~HTTP.chomp.crlf_lines.chomp
64
37
  HTTP/1.1 200
65
38
  Content-Length: 13
66
39
 
@@ -78,7 +51,7 @@ class HTTP1ServerTest < MiniTest::Test
78
51
  connection << "GET / HTTP/1.1\r\n\r\n"
79
52
 
80
53
  response = connection.readpartial(8192)
81
- expected = <<~HTTP.http_lines.chomp
54
+ expected = <<~HTTP.crlf_lines.chomp
82
55
  HTTP/1.1 200
83
56
  Content-Length: 13
84
57
 
@@ -100,7 +73,7 @@ class HTTP1ServerTest < MiniTest::Test
100
73
  connection << "GET / HTTP/1.1\r\n\r\n"
101
74
  response = connection.readpartial(8192)
102
75
  assert !connection.eof?
103
- expected = <<~HTTP.http_lines.chomp
76
+ expected = <<~HTTP.crlf_lines.chomp
104
77
  HTTP/1.1 200
105
78
  Content-Length: 2
106
79
 
@@ -127,7 +100,7 @@ class HTTP1ServerTest < MiniTest::Test
127
100
  sleep 0.01
128
101
  response = connection.readpartial(8192)
129
102
 
130
- expected = <<~HTTP.http_lines.chomp
103
+ expected = <<~HTTP.crlf_lines.chomp
131
104
  HTTP/1.1 200
132
105
  Content-Length: 13
133
106
 
@@ -152,7 +125,7 @@ class HTTP1ServerTest < MiniTest::Test
152
125
  req.finish
153
126
  end
154
127
 
155
- connection << <<~HTTP.http_lines
128
+ connection << <<~HTTP.crlf_lines
156
129
  POST / HTTP/1.1
157
130
  Transfer-Encoding: chunked
158
131
 
@@ -178,7 +151,7 @@ class HTTP1ServerTest < MiniTest::Test
178
151
 
179
152
  response = connection.readpartial(8192)
180
153
 
181
- expected = <<~HTTP.http_lines
154
+ expected = <<~HTTP.crlf_lines
182
155
  HTTP/1.1 200
183
156
  Transfer-Encoding: chunked
184
157
 
@@ -199,7 +172,7 @@ class HTTP1ServerTest < MiniTest::Test
199
172
  upgrade: {
200
173
  echo: lambda do |adapter, _headers|
201
174
  conn = adapter.conn
202
- conn << <<~HTTP.http_lines
175
+ conn << <<~HTTP.crlf_lines
203
176
  HTTP/1.1 101 Switching Protocols
204
177
  Upgrade: echo
205
178
  Connection: Upgrade
@@ -219,7 +192,7 @@ class HTTP1ServerTest < MiniTest::Test
219
192
  connection << "GET / HTTP/1.1\r\n\r\n"
220
193
  response = connection.readpartial(8192)
221
194
  assert !connection.eof?
222
- expected = <<~HTTP.http_lines.chomp
195
+ expected = <<~HTTP.crlf_lines.chomp
223
196
  HTTP/1.1 200
224
197
  Content-Length: 2
225
198
 
@@ -227,7 +200,7 @@ class HTTP1ServerTest < MiniTest::Test
227
200
  HTTP
228
201
  assert_equal(expected, response)
229
202
 
230
- connection << <<~HTTP.http_lines
203
+ connection << <<~HTTP.crlf_lines
231
204
  GET / HTTP/1.1
232
205
  Upgrade: echo
233
206
  Connection: upgrade
@@ -237,7 +210,7 @@ class HTTP1ServerTest < MiniTest::Test
237
210
  snooze
238
211
  response = connection.readpartial(8192)
239
212
  assert !connection.eof?
240
- expected = <<~HTTP.http_lines
213
+ expected = <<~HTTP.crlf_lines
241
214
  HTTP/1.1 101 Switching Protocols
242
215
  Upgrade: echo
243
216
  Connection: Upgrade
@@ -255,7 +228,7 @@ class HTTP1ServerTest < MiniTest::Test
255
228
 
256
229
  connection.close
257
230
  assert !done
258
-
231
+
259
232
  sleep 0.01
260
233
  assert done
261
234
  end
@@ -278,7 +251,7 @@ class HTTP1ServerTest < MiniTest::Test
278
251
  count = 0
279
252
 
280
253
  connection << "GET / HTTP/1.1\r\n\r\n"
281
-
254
+
282
255
  while (data = connection.read(chunk_size))
283
256
  response << data
284
257
  count += 1
@@ -286,7 +259,7 @@ class HTTP1ServerTest < MiniTest::Test
286
259
  end
287
260
 
288
261
  chunks = "#{chunk_size.to_s(16)}\n#{'*' * chunk_size}\n" * chunk_count
289
- expected = <<~HTTP.http_lines
262
+ expected = <<~HTTP.crlf_lines
290
263
  HTTP/1.1 200
291
264
  Transfer-Encoding: chunked
292
265
 
data/test/test_request.rb CHANGED
@@ -9,33 +9,6 @@ class String
9
9
  end
10
10
  end
11
11
 
12
- class IO
13
- # Creates two mockup sockets for simulating server-client communication
14
- def self.server_client_mockup
15
- server_in, client_out = IO.pipe
16
- client_in, server_out = IO.pipe
17
-
18
- server_connection = mockup_connection(server_in, server_out, client_out)
19
- client_connection = mockup_connection(client_in, client_out, server_out)
20
-
21
- [server_connection, client_connection]
22
- end
23
-
24
- def self.mockup_connection(input, output, output2)
25
- eg(
26
- :read => ->(*args) { input.read(*args) },
27
- :read_loop => ->(*args, &block) { input.read_loop(*args, &block) },
28
- :recv_loop => ->(*args, &block) { input.read_loop(*args, &block) },
29
- :readpartial => ->(*args) { input.readpartial(*args) },
30
- :recv => ->(*args) { input.readpartial(*args) },
31
- :<< => ->(*args) { output.write(*args) },
32
- :write => ->(*args) { output.write(*args) },
33
- :close => -> { output.close },
34
- :eof? => -> { output2.closed? }
35
- )
36
- end
37
- end
38
-
39
12
  class RequestHeadersTest < MiniTest::Test
40
13
  def teardown
41
14
  @server&.interrupt if @server&.alive?
@@ -65,8 +38,8 @@ class RequestHeadersTest < MiniTest::Test
65
38
  assert_kind_of Qeweney::Request, req
66
39
  assert_equal 'blah.com', req.headers['host']
67
40
  assert_equal 'bar', req.headers['foo']
68
- assert_equal ['1', '3', '2'], req.headers['hi']
69
- assert_equal 'get', req.headers[':method']
41
+ assert_equal ['1', '2', '3'], req.headers['hi']
42
+ assert_equal 'GET', req.headers[':method']
70
43
  assert_equal '/titi', req.headers[':path']
71
44
  end
72
45
 
data/tipi.gemspec CHANGED
@@ -19,21 +19,25 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.executables = ['tipi']
21
21
 
22
- s.add_runtime_dependency 'polyphony', '~>0.57.0'
23
- s.add_runtime_dependency 'qeweney', '~>0.10.0'
24
-
25
- s.add_runtime_dependency 'http_parser.rb', '~>0.6.0'
26
- s.add_runtime_dependency 'http-2', '~>0.10.0'
22
+ s.add_runtime_dependency 'polyphony', '~>0.71'
23
+ s.add_runtime_dependency 'ever', '~>0.1'
24
+ s.add_runtime_dependency 'qeweney', '~>0.14'
25
+ s.add_runtime_dependency 'extralite', '~>1.2'
26
+ s.add_runtime_dependency 'h1p', '~>0.2'
27
+
28
+ s.add_runtime_dependency 'http-2', '~>0.11'
27
29
  s.add_runtime_dependency 'rack', '>=2.0.8', '<2.3.0'
28
30
  s.add_runtime_dependency 'websocket', '~>1.2.8'
29
31
  s.add_runtime_dependency 'acme-client', '~>2.0.8'
32
+ s.add_runtime_dependency 'localhost', '~>1.1.4'
30
33
 
31
34
  # for digital fabric
32
35
  s.add_runtime_dependency 'msgpack', '~>1.4.2'
33
36
 
34
- s.add_development_dependency 'rake', '~>12.3.3'
35
- s.add_development_dependency 'localhost', '~>1.1.4'
37
+ s.add_development_dependency 'rake', '~>13.0.6'
36
38
  s.add_development_dependency 'minitest', '~>5.11.3'
37
- s.add_development_dependency 'minitest-reporters', '~>1.4.2'
38
39
  s.add_development_dependency 'simplecov', '~>0.17.1'
40
+ s.add_development_dependency 'memory_profiler', '~>1.0.0'
41
+
42
+ s.add_development_dependency 'cuba', '~>3.9.3'
39
43
  end