polyphony 0.23 → 0.24

Sign up to get free protection for your applications and to get access to all the features.
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