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,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