polyphony 0.23 → 0.24

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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +4 -10
  4. data/README.md +0 -4
  5. data/TODO.md +5 -56
  6. data/docs/README.md +4 -7
  7. data/examples/core/{channel_echo.rb → xx-channels.rb} +0 -0
  8. data/examples/core/{defer.rb → xx-deferring-an-operation.rb} +0 -0
  9. data/examples/core/{genserver.rb → xx-erlang-style-genserver.rb} +2 -2
  10. data/examples/core/{fork.rb → xx-forking.rb} +2 -0
  11. data/examples/core/xx-move_on.rb +23 -0
  12. data/examples/core/{pulse.rb → xx-recurrent-timer.rb} +3 -2
  13. data/examples/core/{resource_cancel.rb → xx-resource_cancel.rb} +1 -2
  14. data/examples/core/{resource_delegate.rb → xx-resource_delegate.rb} +0 -0
  15. data/examples/core/{wait_for_signal.rb → xx-signals.rb} +0 -0
  16. data/examples/core/{sleep.rb → xx-sleeping.rb} +0 -0
  17. data/examples/core/{spin_error_backtrace.rb → xx-spin_error_backtrace.rb} +5 -2
  18. data/examples/core/{supervisor.rb → xx-supervisors.rb} +0 -0
  19. data/examples/core/{thread_cancel.rb → xx-thread_cancel.rb} +0 -0
  20. data/examples/core/{thread_pool.rb → xx-thread_pool.rb} +0 -0
  21. data/examples/core/{throttle.rb → xx-throttling.rb} +0 -0
  22. data/examples/core/{timeout.rb → xx-timeout.rb} +0 -0
  23. data/examples/core/{lock.rb → xx-using-a-mutex.rb} +0 -0
  24. data/examples/io/{backticks.rb → xx-backticks.rb} +0 -0
  25. data/examples/io/{echo_client.rb → xx-echo_client.rb} +0 -1
  26. data/examples/io/{echo_client_from_stdin.rb → xx-echo_client_from_stdin.rb} +0 -1
  27. data/examples/io/{echo_pipe.rb → xx-echo_pipe.rb} +0 -0
  28. data/examples/io/{echo_server.rb → xx-echo_server.rb} +0 -0
  29. data/examples/io/{echo_server_with_timeout.rb → xx-echo_server_with_timeout.rb} +0 -0
  30. data/examples/io/{echo_stdin.rb → xx-echo_stdin.rb} +0 -0
  31. data/examples/io/xx-httparty.rb +13 -0
  32. data/examples/io/{irb.rb → xx-irb.rb} +0 -0
  33. data/examples/io/{net-http.rb → xx-net-http.rb} +0 -0
  34. data/examples/io/{open.rb → xx-open.rb} +0 -1
  35. data/examples/io/{system.rb → xx-system.rb} +0 -0
  36. data/examples/io/{tcpserver.rb → xx-tcpserver.rb} +0 -0
  37. data/examples/io/{tcpsocket.rb → xx-tcpsocket.rb} +0 -1
  38. data/examples/{fs/read.rb → performance/fs_read.rb} +0 -0
  39. data/examples/{core → performance}/mem-usage.rb +1 -0
  40. data/examples/performance/multi_snooze.rb +2 -0
  41. data/examples/performance/snooze.rb +2 -0
  42. data/examples/performance/thread-vs-fiber/polyphony_server.rb +5 -3
  43. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -1
  44. data/examples/{io/httparty_multi.rb → performance/thread-vs-fiber/xx-httparty_multi.rb} +16 -13
  45. data/examples/{io/httparty_threaded.rb → performance/thread-vs-fiber/xx-httparty_threaded.rb} +2 -2
  46. data/examples/performance/thread.rb +27 -0
  47. data/examples/{core → performance}/thread_pool_perf.rb +0 -0
  48. data/ext/gyro/extconf.rb +1 -0
  49. data/lib/polyphony/extensions/core.rb +0 -5
  50. data/lib/polyphony/version.rb +1 -1
  51. data/polyphony.gemspec +3 -9
  52. metadata +59 -167
  53. data/bin/poly +0 -11
  54. data/examples/core/cancel.rb +0 -13
  55. data/examples/core/enumerator.rb +0 -15
  56. data/examples/core/error_bubbling.rb +0 -35
  57. data/examples/core/fiber_error.rb +0 -9
  58. data/examples/core/fiber_error_with_backtrace.rb +0 -73
  59. data/examples/core/move_on.rb +0 -11
  60. data/examples/core/move_on_twice.rb +0 -16
  61. data/examples/core/move_on_with_ensure.rb +0 -13
  62. data/examples/core/move_on_with_value.rb +0 -14
  63. data/examples/core/multiple_spin.rb +0 -18
  64. data/examples/core/nested_cancel.rb +0 -40
  65. data/examples/core/nested_multiple_spin.rb +0 -20
  66. data/examples/core/nested_spin.rb +0 -19
  67. data/examples/core/pingpong.rb +0 -21
  68. data/examples/core/resource.rb +0 -30
  69. data/examples/core/sleep_spin.rb +0 -21
  70. data/examples/core/snooze.rb +0 -32
  71. data/examples/core/spin_error.rb +0 -17
  72. data/examples/core/spin_uncaught_error.rb +0 -16
  73. data/examples/core/supervisor_with_cancel_scope.rb +0 -23
  74. data/examples/core/supervisor_with_error.rb +0 -24
  75. data/examples/core/supervisor_with_manual_move_on.rb +0 -23
  76. data/examples/core/suspend.rb +0 -13
  77. data/examples/core/thread.rb +0 -27
  78. data/examples/http/config.ru +0 -7
  79. data/examples/http/cuba.ru +0 -22
  80. data/examples/http/happy_eyeballs.rb +0 -37
  81. data/examples/http/http2_raw.rb +0 -135
  82. data/examples/http/http_client.rb +0 -28
  83. data/examples/http/http_get.rb +0 -33
  84. data/examples/http/http_parse_experiment.rb +0 -123
  85. data/examples/http/http_proxy.rb +0 -83
  86. data/examples/http/http_server.js +0 -24
  87. data/examples/http/http_server.rb +0 -28
  88. data/examples/http/http_server_forked.rb +0 -29
  89. data/examples/http/http_server_graceful.rb +0 -27
  90. data/examples/http/http_server_simple.rb +0 -11
  91. data/examples/http/http_server_throttled.rb +0 -15
  92. data/examples/http/http_ws_server.rb +0 -37
  93. data/examples/http/https_raw_client.rb +0 -12
  94. data/examples/http/https_server.rb +0 -22
  95. data/examples/http/https_wss_server.rb +0 -39
  96. data/examples/http/rack_server.rb +0 -12
  97. data/examples/http/rack_server_https.rb +0 -19
  98. data/examples/http/rack_server_https_forked.rb +0 -27
  99. data/examples/http/websocket_secure_server.rb +0 -27
  100. data/examples/http/websocket_server.rb +0 -24
  101. data/examples/http/ws_page.html +0 -34
  102. data/examples/http/wss_page.html +0 -34
  103. data/examples/io/cat.rb +0 -12
  104. data/examples/io/httparty.rb +0 -10
  105. data/examples/io/io_read.rb +0 -9
  106. data/lib/ev_ext.bundle +0 -0
  107. data/lib/polyphony/http.rb +0 -16
  108. data/lib/polyphony/http/client/agent.rb +0 -131
  109. data/lib/polyphony/http/client/http1.rb +0 -129
  110. data/lib/polyphony/http/client/http2.rb +0 -180
  111. data/lib/polyphony/http/client/response.rb +0 -32
  112. data/lib/polyphony/http/client/site_connection_manager.rb +0 -109
  113. data/lib/polyphony/http/server.rb +0 -49
  114. data/lib/polyphony/http/server/http1.rb +0 -268
  115. data/lib/polyphony/http/server/http2.rb +0 -78
  116. data/lib/polyphony/http/server/http2_stream.rb +0 -136
  117. data/lib/polyphony/http/server/rack.rb +0 -64
  118. data/lib/polyphony/http/server/request.rb +0 -118
  119. data/lib/polyphony/websocket.rb +0 -59
  120. data/test/test_http_server.rb +0 -313
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :Protocol
4
-
5
- require 'http/2'
6
-
7
- Stream = import './http2_stream'
8
-
9
- # HTTP2 API
10
- class Protocol
11
- def self.upgrade_each(socket, opts, headers, &block)
12
- adapter = new(socket, opts, headers)
13
- adapter.each(&block)
14
- end
15
-
16
- def initialize(conn, opts, upgrade_headers = nil)
17
- @conn = conn
18
- @opts = opts
19
- @upgrade_headers = upgrade_headers
20
-
21
- @interface = ::HTTP2::Server.new
22
- @connection_fiber = Fiber.current
23
- @interface.on(:frame, &method(:send_frame))
24
- @streams = {}
25
- end
26
-
27
- def send_frame(data)
28
- @conn << data
29
- rescue Exception => e
30
- @connection_fiber.transfer e
31
- end
32
-
33
- UPGRADE_MESSAGE = <<~HTTP.gsub("\n", "\r\n")
34
- HTTP/1.1 101 Switching Protocols
35
- Connection: Upgrade
36
- Upgrade: h2c
37
-
38
- HTTP
39
-
40
- def upgrade
41
- @conn << UPGRADE_MESSAGE
42
- settings = @upgrade_headers['HTTP2-Settings']
43
- Fiber.current.schedule(nil)
44
- @interface.upgrade(settings, @upgrade_headers, '')
45
- ensure
46
- @upgrade_headers = nil
47
- end
48
-
49
- # Iterates over incoming requests
50
- def each(&block)
51
- @interface.on(:stream) { |stream| start_stream(stream, &block) }
52
- upgrade if @upgrade_headers
53
-
54
- while (data = @conn.readpartial(8192))
55
- @interface << data
56
- snooze
57
- end
58
- rescue SystemCallError, IOError
59
- # ignore
60
- ensure
61
- finalize_client_loop
62
- end
63
-
64
- def start_stream(stream, &block)
65
- stream = Stream.new(stream, &block)
66
- @streams[stream] = true
67
- end
68
-
69
- def finalize_client_loop
70
- @interface = nil
71
- @streams.each_key(&:stop)
72
- @conn.close
73
- end
74
-
75
- def close
76
- @conn.close
77
- end
78
- end
@@ -1,136 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :StreamHandler
4
-
5
- require 'http/2'
6
-
7
- Request = import './request'
8
- Exceptions = import '../../core/exceptions'
9
-
10
- # Manages an HTTP 2 stream
11
- class StreamHandler
12
- attr_accessor :__next__
13
-
14
- def initialize(stream, &block)
15
- @stream = stream
16
- @calling_fiber = Fiber.current
17
- @stream_fiber = Fiber.new { |req| handle_request(req, &block) }
18
-
19
- # Stream callbacks occur on the connection fiber (see HTTP2::Protocol#each).
20
- # The request handler is run on a separate fiber for each stream, allowing
21
- # concurrent handling of incoming requests on the same HTTP/2 connection.
22
- #
23
- # The different stream adapter APIs suspend the stream fiber, waiting for
24
- # stream callbacks to be called. The callbacks, in turn, transfer control to
25
- # the stream fiber, effectively causing the return of the adapter API calls.
26
- #
27
- # Note: the request handler is run once headers are received. Reading the
28
- # request body, if present, is at the discretion of the request handler.
29
- # This mirrors the behaviour of the HTTP/1 adapter.
30
- stream.on(:headers, &method(:on_headers))
31
- stream.on(:data, &method(:on_data))
32
- stream.on(:half_close, &method(:on_half_close))
33
- end
34
-
35
- def handle_request(request, &block)
36
- error = nil
37
- block.(request)
38
- @calling_fiber.transfer
39
- rescue Exceptions::MoveOn
40
- # ignore
41
- rescue Exception => e
42
- error = e
43
- ensure
44
- @done = true
45
- @calling_fiber.transfer error
46
- end
47
-
48
- def on_headers(headers)
49
- @request = Request.new(headers.to_h, self)
50
- @stream_fiber.transfer(@request)
51
- end
52
-
53
- def on_data(data)
54
- if @waiting_for_body_chunk
55
- @waiting_for_body_chunk = nil
56
- @stream_fiber.transfer(data)
57
- else
58
- @request.buffer_body_chunk(data)
59
- end
60
- end
61
-
62
- def on_half_close
63
- if @waiting_for_body_chunk
64
- @waiting_for_body_chunk = nil
65
- @stream_fiber.transfer(nil)
66
- elsif @waiting_for_half_close
67
- @waiting_for_half_close = nil
68
- @stream_fiber.transfer(nil)
69
- else
70
- @request.complete!
71
- end
72
- end
73
-
74
- def protocol
75
- 'h2'
76
- end
77
-
78
- def get_body_chunk
79
- # called in the context of the stream fiber
80
- return nil if @request.complete?
81
-
82
- @waiting_for_body_chunk = true
83
- # the chunk (or an exception) will be returned once the stream fiber is
84
- # resumed
85
- suspend
86
- ensure
87
- @waiting_for_body_chunk = nil
88
- end
89
-
90
- # Wait for request to finish
91
- def consume_request
92
- return if @request.complete?
93
-
94
- @waiting_for_half_close = true
95
- suspend
96
- ensure
97
- @waiting_for_half_close = nil
98
- end
99
-
100
- # response API
101
- def respond(chunk, headers)
102
- headers[':status'] ||= '200'
103
- @stream.headers(headers, end_stream: false)
104
- @stream.data(chunk, end_stream: true)
105
- @headers_sent = true
106
- end
107
-
108
- def send_headers(headers, empty_response = false)
109
- return if @headers_sent
110
-
111
- headers[':status'] ||= (empty_response ? 204 : 200).to_s
112
- @stream.headers(headers, end_stream: false)
113
- @headers_sent = true
114
- end
115
-
116
- def send_chunk(chunk, done: false)
117
- send_headers({}, false) unless @headers_sent
118
- @stream.data(chunk, end_stream: done)
119
- end
120
-
121
- def finish
122
- if @headers_sent
123
- @stream.close
124
- else
125
- headers[':status'] ||= '204'
126
- @stream.headers(headers, end_stream: true)
127
- end
128
- end
129
-
130
- def stop
131
- return if @done
132
-
133
- @stream.close
134
- @stream_fiber.schedule(Polyphony::MoveOn.new)
135
- end
136
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export :load
4
-
5
- require 'rack'
6
-
7
- def run(app)
8
- ->(req) { respond(req, app.(env(req))) }
9
- end
10
-
11
- def load(path)
12
- src = IO.read(path)
13
- instance_eval(src, path, 1)
14
- end
15
-
16
- # Implements a rack input stream:
17
- # https://www.rubydoc.info/github/rack/rack/master/file/SPEC#label-The+Input+Stream
18
- class InputStream
19
- def initialize(request)
20
- @request = request
21
- end
22
-
23
- def gets; end
24
-
25
- def read(length = nil, outbuf = nil); end
26
-
27
- def each(&block)
28
- @request.each_chunk(&block)
29
- end
30
-
31
- def rewind; end
32
- end
33
-
34
- def env(request)
35
- {
36
- 'REQUEST_METHOD' => request.method,
37
- 'SCRIPT_NAME' => '',
38
- 'PATH_INFO' => request.path,
39
- 'QUERY_STRING' => request.query_string || '',
40
- 'SERVER_NAME' => request.headers['Host'], # ?
41
- 'SERVER_PORT' => '80', # ?
42
- 'rack.version' => Rack::VERSION,
43
- 'rack.url_scheme' => 'https', # ?
44
- 'rack.input' => InputStream.new(request),
45
- 'rack.errors' => STDERR, # ?
46
- 'rack.multithread' => false,
47
- 'rack.run_once' => false,
48
- 'rack.hijack?' => false,
49
- 'rack.hijack' => nil,
50
- 'rack.hijack_io' => nil,
51
- 'rack.session' => nil,
52
- 'rack.logger' => nil,
53
- 'rack.multipart.buffer_size' => nil,
54
- 'rack.multipar.tempfile_factory' => nil
55
- }.tap do |env|
56
- request.headers.each { |k, v| env["HTTP_#{k.upcase}"] = v }
57
- end
58
- end
59
-
60
- def respond(request, (status_code, headers, body))
61
- headers[':status'] = status_code.to_s
62
- puts "headers: #{headers.inspect}"
63
- request.respond(body.first, headers)
64
- end
@@ -1,118 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :Request
4
-
5
- require 'uri'
6
-
7
- # HTTP request
8
- class Request
9
- attr_reader :headers, :adapter
10
- attr_accessor :__next__
11
-
12
- def initialize(headers, adapter)
13
- @headers = headers
14
- @adapter = adapter
15
- end
16
-
17
- def protocol
18
- @protocol = @adapter.protocol
19
- end
20
-
21
- def method
22
- @method ||= @headers[':method']
23
- end
24
-
25
- def scheme
26
- @scheme ||= @headers[':scheme']
27
- end
28
-
29
- def uri
30
- @uri ||= URI.parse(@headers[':path'] || '')
31
- end
32
-
33
- def path
34
- @path ||= uri.path
35
- end
36
-
37
- def query_string
38
- @query_string ||= uri.query
39
- end
40
-
41
- def query
42
- return @query if @query
43
-
44
- @query = (q = uri.query) ? split_query_string(q) : {}
45
- end
46
-
47
- def split_query_string(query)
48
- query.split('&').each_with_object({}) do |kv, h|
49
- k, v = kv.split('=')
50
- h[k.to_sym] = URI.decode_www_form_component(v)
51
- end
52
- end
53
-
54
- def buffer_body_chunk(chunk)
55
- @buffered_body_chunks ||= []
56
- @buffered_body_chunks << chunk
57
- end
58
-
59
- def each_chunk(&block)
60
- if @buffered_body_chunks
61
- @buffered_body_chunks.each(&block)
62
- @buffered_body_chunks = nil
63
- end
64
- while !@message_complete && (chunk = @adapter.get_body_chunk)
65
- yield chunk
66
- end
67
- end
68
-
69
- def complete!(keep_alive = nil)
70
- @message_complete = true
71
- @keep_alive = keep_alive
72
- end
73
-
74
- def complete?
75
- @message_complete
76
- end
77
-
78
- def consume
79
- @adapter.consume_request
80
- end
81
-
82
- def keep_alive?
83
- @keep_alive
84
- end
85
-
86
- def read
87
- buf = @buffered_body_chunks ? @buffered_body_chunks.join : +''
88
- while (chunk = @adapter.get_body_chunk)
89
- buf << chunk
90
- end
91
- buf
92
- end
93
-
94
- def respond(body, headers = {})
95
- @adapter.respond(body, headers)
96
- @headers_sent = true
97
- end
98
-
99
- def send_headers(headers = {}, empty_response = false)
100
- return if @headers_sent
101
-
102
- @headers_sent = true
103
- @adapter.send_headers(headers, empty_response: empty_response)
104
- end
105
-
106
- def send_chunk(body, done: false)
107
- send_headers({}) unless @headers_sent
108
-
109
- @adapter.send_chunk(body, done: done)
110
- end
111
- alias_method :<<, :send_chunk
112
-
113
- def finish
114
- send_headers({}) unless @headers_sent
115
-
116
- @adapter.finish
117
- end
118
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export :handler
4
-
5
- require 'digest/sha1'
6
- require 'websocket'
7
-
8
- # Websocket connection
9
- class WebsocketConnection
10
- def initialize(client, headers)
11
- @client = client
12
- @headers = headers
13
- setup(headers)
14
- end
15
-
16
- S_WS_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
17
- UPGRADE_RESPONSE = <<~HTTP.gsub("\n", "\r\n")
18
- HTTP/1.1 101 Switching Protocols
19
- Upgrade: websocket
20
- Connection: Upgrade
21
- Sec-WebSocket-Accept: %<accept>s
22
-
23
- HTTP
24
-
25
- def setup(headers)
26
- key = headers['Sec-WebSocket-Key']
27
- @version = headers['Sec-WebSocket-Version'].to_i
28
- accept = Digest::SHA1.base64digest([key, S_WS_GUID].join)
29
- @client << format(UPGRADE_RESPONSE, accept: accept)
30
-
31
- @reader = ::WebSocket::Frame::Incoming::Server.new(version: @version)
32
- end
33
-
34
- def recv
35
- loop do
36
- data = @client.readpartial(8192)
37
- break nil unless data
38
-
39
- @reader << data
40
- if (msg = @reader.next)
41
- break msg.to_s
42
- end
43
- end
44
- end
45
-
46
- def send(data)
47
- frame = ::WebSocket::Frame::Outgoing::Server.new(
48
- version: @version, data: data, type: :text
49
- )
50
- @client << frame.to_s
51
- end
52
- alias_method :<<, :send
53
- end
54
-
55
- def handler(&block)
56
- proc { |client, header|
57
- block.(WebsocketConnection.new(client, header))
58
- }
59
- end