polyphony 0.17 → 0.19

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