polyphony 0.17 → 0.19

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +11 -3
  4. data/README.md +18 -18
  5. data/TODO.md +5 -21
  6. data/examples/core/channel_echo.rb +3 -3
  7. data/examples/core/enumerator.rb +1 -1
  8. data/examples/core/fork.rb +1 -1
  9. data/examples/core/genserver.rb +1 -1
  10. data/examples/core/lock.rb +3 -3
  11. data/examples/core/multiple_spawn.rb +2 -2
  12. data/examples/core/nested_async.rb +1 -1
  13. data/examples/core/nested_multiple_spawn.rb +3 -3
  14. data/examples/core/resource_cancel.rb +1 -1
  15. data/examples/core/sleep_spawn.rb +2 -2
  16. data/examples/core/spawn.rb +1 -1
  17. data/examples/core/spawn_cancel.rb +1 -1
  18. data/examples/core/spawn_error.rb +4 -4
  19. data/examples/core/supervisor.rb +1 -1
  20. data/examples/core/supervisor_with_error.rb +1 -1
  21. data/examples/core/supervisor_with_manual_move_on.rb +1 -1
  22. data/examples/core/thread.rb +2 -2
  23. data/examples/core/thread_cancel.rb +2 -2
  24. data/examples/core/thread_pool.rb +1 -1
  25. data/examples/core/throttle.rb +3 -3
  26. data/examples/core/timeout.rb +10 -0
  27. data/examples/fs/read.rb +1 -1
  28. data/examples/http/http_client.rb +1 -1
  29. data/examples/http/http_get.rb +7 -0
  30. data/examples/http/http_parse_experiment.rb +118 -0
  31. data/examples/http/http_proxy.rb +81 -0
  32. data/examples/http/http_server.rb +15 -4
  33. data/examples/http/http_server_forked.rb +2 -2
  34. data/examples/http/http_server_throttled.rb +1 -1
  35. data/examples/http/http_ws_server.rb +2 -2
  36. data/examples/http/https_server.rb +5 -1
  37. data/examples/http/https_wss_server.rb +1 -1
  38. data/examples/http/rack_server_https_forked.rb +1 -1
  39. data/examples/interfaces/pg_client.rb +1 -1
  40. data/examples/interfaces/pg_pool.rb +1 -1
  41. data/examples/interfaces/redis_channels.rb +5 -5
  42. data/examples/interfaces/redis_pubsub.rb +2 -2
  43. data/examples/interfaces/redis_pubsub_perf.rb +3 -3
  44. data/examples/io/echo_client.rb +2 -2
  45. data/examples/io/echo_pipe.rb +17 -0
  46. data/examples/io/echo_server.rb +1 -1
  47. data/examples/io/echo_server_with_timeout.rb +1 -1
  48. data/examples/io/httparty.rb +10 -0
  49. data/examples/io/httparty_multi.rb +29 -0
  50. data/examples/io/httparty_threaded.rb +25 -0
  51. data/examples/io/irb.rb +15 -0
  52. data/examples/io/net-http.rb +15 -0
  53. data/examples/io/system.rb +1 -1
  54. data/examples/io/tcpsocket.rb +18 -0
  55. data/examples/performance/perf_multi_snooze.rb +2 -2
  56. data/examples/performance/perf_snooze.rb +17 -20
  57. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  58. data/ext/ev/ev.h +9 -1
  59. data/ext/ev/ev_ext.c +4 -1
  60. data/ext/ev/ev_module.c +36 -22
  61. data/ext/ev/extconf.rb +1 -1
  62. data/ext/ev/io.c +23 -23
  63. data/ext/ev/signal.c +1 -1
  64. data/ext/ev/socket.c +161 -0
  65. data/lib/polyphony/core/coprocess.rb +1 -1
  66. data/lib/polyphony/core/fiber_pool.rb +2 -2
  67. data/lib/polyphony/core/supervisor.rb +2 -18
  68. data/lib/polyphony/extensions/io.rb +19 -6
  69. data/lib/polyphony/extensions/kernel.rb +17 -5
  70. data/lib/polyphony/extensions/socket.rb +40 -1
  71. data/lib/polyphony/http/agent.rb +56 -25
  72. data/lib/polyphony/http/http1_adapter.rb +254 -0
  73. data/lib/polyphony/http/http2_adapter.rb +157 -0
  74. data/lib/polyphony/http/{http2_request.rb → request.rb} +25 -22
  75. data/lib/polyphony/http/server.rb +19 -11
  76. data/lib/polyphony/net.rb +10 -6
  77. data/lib/polyphony/version.rb +1 -1
  78. data/polyphony.gemspec +6 -5
  79. data/test/test_coprocess.rb +9 -9
  80. data/test/test_core.rb +14 -14
  81. data/test/test_io.rb +4 -4
  82. data/test/test_kernel.rb +1 -1
  83. metadata +48 -23
  84. data/lib/polyphony/http/http1.rb +0 -124
  85. data/lib/polyphony/http/http1_request.rb +0 -83
  86. data/lib/polyphony/http/http2.rb +0 -65
@@ -15,19 +15,19 @@ class IOTest < MiniTest::Test
15
15
  count = 0
16
16
  msg = nil
17
17
  [
18
- coproc {
18
+ spin {
19
19
  @o.write("hello")
20
20
  @o.close
21
21
  },
22
22
 
23
- coproc {
23
+ spin {
24
24
  while count < 5
25
25
  sleep 0.01
26
26
  count += 1
27
27
  end
28
28
  },
29
29
 
30
- coproc {
30
+ spin {
31
31
  msg = @i.read
32
32
  }
33
33
  ].each(&:await)
@@ -118,7 +118,7 @@ class IOClassMethodsTest < MiniTest::Test
118
118
 
119
119
  def test_popen
120
120
  counter = 0
121
- timer = coproc {
121
+ timer = spin {
122
122
  throttled_loop(200) { counter += 1 }
123
123
  }
124
124
 
@@ -11,7 +11,7 @@ class KernelTest < MiniTest::Test
11
11
 
12
12
  def test_system_method
13
13
  counter = 0
14
- timer = coproc {
14
+ timer = spin {
15
15
  throttled_loop(200) { counter += 1 }
16
16
  }
17
17
 
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.17'
4
+ version: '0.19'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-24 00:00:00.000000000 Z
11
+ date: 2019-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: modulation
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.24'
19
+ version: '0.25'
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.24'
26
+ version: '0.25'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: http_parser.rb
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -53,33 +53,33 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.10.0
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake-compiler
56
+ name: hiredis
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 1.0.5
61
+ version: 0.6.3
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 1.0.5
68
+ version: 0.6.3
69
69
  - !ruby/object:Gem::Dependency
70
- name: minitest
70
+ name: httparty
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 5.11.3
75
+ version: 0.17.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 5.11.3
82
+ version: 0.17.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: localhost
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -95,19 +95,19 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: 1.1.4
97
97
  - !ruby/object:Gem::Dependency
98
- name: websocket
98
+ name: minitest
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 1.2.8
103
+ version: 5.11.3
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: 1.2.8
110
+ version: 5.11.3
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: pg
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
124
  version: 1.1.3
125
+ - !ruby/object:Gem::Dependency
126
+ name: rake-compiler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: 1.0.5
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: 1.0.5
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: redis
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -137,19 +151,19 @@ dependencies:
137
151
  - !ruby/object:Gem::Version
138
152
  version: 4.1.0
139
153
  - !ruby/object:Gem::Dependency
140
- name: hiredis
154
+ name: websocket
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
157
  - - '='
144
158
  - !ruby/object:Gem::Version
145
- version: 0.6.3
159
+ version: 1.2.8
146
160
  type: :development
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - '='
151
165
  - !ruby/object:Gem::Version
152
- version: 0.6.3
166
+ version: 1.2.8
153
167
  description:
154
168
  email: ciconia@gmail.com
155
169
  executables: []
@@ -203,10 +217,14 @@ files:
203
217
  - examples/core/thread_cancel.rb
204
218
  - examples/core/thread_pool.rb
205
219
  - examples/core/throttle.rb
220
+ - examples/core/timeout.rb
206
221
  - examples/fs/read.rb
207
222
  - examples/http/config.ru
208
223
  - examples/http/happy_eyeballs.rb
209
224
  - examples/http/http_client.rb
225
+ - examples/http/http_get.rb
226
+ - examples/http/http_parse_experiment.rb
227
+ - examples/http/http_proxy.rb
210
228
  - examples/http/http_server.js
211
229
  - examples/http/http_server.rb
212
230
  - examples/http/http_server_forked.rb
@@ -231,11 +249,18 @@ files:
231
249
  - examples/interfaces/redis_pubsub_perf.rb
232
250
  - examples/io/cat.rb
233
251
  - examples/io/echo_client.rb
252
+ - examples/io/echo_pipe.rb
234
253
  - examples/io/echo_server.rb
235
254
  - examples/io/echo_server_with_timeout.rb
236
255
  - examples/io/echo_stdin.rb
256
+ - examples/io/httparty.rb
257
+ - examples/io/httparty_multi.rb
258
+ - examples/io/httparty_threaded.rb
237
259
  - examples/io/io_read.rb
260
+ - examples/io/irb.rb
261
+ - examples/io/net-http.rb
238
262
  - examples/io/system.rb
263
+ - examples/io/tcpsocket.rb
239
264
  - examples/performance/perf_multi_snooze.rb
240
265
  - examples/performance/perf_snooze.rb
241
266
  - examples/performance/thread-vs-fiber/polyphony_server.rb
@@ -249,6 +274,7 @@ files:
249
274
  - ext/ev/io.c
250
275
  - ext/ev/libev.h
251
276
  - ext/ev/signal.c
277
+ - ext/ev/socket.c
252
278
  - ext/ev/timer.c
253
279
  - ext/libev/Changes
254
280
  - ext/libev/LICENSE
@@ -284,11 +310,10 @@ files:
284
310
  - lib/polyphony/fs.rb
285
311
  - lib/polyphony/http.rb
286
312
  - lib/polyphony/http/agent.rb
287
- - lib/polyphony/http/http1.rb
288
- - lib/polyphony/http/http1_request.rb
289
- - lib/polyphony/http/http2.rb
290
- - lib/polyphony/http/http2_request.rb
313
+ - lib/polyphony/http/http1_adapter.rb
314
+ - lib/polyphony/http/http2_adapter.rb
291
315
  - lib/polyphony/http/rack.rb
316
+ - lib/polyphony/http/request.rb
292
317
  - lib/polyphony/http/server.rb
293
318
  - lib/polyphony/line_reader.rb
294
319
  - lib/polyphony/net.rb
@@ -326,7 +351,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
326
351
  - !ruby/object:Gem::Version
327
352
  version: '0'
328
353
  requirements: []
329
- rubygems_version: 3.0.1
354
+ rubygems_version: 3.0.3
330
355
  signing_key:
331
356
  specification_version: 4
332
357
  summary: 'Polyphony: Fiber-based Concurrency for Ruby'
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export :call
4
-
5
- require 'http/parser'
6
-
7
- Request = import('./http1_request')
8
- HTTP2 = import('./http2')
9
-
10
- class Http::Parser
11
- def async!
12
- self.on_message_complete = proc { @request_complete = true }
13
- self
14
- end
15
-
16
- def parse(data)
17
- self << data
18
- return nil unless @request_complete
19
-
20
- @request_complete = nil
21
- self
22
- end
23
- end
24
-
25
- # Sets up parsing and handling of request/response cycle
26
- # @param socket [Net::Socket] socket
27
- # @param handler [Proc] request handler
28
- # @return [void]
29
- def call(socket, opts, &handler)
30
- ctx = connection_context(socket, opts, handler)
31
- ctx[:parser].on_body = proc { |chunk| handle_body_chunk(ctx, chunk) }
32
-
33
- loop do
34
- data = socket.readpartial(8192)
35
- break unless data
36
- if ctx[:parser].parse(data)
37
- break unless handle_request(ctx)
38
- snooze
39
- end
40
- end
41
- rescue IOError, SystemCallError => e
42
- # do nothing
43
- ensure
44
- socket.close
45
- end
46
-
47
- # Returns a context hash for the given socket. This hash contains references
48
- # related to the connection and its current state
49
- # @param socket [Net::Socket] socket
50
- # @param handler [Proc] request handler
51
- # @return [Hash]
52
- def connection_context(socket, opts, handler)
53
- {
54
- can_upgrade: true,
55
- upgrade: opts[:upgrade],
56
- count: 0,
57
- socket: socket,
58
- handler: handler,
59
- parser: Http::Parser.new.async!,
60
- body: nil
61
- }
62
- end
63
-
64
- # Adds given chunk to request body
65
- # @param ctx [Hash] connection context
66
- # @return [void]
67
- def handle_body_chunk(context, chunk)
68
-
69
- context[:body] ||= +''
70
- context[:body] << chunk
71
- end
72
-
73
- # Handles request, upgrading the connection if possible
74
- # @param ctx [Hash] connection context
75
- # @return [boolean] true if HTTP 1 loop should continue handling socket
76
- def handle_request(ctx)
77
- return nil if ctx[:can_upgrade] && upgrade_connection(ctx)
78
-
79
- # allow upgrading the connection only on first request
80
- ctx[:can_upgrade] = false
81
- request = Request.new(ctx[:socket], ctx[:parser], ctx[:body])
82
- ctx[:handler].(request)
83
-
84
- if ctx[:parser].keep_alive?
85
- ctx[:body] = nil
86
- true
87
- else
88
- nil
89
- end
90
- end
91
-
92
- # Upgrades an HTTP 1 connection to HTTP/2 or other protocol on client request
93
- # @param ctx [Hash] connection context
94
- # @return [Boolean] true if connection was upgraded
95
- def upgrade_connection(ctx)
96
- upgrade_protocol = ctx[:parser].headers['Upgrade']
97
- return false unless upgrade_protocol
98
-
99
- if ctx[:upgrade] && ctx[:upgrade][upgrade_protocol.to_sym]
100
- ctx[:upgrade][upgrade_protocol.to_sym].(ctx[:socket], ctx[:parser].headers)
101
- return true
102
- end
103
-
104
- return false unless upgrade_protocol == 'h2c'
105
-
106
- # upgrade to HTTP/2
107
- request = http2_upgraded_request(ctx)
108
- body = ctx[:body] || ''
109
- HTTP2.upgrade(ctx[:socket], ctx[:handler], request, body)
110
- true
111
- end
112
-
113
- # Returns a request hash for handling by upgraded HTTP 2 connection
114
- # @param ctx [Hash] connection context
115
- # @return [Hash]
116
- def http2_upgraded_request(ctx)
117
- headers = ctx[:parser].headers
118
- headers.merge(
119
- ':scheme' => 'http',
120
- ':method' => ctx[:parser].http_method,
121
- ':authority' => headers['Host'],
122
- ':path' => ctx[:parser].request_url
123
- )
124
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- export_default :Request
4
-
5
- require 'uri'
6
-
7
- class Request
8
- def initialize(conn, parser, body)
9
- @conn = conn
10
- @parser = parser
11
- @method = parser.http_method
12
- @request_url = parser.request_url
13
- @body = body
14
- end
15
-
16
- def http_version
17
- 1
18
- end
19
-
20
- def method
21
- @method ||= @parser.http_method
22
- end
23
-
24
- def path
25
- @uri ||= URI.parse(@parser.request_url || '')
26
- @path ||= @uri.path
27
- end
28
-
29
- def query
30
- @uri ||= URI.parse(@parser.request_url || '')
31
- return @query if @query
32
-
33
- if (q = @uri.query)
34
- @query = q.split('&').each_with_object({}) do |kv, h|
35
- k, v = kv.split('=')
36
- h[k.to_sym] = URI.decode_www_form_component(v)
37
- end
38
- else
39
- @query = {}
40
- end
41
- end
42
-
43
- def headers
44
- @headers ||= @parser.headers
45
- end
46
-
47
- EMPTY_HASH = {}
48
-
49
- def respond(chunk, headers = EMPTY_HASH)
50
- status = headers.delete(':status') || 200
51
- data = format_head(headers)
52
- if chunk
53
- data << "#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n0\r\n\r\n"
54
- end
55
- @conn << data
56
- end
57
-
58
- def format_head(headers)
59
- status = headers[':status'] || 200
60
- data = +"HTTP/1.1 #{status}\r\nTransfer-Encoding: chunked\r\n"
61
- headers.each do |k, v|
62
- next if k =~ /^:/
63
- if v.is_a?(Array)
64
- v.each { |o| data << "#{k}: #{o}\r\n" }
65
- else
66
- data << "#{k}: #{v}\r\n"
67
- end
68
- end
69
- data << "\r\n"
70
- end
71
-
72
- def write_head(headers = EMPTY_HASH)
73
- @conn << format_head(headers)
74
- end
75
-
76
- def write(chunk)
77
- data = +"#{chunk.bytesize.to_s(16)}\r\n#{chunk}\r\n"
78
- end
79
-
80
- def finish
81
- @conn << "0\r\n\r\n"
82
- end
83
- end