polyphony 0.19 → 0.20
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/.gitignore +1 -1
- data/.rubocop.yml +87 -1
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +17 -6
- data/README.md +200 -139
- data/Rakefile +4 -4
- data/TODO.md +35 -7
- data/bin/poly +11 -0
- data/docs/getting-started/getting-started.md +1 -1
- data/docs/summary.md +3 -0
- data/docs/technical-overview/exception-handling.md +94 -0
- data/docs/technical-overview/fiber-scheduling.md +99 -0
- data/examples/core/cancel.rb +8 -4
- data/examples/core/channel_echo.rb +18 -17
- data/examples/core/defer.rb +12 -0
- data/examples/core/enumerator.rb +4 -4
- data/examples/core/fiber_error.rb +9 -0
- data/examples/core/fiber_error_with_backtrace.rb +73 -0
- data/examples/core/fork.rb +6 -6
- data/examples/core/genserver.rb +16 -8
- data/examples/core/lock.rb +3 -3
- data/examples/core/move_on.rb +4 -3
- data/examples/core/move_on_twice.rb +5 -5
- data/examples/core/move_on_with_ensure.rb +8 -11
- data/examples/core/move_on_with_value.rb +14 -0
- data/examples/core/{multiple_spawn.rb → multiple_spin.rb} +5 -5
- data/examples/core/nested_cancel.rb +5 -5
- data/examples/core/{nested_multiple_spawn.rb → nested_multiple_spin.rb} +6 -6
- data/examples/core/nested_spin.rb +17 -0
- data/examples/core/pingpong.rb +21 -0
- data/examples/core/pulse.rb +4 -5
- data/examples/core/resource.rb +6 -4
- data/examples/core/resource_cancel.rb +6 -9
- data/examples/core/resource_delegate.rb +3 -3
- data/examples/core/sleep.rb +3 -3
- data/examples/core/sleep_spin.rb +19 -0
- data/examples/core/snooze.rb +32 -0
- data/examples/core/spin.rb +14 -0
- data/examples/core/{spawn_cancel.rb → spin_cancel.rb} +6 -7
- data/examples/core/spin_error.rb +17 -0
- data/examples/core/spin_error_backtrace.rb +30 -0
- data/examples/core/spin_uncaught_error.rb +15 -0
- data/examples/core/supervisor.rb +8 -8
- data/examples/core/supervisor_with_cancel_scope.rb +7 -7
- data/examples/core/supervisor_with_error.rb +8 -8
- data/examples/core/supervisor_with_manual_move_on.rb +6 -7
- data/examples/core/suspend.rb +13 -0
- data/examples/core/thread.rb +1 -1
- data/examples/core/thread_cancel.rb +9 -11
- data/examples/core/thread_pool.rb +18 -14
- data/examples/core/throttle.rb +7 -7
- data/examples/core/timeout.rb +3 -3
- data/examples/fs/read.rb +7 -9
- data/examples/http/config.ru +7 -3
- data/examples/http/cuba.ru +22 -0
- data/examples/http/happy_eyeballs.rb +6 -4
- data/examples/http/http_client.rb +1 -1
- data/examples/http/http_get.rb +1 -1
- data/examples/http/http_parse_experiment.rb +21 -16
- data/examples/http/http_proxy.rb +28 -26
- data/examples/http/http_server.rb +10 -10
- data/examples/http/http_server_forked.rb +6 -5
- data/examples/http/http_server_throttled.rb +3 -3
- data/examples/http/http_ws_server.rb +11 -11
- data/examples/http/https_raw_client.rb +1 -1
- data/examples/http/https_server.rb +8 -8
- data/examples/http/https_wss_server.rb +13 -11
- data/examples/http/rack_server.rb +2 -2
- data/examples/http/rack_server_https.rb +4 -4
- data/examples/http/rack_server_https_forked.rb +5 -5
- data/examples/http/websocket_secure_server.rb +6 -6
- data/examples/http/websocket_server.rb +5 -5
- data/examples/interfaces/pg_client.rb +4 -4
- data/examples/interfaces/pg_pool.rb +13 -6
- data/examples/interfaces/pg_transaction.rb +5 -4
- data/examples/interfaces/redis_channels.rb +15 -11
- data/examples/interfaces/redis_client.rb +2 -2
- data/examples/interfaces/redis_pubsub.rb +2 -1
- data/examples/interfaces/redis_pubsub_perf.rb +13 -9
- data/examples/io/backticks.rb +11 -0
- data/examples/io/cat.rb +4 -5
- data/examples/io/echo_client.rb +9 -4
- data/examples/io/echo_client_from_stdin.rb +20 -0
- data/examples/io/echo_pipe.rb +7 -8
- data/examples/io/echo_server.rb +8 -6
- data/examples/io/echo_server_with_timeout.rb +13 -10
- data/examples/io/echo_stdin.rb +3 -3
- data/examples/io/httparty.rb +2 -2
- data/examples/io/httparty_multi.rb +8 -4
- data/examples/io/httparty_threaded.rb +6 -2
- data/examples/io/io_read.rb +2 -2
- data/examples/io/irb.rb +16 -4
- data/examples/io/net-http.rb +3 -3
- data/examples/io/open.rb +17 -0
- data/examples/io/system.rb +3 -3
- data/examples/io/tcpserver.rb +15 -0
- data/examples/io/tcpsocket.rb +6 -5
- data/examples/performance/multi_snooze.rb +29 -0
- data/examples/performance/{perf_snooze.rb → snooze.rb} +7 -5
- data/examples/performance/snooze_raw.rb +39 -0
- data/ext/gyro/async.c +165 -0
- data/ext/gyro/child.c +167 -0
- data/ext/{ev → gyro}/extconf.rb +4 -3
- data/ext/gyro/gyro.c +316 -0
- data/ext/{ev/ev.h → gyro/gyro.h} +12 -7
- data/ext/gyro/gyro_ext.c +23 -0
- data/ext/{ev → gyro}/io.c +65 -57
- data/ext/{ev → gyro}/libev.h +0 -0
- data/ext/gyro/signal.c +117 -0
- data/ext/{ev → gyro}/socket.c +61 -6
- data/ext/gyro/timer.c +199 -0
- data/ext/libev/Changes +35 -0
- data/ext/libev/README +2 -1
- data/ext/libev/ev.c +213 -151
- data/ext/libev/ev.h +95 -88
- data/ext/libev/ev_epoll.c +26 -15
- data/ext/libev/ev_kqueue.c +11 -5
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +13 -8
- data/ext/libev/ev_port.c +5 -2
- data/ext/libev/ev_vars.h +14 -3
- data/ext/libev/ev_wrap.h +16 -0
- data/lib/ev_ext.bundle +0 -0
- data/lib/polyphony.rb +46 -50
- data/lib/polyphony/auto_run.rb +12 -0
- data/lib/polyphony/core/cancel_scope.rb +11 -7
- data/lib/polyphony/core/channel.rb +16 -9
- data/lib/polyphony/core/coprocess.rb +101 -51
- data/lib/polyphony/core/exceptions.rb +14 -12
- data/lib/polyphony/core/resource_pool.rb +21 -8
- data/lib/polyphony/core/supervisor.rb +10 -5
- data/lib/polyphony/core/sync.rb +7 -6
- data/lib/polyphony/core/thread.rb +4 -4
- data/lib/polyphony/core/thread_pool.rb +4 -4
- data/lib/polyphony/core/throttler.rb +6 -4
- data/lib/polyphony/extensions/core.rb +253 -0
- data/lib/polyphony/extensions/io.rb +28 -16
- data/lib/polyphony/extensions/openssl.rb +2 -1
- data/lib/polyphony/extensions/socket.rb +47 -52
- data/lib/polyphony/http.rb +4 -3
- data/lib/polyphony/http/agent.rb +68 -57
- data/lib/polyphony/http/server.rb +5 -5
- data/lib/polyphony/http/server/http1.rb +268 -0
- data/lib/polyphony/http/server/http2.rb +62 -0
- data/lib/polyphony/http/server/http2_stream.rb +104 -0
- data/lib/polyphony/http/server/rack.rb +64 -0
- data/lib/polyphony/http/server/request.rb +119 -0
- data/lib/polyphony/net.rb +26 -15
- data/lib/polyphony/postgres.rb +17 -13
- data/lib/polyphony/redis.rb +16 -15
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony/websocket.rb +11 -4
- data/polyphony.gemspec +13 -9
- data/test/eg.rb +27 -0
- data/test/helper.rb +25 -0
- data/test/run.rb +5 -0
- data/test/test_async.rb +33 -0
- data/test/test_coprocess.rb +239 -77
- data/test/test_core.rb +95 -61
- data/test/test_gyro.rb +148 -0
- data/test/test_http_server.rb +313 -0
- data/test/test_io.rb +79 -27
- data/test/test_kernel.rb +22 -12
- data/test/test_signal.rb +36 -0
- data/test/test_timer.rb +24 -0
- metadata +89 -33
- data/examples/core/nested_async.rb +0 -17
- data/examples/core/next_tick.rb +0 -12
- data/examples/core/sleep_spawn.rb +0 -19
- data/examples/core/spawn.rb +0 -14
- data/examples/core/spawn_error.rb +0 -28
- data/examples/performance/perf_multi_snooze.rb +0 -21
- data/ext/ev/async.c +0 -168
- data/ext/ev/child.c +0 -169
- data/ext/ev/ev_ext.c +0 -23
- data/ext/ev/ev_module.c +0 -242
- data/ext/ev/signal.c +0 -119
- data/ext/ev/timer.c +0 -197
- data/lib/polyphony/core/fiber_pool.rb +0 -98
- data/lib/polyphony/extensions/kernel.rb +0 -169
- data/lib/polyphony/http/http1_adapter.rb +0 -254
- data/lib/polyphony/http/http2_adapter.rb +0 -157
- data/lib/polyphony/http/rack.rb +0 -25
- data/lib/polyphony/http/request.rb +0 -66
- data/test/test_ev.rb +0 -110
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
export :load
|
4
|
+
|
5
|
+
require 'rack'
|
6
|
+
|
7
|
+
def run(app)
|
8
|
+
->(req) { respond(req, app.(env(req))) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def load(path)
|
12
|
+
src = IO.read(path)
|
13
|
+
instance_eval(src, path, 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Implements a rack input stream:
|
17
|
+
# https://www.rubydoc.info/github/rack/rack/master/file/SPEC#label-The+Input+Stream
|
18
|
+
class InputStream
|
19
|
+
def initialize(request)
|
20
|
+
@request = request
|
21
|
+
end
|
22
|
+
|
23
|
+
def gets; end
|
24
|
+
|
25
|
+
def read(length = nil, outbuf = nil); end
|
26
|
+
|
27
|
+
def each(&block)
|
28
|
+
@request.each_chunk(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rewind; end
|
32
|
+
end
|
33
|
+
|
34
|
+
def env(request)
|
35
|
+
{
|
36
|
+
'REQUEST_METHOD' => request.method,
|
37
|
+
'SCRIPT_NAME' => '',
|
38
|
+
'PATH_INFO' => request.path,
|
39
|
+
'QUERY_STRING' => request.query_string || '',
|
40
|
+
'SERVER_NAME' => request.headers['Host'], # ?
|
41
|
+
'SERVER_PORT' => '80', # ?
|
42
|
+
'rack.version' => Rack::VERSION,
|
43
|
+
'rack.url_scheme' => 'https', # ?
|
44
|
+
'rack.input' => InputStream.new(request),
|
45
|
+
'rack.errors' => STDERR, # ?
|
46
|
+
'rack.multithread' => false,
|
47
|
+
'rack.run_once' => false,
|
48
|
+
'rack.hijack?' => false,
|
49
|
+
'rack.hijack' => nil,
|
50
|
+
'rack.hijack_io' => nil,
|
51
|
+
'rack.session' => nil,
|
52
|
+
'rack.logger' => nil,
|
53
|
+
'rack.multipart.buffer_size' => nil,
|
54
|
+
'rack.multipar.tempfile_factory' => nil
|
55
|
+
}.tap do |env|
|
56
|
+
request.headers.each { |k, v| env["HTTP_#{k.upcase}"] = v }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def respond(request, (status_code, headers, body))
|
61
|
+
headers[':status'] = status_code.to_s
|
62
|
+
puts "headers: #{headers.inspect}"
|
63
|
+
request.respond(body.first, headers)
|
64
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
export_default :Request
|
4
|
+
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
# HTTP request
|
8
|
+
class Request
|
9
|
+
attr_reader :headers, :adapter
|
10
|
+
attr_accessor :__next__
|
11
|
+
|
12
|
+
def initialize(headers, adapter)
|
13
|
+
@headers = headers
|
14
|
+
@adapter = adapter
|
15
|
+
end
|
16
|
+
|
17
|
+
def protocol
|
18
|
+
@protocol = @adapter.protocol
|
19
|
+
end
|
20
|
+
|
21
|
+
def method
|
22
|
+
@method ||= @headers[':method']
|
23
|
+
end
|
24
|
+
|
25
|
+
def scheme
|
26
|
+
@scheme ||= @headers[':scheme']
|
27
|
+
end
|
28
|
+
|
29
|
+
def uri
|
30
|
+
@uri ||= URI.parse(@headers[':path'] || '')
|
31
|
+
end
|
32
|
+
|
33
|
+
def path
|
34
|
+
@path ||= uri.path
|
35
|
+
end
|
36
|
+
|
37
|
+
def query_string
|
38
|
+
@query_string ||= uri.query
|
39
|
+
end
|
40
|
+
|
41
|
+
def query
|
42
|
+
return @query if @query
|
43
|
+
|
44
|
+
@query = (q = uri.query) ? split_query_string(q) : {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def split_query_string(query)
|
48
|
+
query.split('&').each_with_object({}) do |kv, h|
|
49
|
+
k, v = kv.split('=')
|
50
|
+
h[k.to_sym] = URI.decode_www_form_component(v)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def buffer_body_chunk(chunk)
|
55
|
+
@buffered_body_chunks ||= []
|
56
|
+
@buffered_body_chunks << chunk
|
57
|
+
end
|
58
|
+
|
59
|
+
def each_chunk(&block)
|
60
|
+
if @buffered_body_chunks
|
61
|
+
puts 'serve buffered body_chunks'
|
62
|
+
@buffered_body_chunks.each(&block)
|
63
|
+
@buffered_body_chunks = nil
|
64
|
+
end
|
65
|
+
while !@message_complete && (chunk = @adapter.get_body_chunk)
|
66
|
+
yield chunk
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def complete!(keep_alive = nil)
|
71
|
+
@message_complete = true
|
72
|
+
@keep_alive = keep_alive
|
73
|
+
end
|
74
|
+
|
75
|
+
def complete?
|
76
|
+
@message_complete
|
77
|
+
end
|
78
|
+
|
79
|
+
def consume
|
80
|
+
@adapter.consume_request
|
81
|
+
end
|
82
|
+
|
83
|
+
def keep_alive?
|
84
|
+
@keep_alive
|
85
|
+
end
|
86
|
+
|
87
|
+
def read
|
88
|
+
buf = @buffered_body_chunks ? @buffered_body_chunks.join : +''
|
89
|
+
while (chunk = @adapter.get_body_chunk)
|
90
|
+
buf << chunk
|
91
|
+
end
|
92
|
+
buf
|
93
|
+
end
|
94
|
+
|
95
|
+
def respond(body, headers = {})
|
96
|
+
@adapter.respond(body, headers)
|
97
|
+
@headers_sent = true
|
98
|
+
end
|
99
|
+
|
100
|
+
def send_headers(headers = {}, empty_response = false)
|
101
|
+
return if @headers_sent
|
102
|
+
|
103
|
+
@headers_sent = true
|
104
|
+
@adapter.send_headers(headers, empty_response: empty_response)
|
105
|
+
end
|
106
|
+
|
107
|
+
def send_chunk(body, done: false)
|
108
|
+
send_headers({}) unless @headers_sent
|
109
|
+
|
110
|
+
@adapter.send_chunk(body, done: done)
|
111
|
+
end
|
112
|
+
alias_method :<<, :send_chunk
|
113
|
+
|
114
|
+
def finish
|
115
|
+
send_headers({}) unless @headers_sent
|
116
|
+
|
117
|
+
@adapter.finish
|
118
|
+
end
|
119
|
+
end
|
data/lib/polyphony/net.rb
CHANGED
@@ -7,10 +7,10 @@ import('./extensions/socket')
|
|
7
7
|
import('./extensions/openssl')
|
8
8
|
|
9
9
|
def tcp_connect(host, port, opts = {})
|
10
|
-
socket = ::Socket.new(:INET, :STREAM).tap
|
10
|
+
socket = ::Socket.new(:INET, :STREAM).tap do |s|
|
11
11
|
addr = ::Socket.sockaddr_in(port, host)
|
12
12
|
s.connect(addr)
|
13
|
-
|
13
|
+
end
|
14
14
|
if opts[:secure_context] || opts[:secure]
|
15
15
|
secure_socket(socket, opts[:secure_context], opts.merge(host: host))
|
16
16
|
else
|
@@ -20,27 +20,30 @@ end
|
|
20
20
|
|
21
21
|
def tcp_listen(host = nil, port = nil, opts = {})
|
22
22
|
host ||= '0.0.0.0'
|
23
|
-
raise
|
24
|
-
|
23
|
+
raise 'Port number not specified' unless port
|
24
|
+
|
25
|
+
socket = socket_from_options(host, port, opts)
|
26
|
+
if opts[:secure_context] || opts[:secure]
|
27
|
+
secure_server(socket, opts[:secure_context], opts)
|
28
|
+
else
|
29
|
+
socket
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def socket_from_options(host, port, opts)
|
34
|
+
::Socket.new(:INET, :STREAM).tap do |s|
|
25
35
|
s.reuse_addr if opts[:reuse_addr]
|
26
36
|
s.dont_linger if opts[:dont_linger]
|
27
37
|
addr = ::Socket.sockaddr_in(port, host)
|
28
38
|
s.bind(addr)
|
29
39
|
s.listen(0)
|
30
|
-
}
|
31
|
-
if opts[:secure_context] || opts[:secure]
|
32
|
-
secure_server(socket, opts[:secure_context], opts)
|
33
|
-
else
|
34
|
-
socket
|
35
40
|
end
|
36
41
|
end
|
37
42
|
|
38
43
|
def secure_socket(socket, context, opts)
|
39
44
|
setup_alpn(context, opts[:alpn_protocols]) if context && opts[:alpn_protocols]
|
40
|
-
socket = context
|
41
|
-
|
42
|
-
OpenSSL::SSL::SSLSocket.new(socket)
|
43
|
-
|
45
|
+
socket = secure_socket_wrapper(socket, context)
|
46
|
+
|
44
47
|
socket.tap do |s|
|
45
48
|
s.hostname = opts[:host] if opts[:host]
|
46
49
|
s.connect
|
@@ -48,6 +51,14 @@ def secure_socket(socket, context, opts)
|
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
54
|
+
def secure_socket_wrapper(socket, context)
|
55
|
+
if context
|
56
|
+
OpenSSL::SSL::SSLSocket.new(socket, context)
|
57
|
+
else
|
58
|
+
OpenSSL::SSL::SSLSocket.new(socket)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
51
62
|
def secure_server(socket, context, opts)
|
52
63
|
setup_alpn(context, opts[:alpn_protocols]) if opts[:alpn_protocols]
|
53
64
|
OpenSSL::SSL::SSLServer.new(socket, context)
|
@@ -55,7 +66,7 @@ end
|
|
55
66
|
|
56
67
|
def setup_alpn(context, protocols)
|
57
68
|
context.alpn_protocols = protocols
|
58
|
-
context.alpn_select_cb =
|
69
|
+
context.alpn_select_cb = lambda do |peer_protocols|
|
59
70
|
(protocols & peer_protocols).first
|
60
|
-
|
71
|
+
end
|
61
72
|
end
|
data/lib/polyphony/postgres.rb
CHANGED
@@ -3,21 +3,20 @@
|
|
3
3
|
require_relative '../polyphony'
|
4
4
|
require 'pg'
|
5
5
|
|
6
|
+
# PG overrides
|
6
7
|
module ::PG
|
7
8
|
def self.connect(*args)
|
8
9
|
Connection.connect_start(*args).tap(&method(:connect_async))
|
9
10
|
end
|
10
|
-
|
11
|
+
|
11
12
|
def self.connect_async(conn)
|
12
13
|
loop do
|
13
14
|
res = conn.connect_poll
|
14
15
|
case res
|
15
|
-
when PGRES_POLLING_FAILED then raise Error
|
16
|
+
when PGRES_POLLING_FAILED then raise Error, conn.error_message
|
16
17
|
when PGRES_POLLING_READING then conn.socket_io.read_watcher.await
|
17
18
|
when PGRES_POLLING_WRITING then conn.socket_io.write_watcher.await
|
18
|
-
when PGRES_POLLING_OK then
|
19
|
-
conn.setnonblocking(true)
|
20
|
-
return
|
19
|
+
when PGRES_POLLING_OK then return conn.setnonblocking(true)
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
@@ -26,8 +25,9 @@ module ::PG
|
|
26
25
|
loop do
|
27
26
|
res = conn.connect_poll
|
28
27
|
case res
|
29
|
-
when PGRES_POLLING_FAILED
|
30
|
-
|
28
|
+
when PGRES_POLLING_FAILED
|
29
|
+
raise Error, conn.error_message
|
30
|
+
when PGRES_POLLING_OK
|
31
31
|
conn.setnonblocking(true)
|
32
32
|
return
|
33
33
|
end
|
@@ -35,9 +35,10 @@ module ::PG
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
# Overrides for PG connection
|
38
39
|
class ::PG::Connection
|
39
40
|
alias_method :orig_get_result, :get_result
|
40
|
-
|
41
|
+
|
41
42
|
def get_result(&block)
|
42
43
|
while is_busy
|
43
44
|
socket_io.read_watcher.await
|
@@ -55,7 +56,7 @@ class ::PG::Connection
|
|
55
56
|
while get_result; end
|
56
57
|
end
|
57
58
|
|
58
|
-
def block(
|
59
|
+
def block(_timeout = 0)
|
59
60
|
while is_busy
|
60
61
|
socket_io.read_watcher.await
|
61
62
|
consume_input
|
@@ -70,20 +71,23 @@ class ::PG::Connection
|
|
70
71
|
# error is raised, the transaction is rolled back and the error is raised
|
71
72
|
# again.
|
72
73
|
# @return [void]
|
73
|
-
def transaction
|
74
|
-
began = false
|
74
|
+
def transaction(&block)
|
75
75
|
return yield if @transaction # allow nesting of calls to #transactions
|
76
76
|
|
77
|
+
perform_transaction(&block)
|
78
|
+
end
|
79
|
+
|
80
|
+
def perform_transaction
|
77
81
|
query(SQL_BEGIN)
|
78
82
|
began = true
|
79
83
|
@transaction = true
|
80
84
|
yield
|
81
85
|
query(SQL_COMMIT)
|
82
86
|
rescue StandardError => e
|
83
|
-
|
87
|
+
query(SQL_ROLLBACK) if began
|
84
88
|
raise e
|
85
89
|
ensure
|
86
|
-
@transaction = false
|
90
|
+
@transaction = false
|
87
91
|
end
|
88
92
|
|
89
93
|
self.async_api = true
|
data/lib/polyphony/redis.rb
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
require_relative '../polyphony'
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require 'redis'
|
6
|
+
require 'hiredis/reader'
|
7
7
|
|
8
|
+
# Polyphony-based Redis driver
|
8
9
|
class Driver
|
9
10
|
def self.connect(config)
|
10
|
-
if config[:scheme] ==
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
raise 'unix sockets not supported' if config[:scheme] == 'unix'
|
12
|
+
|
13
|
+
# connection.connect_unix(config[:path], connect_timeout)
|
14
|
+
|
15
|
+
raise 'ssl not supported' if config[:scheme] == 'rediss' || config[:ssl]
|
16
|
+
|
17
|
+
# raise NotImplementedError, "SSL not supported by hiredis driver"
|
18
|
+
|
19
|
+
new(config[:host], config[:port])
|
20
|
+
# connection.connect(config[:host], config[:port], connect_timeout)
|
20
21
|
end
|
21
22
|
|
22
23
|
def initialize(host, port)
|
@@ -53,13 +54,13 @@ class Driver
|
|
53
54
|
def read
|
54
55
|
reply = @reader.gets
|
55
56
|
return reply if reply
|
56
|
-
|
57
|
+
|
57
58
|
while (data = @connection.readpartial(8192))
|
58
59
|
@reader.feed(data)
|
59
60
|
reply = @reader.gets
|
60
|
-
return reply
|
61
|
+
return reply unless reply == false
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
|
-
Redis::Connection.drivers << Driver
|
66
|
+
Redis::Connection.drivers << Driver
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony/websocket.rb
CHANGED
@@ -5,6 +5,7 @@ export :handler
|
|
5
5
|
require 'digest/sha1'
|
6
6
|
require 'websocket'
|
7
7
|
|
8
|
+
# Websocket connection
|
8
9
|
class WebsocketConnection
|
9
10
|
def initialize(client, headers)
|
10
11
|
@client = client
|
@@ -13,24 +14,30 @@ class WebsocketConnection
|
|
13
14
|
end
|
14
15
|
|
15
16
|
S_WS_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
|
16
|
-
UPGRADE_RESPONSE =
|
17
|
+
UPGRADE_RESPONSE = <<~HTTP.gsub("\n", "\r\n")
|
18
|
+
HTTP/1.1 101 Switching Protocols
|
19
|
+
Upgrade: websocket
|
20
|
+
Connection: Upgrade
|
21
|
+
Sec-WebSocket-Accept: %<accept>s
|
22
|
+
|
23
|
+
HTTP
|
17
24
|
|
18
25
|
def setup(headers)
|
19
26
|
key = headers['Sec-WebSocket-Key']
|
20
27
|
@version = headers['Sec-WebSocket-Version'].to_i
|
21
28
|
accept = Digest::SHA1.base64digest([key, S_WS_GUID].join)
|
22
|
-
@client << UPGRADE_RESPONSE
|
29
|
+
@client << format(UPGRADE_RESPONSE, accept: accept)
|
23
30
|
|
24
31
|
@reader = ::WebSocket::Frame::Incoming::Server.new(version: @version)
|
25
32
|
end
|
26
33
|
|
27
34
|
def recv
|
28
|
-
|
35
|
+
loop do
|
29
36
|
data = @client.readpartial(8192)
|
30
37
|
break nil unless data
|
31
38
|
|
32
39
|
@reader << data
|
33
|
-
if msg = @reader.next
|
40
|
+
if (msg = @reader.next)
|
34
41
|
break msg.to_s
|
35
42
|
end
|
36
43
|
end
|