polyphony 0.14 → 0.15
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -2
- data/Gemfile.lock +1 -1
- data/TODO.md +5 -0
- data/examples/core/genserver.rb +1 -1
- data/examples/{io → http}/config.ru +0 -0
- data/examples/{io → http}/happy_eyeballs.rb +7 -4
- data/examples/{io → http}/http_client.rb +2 -2
- data/examples/{io → http}/http_server.js +0 -0
- data/examples/http/http_server.rb +15 -0
- data/examples/{io → http}/http_server_forked.rb +7 -7
- data/examples/http/http_server_throttled.rb +16 -0
- data/examples/{io → http}/http_ws_server.rb +7 -10
- data/examples/http/https_raw_client.rb +13 -0
- data/examples/http/https_server.rb +19 -0
- data/examples/{io → http}/https_wss_server.rb +4 -10
- data/examples/http/rack_server.rb +14 -0
- data/examples/http/rack_server_https.rb +20 -0
- data/examples/{io → http}/rack_server_https_forked.rb +4 -8
- data/examples/http/websocket_secure_server.rb +30 -0
- data/examples/{io → http}/websocket_server.rb +4 -10
- data/examples/{io → http}/ws_page.html +0 -0
- data/examples/{io → http}/wss_page.html +0 -0
- data/examples/performance/perf_multi_snooze.rb +1 -1
- data/examples/performance/perf_snooze.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/ext/ev/ev_module.c +9 -4
- data/ext/ev/io.c +7 -1
- data/lib/polyphony/core/channel.rb +1 -1
- data/lib/polyphony/core/coprocess.rb +1 -1
- data/lib/polyphony/core/supervisor.rb +3 -2
- data/lib/polyphony/core.rb +1 -1
- data/lib/polyphony/extensions/io.rb +46 -45
- data/lib/polyphony/http/agent.rb +4 -4
- data/lib/polyphony/http/http1.rb +3 -3
- data/lib/polyphony/http/http2.rb +7 -7
- data/lib/polyphony/http/server.rb +9 -11
- data/lib/polyphony/http.rb +7 -0
- data/lib/polyphony/net.rb +1 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +10 -1
- data/test/test_io.rb +15 -5
- metadata +21 -20
- data/examples/io/http_server.rb +0 -16
- data/examples/io/http_server_throttled.rb +0 -16
- data/examples/io/https_client.rb +0 -17
- data/examples/io/https_server.rb +0 -23
- data/examples/io/rack_server.rb +0 -19
- data/examples/io/rack_server_https.rb +0 -24
- data/lib/polyphony/testing.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b20863a05d3f48a1b2af107ebeecb67c08cdeb20a7973cdcf6cf0e7ad3d31f7
|
4
|
+
data.tar.gz: 62753e931ed71137ef4cc3c2b1b011f69cfaf2e578da65c6b193b3c40dc88e5f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 075bbc81be5b7818f550186d6d5d4094e53245cd425743fff407b15573bcd7b4a7c9219d9628167589b13ea538c6202e72b5f782675135d397a6346323133391
|
7
|
+
data.tar.gz: d4c25633ff9f79a14ae978fbf3c8a2e51ce1b7a7c82d5ab4aa007dae26780d7b29deca39bf285c885f197b67f290f78c91bccf0faaeb22b13a0481cc664d5a57
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
+
0.15 2019-05-20
|
2
|
+
---------------
|
3
|
+
|
4
|
+
* Optimize `#next_tick` callback (about 6% faster than before)
|
5
|
+
* Fix IO#<< to return self
|
6
|
+
* Refactor HTTP code and examples
|
7
|
+
* Fix race condition in `Supervisor#stop!`
|
8
|
+
* Add `Kernel#snooze` method (`EV.snooze` will be deprecated eventually)
|
9
|
+
|
1
10
|
0.14 2019-05-17
|
2
11
|
---------------
|
3
12
|
|
4
13
|
* Use chunked encoding in HTTP 1 response
|
5
|
-
* Rewrite IO#read
|
14
|
+
* Rewrite `IO#read`, `#readpartial`, `#write` in C (about 30% performance improvement)
|
6
15
|
* Add method delegation to `ResourcePool`
|
7
16
|
* Optimize PG::Connection#async_exec
|
8
|
-
* Fix Coprocess#cancel
|
17
|
+
* Fix `Coprocess#cancel!`
|
9
18
|
* Preliminary support for websocket (see `examples/io/http_ws_server.rb`)
|
10
19
|
* Rename `Coroutine` to `Coprocess`
|
11
20
|
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
data/examples/core/genserver.rb
CHANGED
File without changes
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# idea taken from the example given in trio:
|
4
|
+
# https://www.youtube.com/watch?v=oLkfnc_UMcE
|
5
|
+
|
3
6
|
require 'modulation'
|
4
7
|
Polyphony = import('../../lib/polyphony')
|
5
8
|
|
6
|
-
async def try_connect(
|
9
|
+
async def try_connect(target, supervisor)
|
7
10
|
puts "trying #{target[2]}"
|
8
11
|
socket = Polyphony::Net.tcp_connect(target[2], 80)
|
9
12
|
supervisor.stop!([target[2], socket])
|
@@ -17,11 +20,11 @@ def happy_eyeballs(hostname, port, max_wait_time: 0.025)
|
|
17
20
|
success = supervise do |supervisor|
|
18
21
|
targets.each_with_index do |t, idx|
|
19
22
|
sleep(max_wait_time) if idx > 0
|
20
|
-
supervisor.spawn try_connect(
|
23
|
+
supervisor.spawn try_connect(t, supervisor)
|
21
24
|
end
|
22
25
|
end
|
23
26
|
if success
|
24
|
-
puts "success:
|
27
|
+
puts "success: %s (%.3fs)" % [success[0], Time.now - t0]
|
25
28
|
else
|
26
29
|
puts "timed out (#{Time.now - t0}s)"
|
27
30
|
end
|
@@ -29,4 +32,4 @@ def happy_eyeballs(hostname, port, max_wait_time: 0.025)
|
|
29
32
|
end
|
30
33
|
|
31
34
|
# Let's try it out:
|
32
|
-
happy_eyeballs("debian.org", "https")
|
35
|
+
happy_eyeballs("debian.org", "https")
|
@@ -9,11 +9,11 @@ def get_server_time
|
|
9
9
|
Agent.get('https://ui.realiteq.net/', q: :time).json
|
10
10
|
end
|
11
11
|
|
12
|
-
X =
|
12
|
+
X = 1
|
13
13
|
puts "Making #{X} requests..."
|
14
14
|
t0 = Time.now
|
15
15
|
supervise do |s|
|
16
16
|
X.times { get_server_time }
|
17
17
|
end
|
18
18
|
elapsed = Time.now - t0
|
19
|
-
puts "count: #{X} elapsed: #{elapsed} rate: #{X / elapsed} reqs/s"
|
19
|
+
puts "count: #{X} elapsed: #{elapsed} rate: #{X / elapsed} reqs/s"
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
opts = { reuse_addr: true, dont_linger: true }
|
8
|
+
spawn {
|
9
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
10
|
+
req.respond("Hello world!\n")
|
11
|
+
end
|
12
|
+
}
|
13
|
+
|
14
|
+
puts "pid: #{Process.pid}"
|
15
|
+
puts "Listening on port 1234..."
|
@@ -1,18 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'modulation'
|
4
|
-
require 'localhost/authority'
|
5
4
|
|
6
5
|
Polyphony = import('../../lib/polyphony')
|
7
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
8
6
|
|
9
7
|
opts = {
|
10
8
|
reuse_addr: true,
|
11
9
|
dont_linger: true,
|
12
10
|
}
|
13
|
-
|
14
|
-
|
15
|
-
end
|
11
|
+
|
12
|
+
server = Polyphony::HTTP::Server.listen('0.0.0.0', 1234, opts)
|
16
13
|
|
17
14
|
puts "Listening on port 1234"
|
18
15
|
|
@@ -20,8 +17,11 @@ child_pids = []
|
|
20
17
|
4.times do
|
21
18
|
child_pids << Polyphony.fork do
|
22
19
|
puts "forked pid: #{Process.pid}"
|
23
|
-
|
20
|
+
Polyphony::HTTP::Server.accept_loop(server, opts) do |req|
|
21
|
+
req.respond("Hello world!\n")
|
22
|
+
end
|
23
|
+
rescue Interrupt
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
child_pids.each { |pid| EV::Child.new(pid).await }
|
27
|
+
child_pids.each { |pid| EV::Child.new(pid).await }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
$throttler = throttle(1000)
|
8
|
+
opts = { reuse_addr: true, dont_linger: true }
|
9
|
+
spawn {
|
10
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
11
|
+
$throttler.call { req.respond("Hello world!\n") }
|
12
|
+
end
|
13
|
+
}
|
14
|
+
|
15
|
+
puts "pid: #{Process.pid}"
|
16
|
+
puts "Listening on port 1234..."
|
@@ -5,8 +5,6 @@ require 'modulation'
|
|
5
5
|
STDOUT.sync = true
|
6
6
|
|
7
7
|
Polyphony = import('../../lib/polyphony')
|
8
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
9
|
-
Websocket = import('../../lib/polyphony/websocket')
|
10
8
|
|
11
9
|
def ws_handler(conn)
|
12
10
|
timer = spawn {
|
@@ -25,18 +23,17 @@ opts = {
|
|
25
23
|
reuse_addr: true,
|
26
24
|
dont_linger: true,
|
27
25
|
upgrade: {
|
28
|
-
websocket: Websocket.handler(&method(:ws_handler))
|
26
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
29
27
|
}
|
30
28
|
}
|
31
29
|
|
32
30
|
HTML = IO.read(File.join(__dir__, 'ws_page.html'))
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
spawn {
|
33
|
+
server = Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
34
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
35
|
+
end
|
36
|
+
}
|
37
37
|
|
38
38
|
puts "pid: #{Process.pid}"
|
39
|
-
puts "Listening on port 1234..."
|
40
|
-
server.await
|
41
|
-
puts "bye bye"
|
42
|
-
|
39
|
+
puts "Listening on port 1234..."
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
|
5
|
+
Polyphony = import('../../lib/polyphony')
|
6
|
+
|
7
|
+
t0 = Time.now
|
8
|
+
io = Polyphony::Net.tcp_connect('realiteq.net', 443, secure: true)
|
9
|
+
io.write("GET /?q=time HTTP/1.0\r\nHost: realiteq.net\r\n\r\n")
|
10
|
+
reply = io.read
|
11
|
+
puts "time: #{Time.now - t0}"
|
12
|
+
puts
|
13
|
+
puts reply
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
|
8
|
+
authority = Localhost::Authority.fetch
|
9
|
+
opts = {
|
10
|
+
reuse_addr: true,
|
11
|
+
dont_linger: true,
|
12
|
+
secure_context: authority.server_context
|
13
|
+
}
|
14
|
+
|
15
|
+
puts "pid: #{Process.pid}"
|
16
|
+
puts "Listening on port 1234..."
|
17
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
18
|
+
req.respond("Hello world!\n")
|
19
|
+
end
|
@@ -6,8 +6,6 @@ require 'localhost/authority'
|
|
6
6
|
STDOUT.sync = true
|
7
7
|
|
8
8
|
Polyphony = import('../../lib/polyphony')
|
9
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
10
|
-
Websocket = import('../../lib/polyphony/websocket')
|
11
9
|
|
12
10
|
def ws_handler(conn)
|
13
11
|
timer = spawn {
|
@@ -29,18 +27,14 @@ opts = {
|
|
29
27
|
dont_linger: true,
|
30
28
|
secure_context: authority.server_context,
|
31
29
|
upgrade: {
|
32
|
-
websocket: Websocket.handler(&method(:ws_handler))
|
30
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
33
31
|
}
|
34
32
|
}
|
35
33
|
|
36
34
|
HTML = IO.read(File.join(__dir__, 'wss_page.html'))
|
37
35
|
|
38
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
39
|
-
req.respond(HTML, 'Content-Type' => 'text/html')
|
40
|
-
end
|
41
|
-
|
42
36
|
puts "pid: #{Process.pid}"
|
43
37
|
puts "Listening on port 1234..."
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
39
|
+
req.respond(HTML, 'Content-Type' => 'text/html')
|
40
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
|
8
|
+
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
9
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
10
|
+
opts = { reuse_addr: true, dont_linger: true }
|
11
|
+
|
12
|
+
puts "listening on port 1234"
|
13
|
+
puts "pid: #{Process.pid}"
|
14
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts, &app)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
Polyphony = import('../../lib/polyphony')
|
7
|
+
|
8
|
+
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
9
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
10
|
+
|
11
|
+
authority = Localhost::Authority.fetch
|
12
|
+
opts = {
|
13
|
+
reuse_addr: true,
|
14
|
+
dont_linger: true,
|
15
|
+
secure_context: authority.server_context
|
16
|
+
}
|
17
|
+
|
18
|
+
puts "listening on port 1234"
|
19
|
+
puts "pid: #{Process.pid}"
|
20
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts, &app)
|
@@ -4,11 +4,9 @@ require 'modulation'
|
|
4
4
|
require 'localhost/authority'
|
5
5
|
|
6
6
|
Polyphony = import('../../lib/polyphony')
|
7
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
-
Rack = import('../../lib/polyphony/http/rack')
|
9
7
|
|
10
8
|
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
11
|
-
|
9
|
+
app = Polyphony::HTTP::Rack.load(app_path)
|
12
10
|
|
13
11
|
authority = Localhost::Authority.fetch
|
14
12
|
opts = {
|
@@ -16,17 +14,15 @@ opts = {
|
|
16
14
|
dont_linger: true,
|
17
15
|
secure_context: authority.server_context
|
18
16
|
}
|
19
|
-
|
17
|
+
server = Polyphony::HTTP::Server.listen('0.0.0.0', 1234, opts)
|
20
18
|
puts "Listening on port 1234"
|
21
19
|
|
22
20
|
child_pids = []
|
23
21
|
4.times do
|
24
22
|
child_pids << Polyphony.fork do
|
25
23
|
puts "forked pid: #{Process.pid}"
|
26
|
-
|
24
|
+
Polyphony::HTTP::Server.accept_loop(server, opts, &app)
|
27
25
|
end
|
28
26
|
end
|
29
27
|
|
30
|
-
|
31
|
-
child_pids.each { |pid| EV::Child.new(pid).await }
|
32
|
-
end
|
28
|
+
child_pids.each { |pid| EV::Child.new(pid).await }
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'modulation'
|
4
|
+
require 'localhost/authority'
|
5
|
+
|
6
|
+
STDOUT.sync = true
|
7
|
+
|
8
|
+
Polyphony = import('../../lib/polyphony')
|
9
|
+
|
10
|
+
def ws_handler(conn)
|
11
|
+
while msg = conn.recv
|
12
|
+
conn << "you said: #{msg}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
authority = Localhost::Authority.fetch
|
17
|
+
opts = {
|
18
|
+
reuse_addr: true,
|
19
|
+
dont_linger: true,
|
20
|
+
upgrade: {
|
21
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
22
|
+
},
|
23
|
+
secure_context: authority.server_context
|
24
|
+
}
|
25
|
+
|
26
|
+
puts "pid: #{Process.pid}"
|
27
|
+
puts "Listening on port 1234..."
|
28
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
29
|
+
req.respond("Hello world!\n")
|
30
|
+
end
|
@@ -5,8 +5,6 @@ require 'modulation'
|
|
5
5
|
STDOUT.sync = true
|
6
6
|
|
7
7
|
Polyphony = import('../../lib/polyphony')
|
8
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
9
|
-
Websocket = import('../../lib/polyphony/websocket')
|
10
8
|
|
11
9
|
def ws_handler(conn)
|
12
10
|
while msg = conn.recv
|
@@ -18,16 +16,12 @@ opts = {
|
|
18
16
|
reuse_addr: true,
|
19
17
|
dont_linger: true,
|
20
18
|
upgrade: {
|
21
|
-
websocket: Websocket.handler(&method(:ws_handler))
|
19
|
+
websocket: Polyphony::Websocket.handler(&method(:ws_handler))
|
22
20
|
}
|
23
21
|
}
|
24
22
|
|
25
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
26
|
-
req.respond("Hello world!\n")
|
27
|
-
end
|
28
|
-
|
29
23
|
puts "pid: #{Process.pid}"
|
30
24
|
puts "Listening on port 1234..."
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
Polyphony::HTTP::Server.serve('0.0.0.0', 1234, opts) do |req|
|
26
|
+
req.respond("Hello world!\n")
|
27
|
+
end
|
File without changes
|
File without changes
|
data/ext/ev/ev_module.c
CHANGED
@@ -55,6 +55,7 @@ void Init_EV() {
|
|
55
55
|
rb_define_singleton_method(mEV, "schedule_fiber", EV_schedule_fiber, 2);
|
56
56
|
|
57
57
|
rb_define_method(rb_mKernel, "suspend", EV_suspend, 0);
|
58
|
+
rb_define_method(rb_mKernel, "snooze", EV_snooze, 0);
|
58
59
|
|
59
60
|
ID_call = rb_intern("call");
|
60
61
|
ID_caller = rb_intern("caller");
|
@@ -175,7 +176,7 @@ static VALUE EV_post_fork(VALUE self) {
|
|
175
176
|
return Qnil;
|
176
177
|
}
|
177
178
|
|
178
|
-
VALUE
|
179
|
+
VALUE EV_next_tick_runner(VALUE proc) {
|
179
180
|
if (rb_obj_is_proc(proc)) {
|
180
181
|
rb_funcall(proc, ID_call, 1, Qtrue);
|
181
182
|
}
|
@@ -186,9 +187,13 @@ VALUE EV_next_tick_caller(VALUE proc, VALUE data, int argc, VALUE* argv) {
|
|
186
187
|
}
|
187
188
|
|
188
189
|
void EV_next_tick_callback(ev_loop *ev_loop, struct ev_timer *timer, int revents) {
|
189
|
-
VALUE scheduled_procs =
|
190
|
-
|
191
|
-
|
190
|
+
VALUE scheduled_procs = next_tick_procs;
|
191
|
+
next_tick_procs = rb_ary_new();
|
192
|
+
|
193
|
+
for (long i = 0; i < RARRAY_LEN(scheduled_procs); i++) {
|
194
|
+
EV_next_tick_runner(RARRAY_AREF(scheduled_procs, i));
|
195
|
+
}
|
196
|
+
|
192
197
|
if (rb_array_len(next_tick_procs) > 0) {
|
193
198
|
ev_timer_start(EV_DEFAULT, &next_tick_timer);
|
194
199
|
} else {
|
data/ext/ev/io.c
CHANGED
@@ -35,6 +35,7 @@ static int EV_IO_symbol2event_mask(VALUE sym);
|
|
35
35
|
static VALUE IO_read(int argc, VALUE *argv, VALUE io);
|
36
36
|
static VALUE IO_readpartial(int argc, VALUE *argv, VALUE io);
|
37
37
|
static VALUE IO_write(int argc, VALUE *argv, VALUE io);
|
38
|
+
static VALUE IO_write_chevron(VALUE io, VALUE str);
|
38
39
|
|
39
40
|
void Init_EV_IO() {
|
40
41
|
mEV = rb_define_module("EV");
|
@@ -51,7 +52,7 @@ void Init_EV_IO() {
|
|
51
52
|
rb_define_method(cIO, "readpartial", IO_readpartial, -1);
|
52
53
|
rb_define_method(cIO, "write", IO_write, -1);
|
53
54
|
rb_define_method(cIO, "write_nonblock", IO_write, -1);
|
54
|
-
rb_define_method(cIO, "<<",
|
55
|
+
rb_define_method(cIO, "<<", IO_write_chevron, 1);
|
55
56
|
}
|
56
57
|
|
57
58
|
static const rb_data_type_t EV_IO_type = {
|
@@ -403,3 +404,8 @@ static VALUE IO_write(int argc, VALUE *argv, VALUE io) {
|
|
403
404
|
|
404
405
|
return LONG2FIX(total);
|
405
406
|
}
|
407
|
+
|
408
|
+
static VALUE IO_write_chevron(VALUE io, VALUE str) {
|
409
|
+
IO_write(1, &str, io);
|
410
|
+
return io;
|
411
|
+
}
|
@@ -54,9 +54,10 @@ class Supervisor
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def stop!(result = nil)
|
57
|
-
return unless @supervisor_fiber
|
57
|
+
return unless @supervisor_fiber && !@stopped
|
58
58
|
|
59
|
-
@
|
59
|
+
@stopped = true
|
60
|
+
@supervisor_fiber.transfer Exceptions::MoveOn.new(nil, result)
|
60
61
|
end
|
61
62
|
|
62
63
|
def stop_all_tasks
|
data/lib/polyphony/core.rb
CHANGED
@@ -41,5 +41,5 @@ at_exit do
|
|
41
41
|
# in most cases, by the main fiber is done there are still pending or other
|
42
42
|
# or asynchronous operations going on. If the reactor loop is not done, we
|
43
43
|
# suspend the root fiber until it is done
|
44
|
-
suspend if $__reactor_fiber__
|
44
|
+
suspend if $__reactor_fiber__&.alive?
|
45
45
|
end
|
@@ -14,50 +14,51 @@ class ::IO
|
|
14
14
|
@write_watcher&.stop
|
15
15
|
end
|
16
16
|
|
17
|
-
#
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
#
|
26
|
-
#
|
27
|
-
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
#
|
45
|
-
# end
|
46
|
-
|
47
|
-
#
|
48
|
-
#
|
49
|
-
|
50
|
-
#
|
51
|
-
#
|
52
|
-
|
53
|
-
#
|
54
|
-
#
|
55
|
-
|
56
|
-
#
|
57
|
-
#
|
58
|
-
|
59
|
-
#
|
60
|
-
#
|
61
|
-
|
17
|
+
# def each(sep = $/, limit = nil, chomp: nil)
|
18
|
+
# sep, limit = $/, sep if sep.is_a?(Integer)
|
19
|
+
# end
|
20
|
+
# alias_method :each_line, :each
|
21
|
+
|
22
|
+
# def each_byte
|
23
|
+
# end
|
24
|
+
|
25
|
+
# def each_char
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def each_codepoint
|
29
|
+
# end
|
30
|
+
|
31
|
+
# def getbyte
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def getc
|
35
|
+
# end
|
36
|
+
|
37
|
+
# def gets(sep = $/, limit = nil, chomp: nil)
|
38
|
+
# sep, limit = $/, sep if sep.is_a?(Integer)
|
39
|
+
# end
|
40
|
+
|
41
|
+
# def print(*args)
|
42
|
+
# end
|
43
|
+
|
44
|
+
# def printf(format, *args)
|
45
|
+
# end
|
46
|
+
|
47
|
+
# def putc(obj)
|
48
|
+
# end
|
49
|
+
|
50
|
+
# def puts(*args)
|
51
|
+
# end
|
52
|
+
|
53
|
+
# def readbyte
|
54
|
+
# end
|
55
|
+
|
56
|
+
# def readchar
|
57
|
+
# end
|
58
|
+
|
59
|
+
# def readline(sep = $/, limit = nil, chomp: nil)
|
60
|
+
# end
|
61
|
+
|
62
|
+
# def readlines(sep = $/, limit = nil, chomp: nil)
|
62
63
|
# end
|
63
64
|
end
|
data/lib/polyphony/http/agent.rb
CHANGED
@@ -51,8 +51,8 @@ class Agent
|
|
51
51
|
|
52
52
|
def request(url, opts = OPTS_DEFAULT)
|
53
53
|
ctx = request_ctx(url, opts)
|
54
|
-
response = do_request(ctx)
|
55
54
|
|
55
|
+
response = do_request(ctx)
|
56
56
|
case response[:status_code]
|
57
57
|
when 301, 302
|
58
58
|
request(response[:headers]['Location'])
|
@@ -115,7 +115,7 @@ class Agent
|
|
115
115
|
|
116
116
|
state[:socket] << request
|
117
117
|
while !done
|
118
|
-
parser << state[:socket].
|
118
|
+
parser << state[:socket].readpartial(8192)
|
119
119
|
end
|
120
120
|
|
121
121
|
{
|
@@ -159,14 +159,14 @@ class Agent
|
|
159
159
|
stream.on(:close) {
|
160
160
|
done = true
|
161
161
|
return {
|
162
|
-
protocol: '
|
162
|
+
protocol: 'http2',
|
163
163
|
status_code: headers && headers[':status'].to_i,
|
164
164
|
headers: headers || {},
|
165
165
|
body: body
|
166
166
|
}
|
167
167
|
}
|
168
168
|
|
169
|
-
while data = state[:socket].
|
169
|
+
while data = state[:socket].readpartial(8192)
|
170
170
|
state[:http2_client] << data
|
171
171
|
end
|
172
172
|
ensure
|
data/lib/polyphony/http/http1.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
export :
|
3
|
+
export :call
|
4
4
|
|
5
5
|
require 'http/parser'
|
6
6
|
|
@@ -26,7 +26,7 @@ end
|
|
26
26
|
# @param socket [Net::Socket] socket
|
27
27
|
# @param handler [Proc] request handler
|
28
28
|
# @return [void]
|
29
|
-
def
|
29
|
+
def call(socket, opts, &handler)
|
30
30
|
ctx = connection_context(socket, opts, handler)
|
31
31
|
ctx[:parser].on_body = proc { |chunk| handle_body_chunk(ctx, chunk) }
|
32
32
|
|
@@ -35,7 +35,7 @@ def run(socket, opts, handler)
|
|
35
35
|
break unless data
|
36
36
|
if ctx[:parser].parse(data)
|
37
37
|
break unless handle_request(ctx)
|
38
|
-
|
38
|
+
snooze
|
39
39
|
end
|
40
40
|
end
|
41
41
|
rescue IOError, SystemCallError => e
|
data/lib/polyphony/http/http2.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
export :
|
3
|
+
export :call, :upgrade
|
4
4
|
|
5
5
|
require 'http/2'
|
6
6
|
|
7
7
|
Request = import('./http2_request')
|
8
8
|
|
9
|
+
def call(socket, opts, &handler)
|
10
|
+
interface = prepare(socket, handler)
|
11
|
+
client_loop(socket, interface)
|
12
|
+
end
|
13
|
+
|
9
14
|
UPGRADE_MESSAGE = <<~HTTP.gsub("\n", "\r\n")
|
10
15
|
HTTP/1.1 101 Switching Protocols
|
11
16
|
Connection: Upgrade
|
@@ -28,17 +33,12 @@ def prepare(socket, handler)
|
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
def run(socket, opts, handler)
|
32
|
-
interface = prepare(socket, handler)
|
33
|
-
client_loop(socket, interface)
|
34
|
-
end
|
35
|
-
|
36
36
|
def client_loop(socket, interface)
|
37
37
|
loop do
|
38
38
|
data = socket.readpartial(8192)
|
39
39
|
break unless data
|
40
40
|
interface << data
|
41
|
-
|
41
|
+
snooze
|
42
42
|
end
|
43
43
|
rescue IOError, SystemCallError => e
|
44
44
|
# do nothing
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
export :serve, :
|
3
|
+
export :serve, :listen, :accept_loop
|
4
4
|
|
5
5
|
Net = import('../net')
|
6
6
|
HTTP1 = import('./http1')
|
@@ -9,31 +9,29 @@ HTTP2 = import('./http2')
|
|
9
9
|
ALPN_PROTOCOLS = %w[h2 http/1.1].freeze
|
10
10
|
H2_PROTOCOL = 'h2'
|
11
11
|
|
12
|
-
|
12
|
+
def serve(host, port, opts = {}, &handler)
|
13
13
|
opts[:alpn_protocols] = ALPN_PROTOCOLS
|
14
14
|
server = Net.tcp_listen(host, port, opts)
|
15
|
-
|
16
|
-
accept_loop(server, opts, handler)
|
15
|
+
accept_loop(server, opts, &handler)
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
18
|
+
def listen(host, port, opts = {})
|
20
19
|
opts[:alpn_protocols] = ALPN_PROTOCOLS
|
21
|
-
|
22
|
-
proc { accept_loop(server, opts, handler) }
|
20
|
+
Net.tcp_listen(host, port, opts)
|
23
21
|
end
|
24
22
|
|
25
|
-
def accept_loop(server, opts, handler)
|
23
|
+
def accept_loop(server, opts, &handler)
|
26
24
|
while true
|
27
25
|
client = server.accept
|
28
|
-
spawn client_task(client, opts, handler)
|
26
|
+
spawn { client_task(client, opts, &handler) }
|
29
27
|
end
|
30
28
|
rescue OpenSSL::SSL::SSLError
|
31
29
|
retry # disregard
|
32
30
|
end
|
33
31
|
|
34
|
-
|
32
|
+
def client_task(client, opts, &handler)
|
35
33
|
client.no_delay rescue nil
|
36
|
-
protocol_module(client).
|
34
|
+
protocol_module(client).(client, opts, &handler)
|
37
35
|
end
|
38
36
|
|
39
37
|
def protocol_module(socket)
|
data/lib/polyphony/net.rb
CHANGED
@@ -8,6 +8,7 @@ import('./extensions/socket')
|
|
8
8
|
import('./extensions/ssl')
|
9
9
|
|
10
10
|
def tcp_connect(host, port, opts = {})
|
11
|
+
puts "tcp_connect(#{host.inspect}, #{port.inspect}, #{opts.inspect})"
|
11
12
|
socket = ::Socket.new(:INET, :STREAM).tap { |s|
|
12
13
|
addr = ::Socket.sockaddr_in(port, host)
|
13
14
|
s.connect(addr)
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
@@ -26,6 +26,15 @@ module Polyphony
|
|
26
26
|
FS: './polyphony/fs',
|
27
27
|
# Net: './polyphony/net',
|
28
28
|
ResourcePool: './polyphony/resource_pool',
|
29
|
-
Supervisor: './polyphony/supervisor'
|
29
|
+
Supervisor: './polyphony/supervisor',
|
30
|
+
Websocket: './polyphony/websocket'
|
30
31
|
)
|
32
|
+
|
33
|
+
module HTTP
|
34
|
+
auto_import(
|
35
|
+
Agent: './polyphony/http/agent',
|
36
|
+
Rack: './polyphony/http/rack',
|
37
|
+
Server: './polyphony/http/server',
|
38
|
+
)
|
39
|
+
end
|
31
40
|
end
|
data/test/test_io.rb
CHANGED
@@ -8,16 +8,16 @@ module IOTests
|
|
8
8
|
class IOTest < MiniTest::Test
|
9
9
|
def setup
|
10
10
|
EV.rerun
|
11
|
+
@i, @o = IO.pipe
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
i, o = IO.pipe
|
14
|
+
def test_that_io_op_yields_to_other_fibers
|
15
15
|
count = 0
|
16
16
|
msg = nil
|
17
17
|
[
|
18
18
|
spawn {
|
19
|
-
o.write("hello")
|
20
|
-
o.close
|
19
|
+
@o.write("hello")
|
20
|
+
@o.close
|
21
21
|
},
|
22
22
|
|
23
23
|
spawn {
|
@@ -28,11 +28,21 @@ module IOTests
|
|
28
28
|
},
|
29
29
|
|
30
30
|
spawn {
|
31
|
-
msg = i.read
|
31
|
+
msg = @i.read
|
32
32
|
}
|
33
33
|
].each(&:await)
|
34
34
|
assert_equal(5, count)
|
35
35
|
assert_equal("hello", msg)
|
36
36
|
end
|
37
|
+
|
38
|
+
def test_that_double_chevron_method_returns_io
|
39
|
+
assert_equal(@o, @o << 'foo')
|
40
|
+
|
41
|
+
@o << 'bar' << 'baz'
|
42
|
+
@o.close
|
43
|
+
assert_equal('foobarbaz', @i.read)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_
|
37
47
|
end
|
38
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.15'
|
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-
|
11
|
+
date: 2019-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: modulation
|
@@ -148,6 +148,24 @@ files:
|
|
148
148
|
- examples/core/thread_pool.rb
|
149
149
|
- examples/core/throttle.rb
|
150
150
|
- examples/fs/read.rb
|
151
|
+
- examples/http/config.ru
|
152
|
+
- examples/http/happy_eyeballs.rb
|
153
|
+
- examples/http/http_client.rb
|
154
|
+
- examples/http/http_server.js
|
155
|
+
- examples/http/http_server.rb
|
156
|
+
- examples/http/http_server_forked.rb
|
157
|
+
- examples/http/http_server_throttled.rb
|
158
|
+
- examples/http/http_ws_server.rb
|
159
|
+
- examples/http/https_raw_client.rb
|
160
|
+
- examples/http/https_server.rb
|
161
|
+
- examples/http/https_wss_server.rb
|
162
|
+
- examples/http/rack_server.rb
|
163
|
+
- examples/http/rack_server_https.rb
|
164
|
+
- examples/http/rack_server_https_forked.rb
|
165
|
+
- examples/http/websocket_secure_server.rb
|
166
|
+
- examples/http/websocket_server.rb
|
167
|
+
- examples/http/ws_page.html
|
168
|
+
- examples/http/wss_page.html
|
151
169
|
- examples/interfaces/pg_client.rb
|
152
170
|
- examples/interfaces/pg_pool.rb
|
153
171
|
- examples/interfaces/pg_query.rb
|
@@ -155,27 +173,10 @@ files:
|
|
155
173
|
- examples/interfaces/redis_client.rb
|
156
174
|
- examples/interfaces/redis_pubsub.rb
|
157
175
|
- examples/interfaces/redis_pubsub_perf.rb
|
158
|
-
- examples/io/config.ru
|
159
176
|
- examples/io/echo_client.rb
|
160
177
|
- examples/io/echo_server.rb
|
161
178
|
- examples/io/echo_server_with_timeout.rb
|
162
179
|
- examples/io/echo_stdin.rb
|
163
|
-
- examples/io/happy_eyeballs.rb
|
164
|
-
- examples/io/http_client.rb
|
165
|
-
- examples/io/http_server.js
|
166
|
-
- examples/io/http_server.rb
|
167
|
-
- examples/io/http_server_forked.rb
|
168
|
-
- examples/io/http_server_throttled.rb
|
169
|
-
- examples/io/http_ws_server.rb
|
170
|
-
- examples/io/https_client.rb
|
171
|
-
- examples/io/https_server.rb
|
172
|
-
- examples/io/https_wss_server.rb
|
173
|
-
- examples/io/rack_server.rb
|
174
|
-
- examples/io/rack_server_https.rb
|
175
|
-
- examples/io/rack_server_https_forked.rb
|
176
|
-
- examples/io/websocket_server.rb
|
177
|
-
- examples/io/ws_page.html
|
178
|
-
- examples/io/wss_page.html
|
179
180
|
- examples/performance/perf_multi_snooze.rb
|
180
181
|
- examples/performance/perf_snooze.rb
|
181
182
|
- examples/performance/thread-vs-fiber/polyphony_server.rb
|
@@ -226,6 +227,7 @@ files:
|
|
226
227
|
- lib/polyphony/extensions/socket.rb
|
227
228
|
- lib/polyphony/extensions/ssl.rb
|
228
229
|
- lib/polyphony/fs.rb
|
230
|
+
- lib/polyphony/http.rb
|
229
231
|
- lib/polyphony/http/agent.rb
|
230
232
|
- lib/polyphony/http/http1.rb
|
231
233
|
- lib/polyphony/http/http1_request.rb
|
@@ -237,7 +239,6 @@ files:
|
|
237
239
|
- lib/polyphony/net.rb
|
238
240
|
- lib/polyphony/resource_pool.rb
|
239
241
|
- lib/polyphony/server_task.rb
|
240
|
-
- lib/polyphony/testing.rb
|
241
242
|
- lib/polyphony/version.rb
|
242
243
|
- lib/polyphony/websocket.rb
|
243
244
|
- polyphony.gemspec
|
data/examples/io/http_server.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
|
5
|
-
Polyphony = import('../../lib/polyphony')
|
6
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
7
|
-
|
8
|
-
opts = { reuse_addr: true, dont_linger: true }
|
9
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
10
|
-
req.respond("Hello world!\n")
|
11
|
-
end
|
12
|
-
puts "pid: #{Process.pid}"
|
13
|
-
puts "Listening on port 1234..."
|
14
|
-
server.await
|
15
|
-
puts "bye bye"
|
16
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
|
5
|
-
Polyphony = import('../../lib/polyphony')
|
6
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
7
|
-
|
8
|
-
$throttler = throttle(1000)
|
9
|
-
opts = { reuse_addr: true, dont_linger: true }
|
10
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
11
|
-
$throttler.call { req.respond("Hello world!\n") }
|
12
|
-
end
|
13
|
-
puts "pid: #{Process.pid}"
|
14
|
-
puts "Listening on port 1234..."
|
15
|
-
server.await
|
16
|
-
puts "bye bye"
|
data/examples/io/https_client.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
|
5
|
-
Polyphony = import('../../lib/polyphony')
|
6
|
-
|
7
|
-
spawn do
|
8
|
-
t0 = Time.now
|
9
|
-
io = Polyphony::Net.tcp_connect('google.com', 443, secure: true)
|
10
|
-
io.write("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
|
11
|
-
reply = io.read(2**16)
|
12
|
-
puts "time: #{Time.now - t0}"
|
13
|
-
puts
|
14
|
-
puts reply
|
15
|
-
rescue => e
|
16
|
-
p e
|
17
|
-
end
|
data/examples/io/https_server.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
require 'localhost/authority'
|
5
|
-
|
6
|
-
Polyphony = import('../../lib/polyphony')
|
7
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
-
|
9
|
-
spawn do
|
10
|
-
authority = Localhost::Authority.fetch
|
11
|
-
opts = {
|
12
|
-
reuse_addr: true,
|
13
|
-
dont_linger: true,
|
14
|
-
secure_context: authority.server_context
|
15
|
-
}
|
16
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts) do |req|
|
17
|
-
req.respond("Hello world!\n")
|
18
|
-
end
|
19
|
-
server.await
|
20
|
-
end
|
21
|
-
|
22
|
-
puts "pid: #{Process.pid}"
|
23
|
-
puts "Listening on port 1234..."
|
data/examples/io/rack_server.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
require 'localhost/authority'
|
5
|
-
|
6
|
-
Polyphony = import('../../lib/polyphony')
|
7
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
-
Rack = import('../../lib/polyphony/http/rack')
|
9
|
-
|
10
|
-
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
11
|
-
rack = Rack.load(app_path)
|
12
|
-
|
13
|
-
spawn do
|
14
|
-
opts = { reuse_addr: true, dont_linger: true }
|
15
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts, &rack)
|
16
|
-
puts "listening on port 1234"
|
17
|
-
puts "pid: #{Process.pid}"
|
18
|
-
server.await
|
19
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'modulation'
|
4
|
-
require 'localhost/authority'
|
5
|
-
|
6
|
-
Polyphony = import('../../lib/polyphony')
|
7
|
-
HTTPServer = import('../../lib/polyphony/http/server')
|
8
|
-
Rack = import('../../lib/polyphony/http/rack')
|
9
|
-
|
10
|
-
app_path = ARGV.first || File.expand_path('./config.ru', __dir__)
|
11
|
-
rack = Rack.load(app_path)
|
12
|
-
|
13
|
-
spawn do
|
14
|
-
authority = Localhost::Authority.fetch
|
15
|
-
opts = {
|
16
|
-
reuse_addr: true,
|
17
|
-
dont_linger: true,
|
18
|
-
secure_context: authority.server_context
|
19
|
-
}
|
20
|
-
server = HTTPServer.serve('0.0.0.0', 1234, opts, &rack)
|
21
|
-
puts "listening on port 1234"
|
22
|
-
puts "pid: #{Process.pid}"
|
23
|
-
server.await
|
24
|
-
end
|
data/lib/polyphony/testing.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
Core = import('./core')
|
4
|
-
|
5
|
-
# Fiber used for running reactor loop
|
6
|
-
ReactorLoopFiber = Fiber.new do
|
7
|
-
Polyphony.run_reactor
|
8
|
-
end
|
9
|
-
|
10
|
-
# Monkey-patch core module with async/await methods
|
11
|
-
module Core
|
12
|
-
# Processes a promise by running reactor loop until promise is completed
|
13
|
-
# @param promise [Promise] promise
|
14
|
-
# @param more [Array<Promise>] more promises
|
15
|
-
# @return [any] resolved value
|
16
|
-
def self.await(promise = {}, *more)
|
17
|
-
return await_all(promise, *more) unless more.empty?
|
18
|
-
|
19
|
-
# raise FiberError, AWAIT_ERROR_MSG unless Fiber.current.async?
|
20
|
-
if promise.completed?
|
21
|
-
return_value = promise.clear_result
|
22
|
-
else
|
23
|
-
ReactorLoopFiber.transfer until promise.completed?
|
24
|
-
return_value = promise.result
|
25
|
-
end
|
26
|
-
return_value.is_a?(Exception) ? raise(return_value) : return_value
|
27
|
-
end
|
28
|
-
|
29
|
-
# Runs given block
|
30
|
-
# @return [void]
|
31
|
-
def self.async(&block)
|
32
|
-
block.()
|
33
|
-
end
|
34
|
-
end
|