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,34 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <title>Websocket Client</title>
5
- </head>
6
- <body>
7
- <script>
8
- var connect = function () {
9
- var exampleSocket = new WebSocket("ws://localhost:1234");
10
-
11
- exampleSocket.onopen = function (event) {
12
- document.querySelector('#status').innerText = 'connected';
13
- exampleSocket.send("Can you hear me?");
14
- };
15
- exampleSocket.onclose = function (event) {
16
- console.log('onclose');
17
- document.querySelector('#status').innerText = 'disconnected';
18
- setTimeout(function () {
19
- // exampleSocket.removeAllListeners();
20
- connect();
21
- }, 1000);
22
- }
23
- exampleSocket.onmessage = function (event) {
24
- document.querySelector('#msg').innerText = event.data;
25
- console.log(event.data);
26
- }
27
- };
28
-
29
- connect();
30
- </script>
31
- <h1 id="status">disconnected</h1>
32
- <h1 id="msg"></h1>
33
- </body>
34
- </html>
@@ -1,34 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <title>Websocket Client</title>
5
- </head>
6
- <body>
7
- <script>
8
- var connect = function () {
9
- var exampleSocket = new WebSocket("/");
10
-
11
- exampleSocket.onopen = function (event) {
12
- document.querySelector('#status').innerText = 'connected';
13
- exampleSocket.send("Can you hear me?");
14
- };
15
- exampleSocket.onclose = function (event) {
16
- console.log('onclose');
17
- document.querySelector('#status').innerText = 'disconnected';
18
- setTimeout(function () {
19
- // exampleSocket.removeAllListeners();
20
- connect();
21
- }, 1000);
22
- }
23
- exampleSocket.onmessage = function (event) {
24
- document.querySelector('#msg').innerText = event.data;
25
- console.log(event.data);
26
- }
27
- };
28
-
29
- connect();
30
- </script>
31
- <h1 id="status">disconnected</h1>
32
- <h1 id="msg"></h1>
33
- </body>
34
- </html>
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'polyphony'
5
-
6
- File.open(__FILE__, 'r') do |f|
7
- line_number = 1
8
- while (l = f.gets)
9
- puts format('%03d %s', line_number, l)
10
- line_number += 1
11
- end
12
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'polyphony'
5
- require 'httparty'
6
-
7
- timer = spin { throttled_loop(10) { STDOUT << '.' } }
8
-
9
- puts HTTParty.get('http://google.com/')
10
- timer.stop
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'polyphony'
5
-
6
- s = IO.read(__FILE__)
7
- puts "encoding: #{s.encoding.inspect}"
8
- puts s
9
- puts
Binary file
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../polyphony'
4
-
5
- module Polyphony
6
- # HTTP imports (loaded dynamically)
7
- module HTTP
8
- auto_import(
9
- Agent: './http/client/agent',
10
- Rack: './http/server/rack',
11
- Server: './http/server'
12
- )
13
- end
14
- end
15
-
16
- export_default Polyphony::HTTP
@@ -1,131 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :Agent
4
-
5
- require 'uri'
6
-
7
- ResourcePool = import '../../core/resource_pool'
8
- SiteConnectionManager = import './site_connection_manager'
9
-
10
- # Implements an HTTP agent
11
- class Agent
12
- def self.get(*args, &block)
13
- default.get(*args, &block)
14
- end
15
-
16
- def self.post(*args, &block)
17
- default.post(*args, &block)
18
- end
19
-
20
- def self.default
21
- @default ||= new
22
- end
23
-
24
- def initialize
25
- @pools = Hash.new do |h, k|
26
- h[k] = SiteConnectionManager.new(k)
27
- end
28
- end
29
-
30
- OPTS_DEFAULT = {}.freeze
31
-
32
- def get(url, opts = OPTS_DEFAULT, &block)
33
- request(url, opts.merge(method: :GET), &block)
34
- end
35
-
36
- def post(url, opts = OPTS_DEFAULT, &block)
37
- request(url, opts.merge(method: :POST), &block)
38
- end
39
-
40
- def request(url, opts = OPTS_DEFAULT, &block)
41
- ctx = request_ctx(url, opts)
42
-
43
- response = do_request(ctx, &block)
44
- case response.status_code
45
- when 301, 302
46
- redirect(response.headers['Location'], ctx, opts, &block)
47
- when 200, 204
48
- response
49
- else
50
- raise "Error received from server: #{response.status_code}"
51
- end
52
- end
53
-
54
- def redirect(url, ctx, opts, &block)
55
- url = redirect_url(url, ctx)
56
- request(url, opts, &block)
57
- end
58
-
59
- def redirect_url(url, ctx)
60
- case url
61
- when /^http(?:s)?\:\/\//
62
- url
63
- when /^\/\/(.+)$/
64
- ctx[:uri].scheme + url
65
- when /^\//
66
- format_uri(url, ctx)
67
- else
68
- ctx[:uri] + url
69
- end
70
- end
71
-
72
- def format_uri(url, ctx)
73
- format(
74
- '%<scheme>s://%<host>s%<url>s',
75
- scheme: ctx[:uri].scheme,
76
- host: ctx[:uri].host,
77
- url: url
78
- )
79
- end
80
-
81
- def request_ctx(url, opts)
82
- {
83
- method: opts[:method] || :GET,
84
- uri: url_to_uri(url, opts),
85
- opts: opts,
86
- retry: 0
87
- }
88
- end
89
-
90
- def url_to_uri(url, opts)
91
- uri = URI(url)
92
- if opts[:query]
93
- query = opts[:query].map { |k, v| "#{k}=#{v}" }.join('&')
94
- if uri.query
95
- v.query = "#{uri.query}&#{query}"
96
- else
97
- uri.query = query
98
- end
99
- end
100
- uri
101
- end
102
-
103
- def do_request(ctx, &block)
104
- key = uri_key(ctx[:uri])
105
-
106
- @pools[key].acquire do |adapter|
107
- send_request_and_check_response(adapter, ctx, &block)
108
- end
109
- rescue Exception => e
110
- p e
111
- puts e.backtrace.join("\n")
112
- end
113
-
114
- def send_request_and_check_response(adapter, ctx, &block)
115
- response = adapter.request(ctx)
116
- case response.status_code
117
- when 200, 204
118
- if block
119
- block.(response)
120
- else
121
- # read body
122
- response.body
123
- end
124
- end
125
- response
126
- end
127
-
128
- def uri_key(uri)
129
- { scheme: uri.scheme, host: uri.host, port: uri.port }
130
- end
131
- end
@@ -1,129 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :HTTP1Adapter
4
-
5
- require 'http/parser'
6
-
7
- Response = import './response'
8
-
9
- # HTTP 1 adapter
10
- class HTTP1Adapter
11
- def initialize(socket)
12
- @socket = socket
13
- @parser = HTTP::Parser.new(self)
14
- end
15
-
16
- def on_headers_complete(headers)
17
- @headers = headers
18
- end
19
-
20
- def on_body(chunk)
21
- if @waiting_for_chunk
22
- @buffered_chunks ||= []
23
- @buffered_chunks << chunk
24
- elsif @buffered_body
25
- @buffered_body << chunk
26
- else
27
- @buffered_body = +chunk
28
- end
29
- end
30
-
31
- def on_message_complete
32
- @done = true
33
- end
34
-
35
- def request(ctx)
36
- # consume previous response if not finished
37
- consume_response if @done == false
38
-
39
- @socket << format_http1_request(ctx)
40
-
41
- @buffered_body = nil
42
- @done = false
43
-
44
- read_headers
45
- Response.new(self, @parser.status_code, @headers)
46
- end
47
-
48
- def read_headers
49
- @headers = nil
50
- while !@headers && (data = @socket.readpartial(8192))
51
- @parser << data
52
- end
53
-
54
- raise 'Socket closed by host' unless @headers
55
- end
56
-
57
- def body
58
- @waiting_for_chunk = nil
59
- consume_response
60
- @buffered_body
61
- end
62
-
63
- def each_chunk(&block)
64
- if (body = @buffered_body)
65
- @buffered_body = nil
66
- @waiting_for_chunk = true
67
- block.(body)
68
- end
69
- while !@done && (data = @socket.readpartial(8192))
70
- @parser << data
71
- end
72
- raise 'Socket closed by host' unless @done
73
-
74
- @buffered_chunks.each(&block)
75
- end
76
-
77
- def next_body_chunk
78
- return nil if @done
79
- if @buffered_chunks && !@buffered_chunks.empty?
80
- return @buffered_chunks.shift
81
- end
82
-
83
- read_next_body_chunk
84
- end
85
-
86
- def read_next_body_chunk
87
- @waiting_for_chunk = true
88
- while !@done && (data = @socket.readpartial(8192))
89
- @parser << data
90
- break unless @buffered_chunks.empty?
91
- end
92
- @buffered_chunks.shift
93
- end
94
-
95
- def consume_response
96
- while !@done && (data = @socket.readpartial(8192))
97
- @parser << data
98
- end
99
-
100
- raise 'Socket closed by host' unless @done
101
- end
102
-
103
- HTTP1_REQUEST = <<~HTTP.gsub("\n", "\r\n")
104
- %<method>s %<request>s HTTP/1.1
105
- Host: %<host>s
106
- %<headers>s
107
-
108
- HTTP
109
-
110
- def format_http1_request(ctx)
111
- headers = format_headers(ctx)
112
-
113
- format(
114
- HTTP1_REQUEST,
115
- method: ctx[:method],
116
- request: ctx[:uri].request_uri,
117
- host: ctx[:uri].host,
118
- headers: headers
119
- )
120
- end
121
-
122
- def format_headers(headers)
123
- headers.map { |k, v| "#{k}: #{v}\r\n" }.join
124
- end
125
-
126
- def protocol
127
- :http1
128
- end
129
- end
@@ -1,180 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :HTTP2Adapter
4
-
5
- require 'http/2'
6
-
7
- Response = import './response'
8
-
9
- # HTTP 2 adapter
10
- class HTTP2Adapter
11
- def initialize(socket)
12
- @socket = socket
13
- @client = HTTP2::Client.new
14
- @client.on(:frame) { |bytes| socket << bytes }
15
- # @client.on(:frame_received) do |frame|
16
- # puts "Received frame: #{frame.inspect}"
17
- # end
18
- # @client.on(:frame_sent) do |frame|
19
- # puts "Sent frame: #{frame.inspect}"
20
- # end
21
-
22
- @reader = spin do
23
- while (data = socket.readpartial(8192))
24
- @client << data
25
- snooze
26
- end
27
- end
28
- end
29
-
30
- def allocate_stream_adapter
31
- StreamAdapter.new(self)
32
- end
33
-
34
- def allocate_stream
35
- @client.new_stream
36
- end
37
-
38
- def protocol
39
- :http2
40
- end
41
-
42
- # Virtualizes adapter over HTTP2 stream
43
- class StreamAdapter
44
- def initialize(connection)
45
- @connection = connection
46
- end
47
-
48
- def request(ctx)
49
- stream = setup_stream # (ctx, stream)
50
- send_request(ctx, stream)
51
-
52
- stream.on(:headers, &method(:on_headers))
53
- stream.on(:data, &method(:on_data))
54
- stream.on(:close, &method(:on_close))
55
-
56
- # stream.on(:active) { puts "* active" }
57
- # stream.on(:half_close) { puts "* half_close" }
58
-
59
- wait_for_response(ctx, stream)
60
- rescue Exception => e
61
- p e
62
- puts e.backtrace.join("\n")
63
- # ensure
64
- # stream.close
65
- end
66
-
67
- def send_request(ctx, stream)
68
- headers = prepare_headers(ctx)
69
- if ctx[:opts][:payload]
70
- stream.headers(headers, end_stream: false)
71
- stream.data(ctx[:opts][:payload], end_stream: true)
72
- else
73
- stream.headers(headers, end_stream: true)
74
- end
75
- end
76
-
77
- def on_headers(headers)
78
- if @waiting_headers_fiber
79
- @waiting_headers_fiber.schedule headers.to_h
80
- else
81
- @headers = headers.to_h
82
- end
83
- end
84
-
85
- def on_data(chunk)
86
- if @waiting_chunk_fiber
87
- @waiting_chunk_fiber&.schedule chunk
88
- else
89
- @buffered_chunks << chunk
90
- end
91
- end
92
-
93
- def on_close(_stream)
94
- @done = true
95
- @waiting_done_fiber&.schedule
96
- end
97
-
98
- def setup_stream
99
- stream = @connection.allocate_stream
100
-
101
- @headers = nil
102
- @done = nil
103
- @buffered_chunks = []
104
-
105
- @waiting_headers_fiber = nil
106
- @waiting_chunk_fiber = nil
107
- @waiting_done_fiber = nil
108
-
109
- stream
110
- end
111
-
112
- def wait_for_response(_ctx, _stream)
113
- headers = wait_for_headers
114
- Response.new(self, headers[':status'].to_i, headers)
115
- end
116
-
117
- def wait_for_headers
118
- return @headers if @headers
119
-
120
- @waiting_headers_fiber = Fiber.current
121
- suspend
122
- end
123
-
124
- def protocol
125
- :http2
126
- end
127
-
128
- def prepare_headers(ctx)
129
- headers = {
130
- ':method' => ctx[:method].to_s,
131
- ':scheme' => ctx[:uri].scheme,
132
- ':authority' => [ctx[:uri].host, ctx[:uri].port].join(':'),
133
- ':path' => ctx[:uri].request_uri,
134
- 'User-Agent' => 'curl/7.54.0'
135
- }
136
- headers.merge!(ctx[:opts][:headers]) if ctx[:opts][:headers]
137
- headers
138
- end
139
-
140
- def body
141
- @waiting_done_fiber = Fiber.current
142
- suspend
143
- @buffered_chunks.join
144
- # body = +''
145
- # while !@done
146
- # p :body_suspend_pre
147
- # chunk = suspend
148
- # p :body_suspend_post
149
- # body << chunk
150
- # end
151
- # puts ""
152
- # body
153
- rescue Exception => e
154
- p e
155
- puts e.backtrace.join("\n")
156
- end
157
-
158
- def each_chunk
159
- yield @buffered_chunks.shift until @buffered_chunks.empty?
160
-
161
- @waiting_chunk_fiber = Fiber.current
162
- until @done
163
- chunk = suspend
164
- yield chunk
165
- end
166
- end
167
-
168
- def next_body_chunk
169
- return yield @buffered_chunks.shift unless @buffered_chunks.empty?
170
-
171
- @waiting_chunk_fuber = Fiber.current
172
- until @done
173
- chunk = suspend
174
- return yield chunk
175
- end
176
-
177
- nil
178
- end
179
- end
180
- end