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